-module(cowl). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/cowl.gleam"). -export([secret/1, labeled/2, with_label/2, remove_label/1, get_label/1, mask_with/2, mask/1, to_string/1, equal/2, reveal/1, use_secret/2, map/2, map_label/2, tap/2, from_result/1, labeled_from_result/2, field_with/2, field/1]). -export_type([secret/1, strategy/0, peek_mode/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -opaque secret(DQR) :: {secret, fun(() -> DQR), gleam@option:option(binary())}. -type strategy() :: stars | {fixed, binary()} | label | {peek, peek_mode(), binary()} | {custom, fun((binary()) -> binary())}. -type peek_mode() :: {first, integer()} | {last, integer()} | {both, integer(), integer()}. -file("src/cowl.gleam", 49). ?DOC(" Wrap `value` as a secret with no label.\n"). -spec secret(DQS) -> secret(DQS). secret(Value) -> {secret, fun() -> Value end, none}. -file("src/cowl.gleam", 54). ?DOC(" Wrap `value` as a secret with a `label`.\n"). -spec labeled(DQU, binary()) -> secret(DQU). labeled(Value, Label) -> {secret, fun() -> Value end, {some, Label}}. -file("src/cowl.gleam", 59). ?DOC(" Set or replace the label on a secret.\n"). -spec with_label(secret(DQW), binary()) -> secret(DQW). with_label(Secret, Label) -> {secret, erlang:element(2, Secret), {some, Label}}. -file("src/cowl.gleam", 64). ?DOC(" Remove the label from a secret. The value is untouched.\n"). -spec remove_label(secret(DQZ)) -> secret(DQZ). remove_label(Secret) -> {secret, erlang:element(2, Secret), none}. -file("src/cowl.gleam", 69). ?DOC(" Return the label, if any.\n"). -spec get_label(secret(any())) -> gleam@option:option(binary()). get_label(Secret) -> erlang:element(3, Secret). -file("src/cowl.gleam", 102). -spec apply_peek(binary(), peek_mode(), binary()) -> binary(). apply_peek(Value, Mode, Filler) -> Len = string:length(Value), case Len of 0 -> Filler; _ -> case Mode of {first, N} -> case N =< 0 of true -> Filler; false -> case N >= Len of true -> Value; false -> <<(gleam@string:slice(Value, 0, N))/binary, Filler/binary>> end end; {last, N@1} -> case N@1 =< 0 of true -> Filler; false -> case N@1 >= Len of true -> Value; false -> <> end end; {both, N@2, M} -> case (N@2 =< 0) orelse (M =< 0) of true -> Filler; false -> case (N@2 + M) >= Len of true -> Value; false -> <<<<(gleam@string:slice(Value, 0, N@2))/binary, Filler/binary>>/binary, (gleam@string:slice(Value, Len - M, M))/binary>> end end end end. -file("src/cowl.gleam", 83). ?DOC(" Render a string secret using the given strategy.\n"). -spec mask_with(secret(binary()), strategy()) -> binary(). mask_with(Secret, Strategy) -> case Strategy of stars -> <<"***"/utf8>>; {fixed, Text} -> Text; label -> case erlang:element(3, Secret) of {some, L} -> <<<<"["/utf8, L/binary>>/binary, "]"/utf8>>; none -> <<"[secret]"/utf8>> end; {peek, Mode, Filler} -> apply_peek((erlang:element(2, Secret))(), Mode, Filler); {custom, F} -> F((erlang:element(2, Secret))()) end. -file("src/cowl.gleam", 78). ?DOC(" Render a string secret as `\"***\"`.\n"). -spec mask(secret(binary())) -> binary(). mask(Secret) -> mask_with(Secret, stars). -file("src/cowl.gleam", 98). ?DOC(" A safe debug string — always `\"Secret(***)\"`, never the actual value.\n"). -spec to_string(secret(binary())) -> binary(). to_string(Secret) -> <<<<"Secret("/utf8, (mask(Secret))/binary>>/binary, ")"/utf8>>. -file("src/cowl.gleam", 147). ?DOC(" Compare two secrets by value — labels are ignored.\n"). -spec equal(secret(DRI), secret(DRI)) -> boolean(). equal(A, B) -> (erlang:element(2, A))() =:= (erlang:element(2, B))(). -file("src/cowl.gleam", 156). ?DOC(" Unwrap and return the raw value.\n"). -spec reveal(secret(DRL)) -> DRL. reveal(Secret) -> (erlang:element(2, Secret))(). -file("src/cowl.gleam", 161). ?DOC(" Pass the raw value to `f` without letting it escape the return type.\n"). -spec use_secret(secret(DRN), fun((DRN) -> DRP)) -> DRP. use_secret(Secret, F) -> F((erlang:element(2, Secret))()). -file("src/cowl.gleam", 170). ?DOC(" Transform the wrapped value while keeping it secret. The label is preserved.\n"). -spec map(secret(DRQ), fun((DRQ) -> DRS)) -> secret(DRS). map(Secret, F) -> {secret, fun() -> F((erlang:element(2, Secret))()) end, erlang:element(3, Secret)}. -file("src/cowl.gleam", 175). ?DOC(" Transform only the label, leaving the value untouched.\n"). -spec map_label(secret(DRU), fun((binary()) -> binary())) -> secret(DRU). map_label(Secret, F) -> {secret, erlang:element(2, Secret), case erlang:element(3, Secret) of {some, L} -> {some, F(L)}; none -> none end}. -file("src/cowl.gleam", 186). ?DOC( " Run `f` for its side effects and return the original secret unchanged.\n" "\n" " ⚠️ Never pass a logging function directly — it will print the raw value.\n" " Use `cowl.to_string` for a safe representation instead.\n" ). -spec tap(secret(DRX), fun((DRX) -> any())) -> secret(DRX). tap(Secret, F) -> _ = F((erlang:element(2, Secret))()), Secret. -file("src/cowl.gleam", 196). ?DOC(" Wrap the `Ok` value of a `Result` as a secret, passing errors through.\n"). -spec from_result({ok, DSB} | {error, DSC}) -> {ok, secret(DSB)} | {error, DSC}. from_result(Res) -> case Res of {ok, V} -> {ok, secret(V)}; {error, E} -> {error, E} end. -file("src/cowl.gleam", 204). ?DOC(" Like `from_result`, but also attaches a label.\n"). -spec labeled_from_result({ok, DSI} | {error, DSJ}, binary()) -> {ok, secret(DSI)} | {error, DSJ}. labeled_from_result(Res, Label) -> case Res of {ok, V} -> {ok, labeled(V, Label)}; {error, E} -> {error, E} end. -file("src/cowl.gleam", 224). ?DOC(" Like `field`, with an explicit masking strategy.\n"). -spec field_with(secret(binary()), strategy()) -> {binary(), binary()}. field_with(Secret, Strategy) -> Key = case erlang:element(3, Secret) of {some, L} -> L; none -> <<"secret"/utf8>> end, {Key, mask_with(Secret, Strategy)}. -file("src/cowl.gleam", 219). ?DOC(" Return `#(label, \"***\")` for structured logging. Falls back to `\"secret\"` if unlabeled.\n"). -spec field(secret(binary())) -> {binary(), binary()}. field(Secret) -> field_with(Secret, stars).