@shivaedev/errors 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 - 2026-10-31
4
+
5
+ ### Added
6
+
7
+ - `@shivaedev/errors/taxonomy.ts` exports class guards (`isConflict`, `isNotFound` and one `is<Class>` guard for every other taxonomy error). They narrow actual class instances and reject objects with matching tags.
8
+
9
+ ### Fixed
10
+
11
+ - Logs, error reports, RPC failure data and exported spans share errors' database-key and URL policy. Database users and connection strings are masked under their diagnostic keys; URL user information, query values and fragments are masked in structured values and text.
12
+
13
+ ### Breaking
14
+
15
+ - Import `schemaSensitiveKeys` from `@shivaedev/errors/schemaSensitiveKeys.ts` instead of server, and `redactRecord` from `@shivaedev/errors/redact.ts` instead of server's `redactingDiagnostics.ts`.
16
+ - Import schema sensitivity AST helpers from `@shivaedev/errors/schemaSensitiveAst.ts` instead of `@shivaedev/server/schemaSensitiveAst.ts`.
17
+ - Replace server's `redactOtlpUrl` with `redactUrl` from `@shivaedev/errors/sensitive.ts`. Replace server's `redactOtlpText(value, key, sensitive)` with `redactText(value, sensitive, undefined, key)` from `@shivaedev/errors/sensitive.ts`.
18
+ - Errors' redaction helpers now apply the same URL and database-key masking previously applied only to exported traces. Consumers should expect `<redacted>` for URL user information, query values and fragments, and for `db.user`, `db.user.name` and `db.connection_string` values.
19
+
3
20
  ## 0.1.3 - 2026-10-31
4
21
 
5
22
  ### Fixed
package/README.md CHANGED
@@ -39,6 +39,8 @@ export const Rename = Rpc.make("Rename", {
39
39
 
40
40
  A handler fails with `new Conflict({ field: "name", message: "Name is taken" })`, and native RPC JSON decodes the rejection back to the error instance with its field. `rejectedField(error)` reads either that instance or its tagged JSON. Any value with a string `_tag`, `field` and `message` qualifies, including an application's own tagged error; an untagged object, a missing field or a non-string field yields `Option.none()`.
41
41
 
42
+ Each class has an `is<Class>` guard in `taxonomy.ts`, such as `isConflict(value)`. Guards narrow actual instances, including errors decoded by the class schema; an object with the same `_tag` and fields does not qualify. Use them with `Effect.catchIf(isConflict, handler)` when matching a taxonomy failure by class.
43
+
42
44
  ### Mapping unexpected failures at the handler edge
43
45
 
44
46
  Use `rpcBoundary` only at the RPC handler edge, never inside services. Services keep their typed failures and defects so callers can handle them. At that edge, `rpcBoundary(schema, options)` keeps declared rejections and maps other failures and defects into one declared fallback. It leaves successful values and interruption intact:
@@ -70,13 +72,15 @@ export const Handlers = Api.toLayer({
70
72
 
71
73
  ### Masking secrets in failures
72
74
 
73
- `sensitive.ts` decides which names are secret. `isSensitiveKey(key)` matches credential-shaped names whatever their casing or separator, such as `sessionId`, `bearerToken`, `access_key_id` or `cardNumber`. A `SensitiveKey` is any `(key: string) => boolean`, so an application can widen the policy with its own names. `redactText(text, sensitive, maxLength?)` masks credential-shaped text and `key=value` assignments inside a string, and cuts it at 2,048 characters by default; passing `Infinity` keeps complete public text. Masked values become `REDACTED`, the string `<redacted>`.
75
+ `sensitive.ts` decides which names are secret. `isSensitiveKey(key)` matches credential-shaped names whatever their casing or separator, such as `sessionId`, `bearerToken`, `access_key_id` or `cardNumber`, and database diagnostic keys `db.user`, `db.user.name` and `db.connection_string`. A `SensitiveKey` is any `(key: string) => boolean`, so an application can widen the policy with its own names. `redactText(text, sensitive, maxLength?, key?)` masks credential-shaped text and `key=value` assignments inside a string, URL user information, query values and fragments, and cuts it at 2,048 characters by default; passing `Infinity` keeps complete public text. The optional `key` supplies context for standalone URL components such as `url.query`. `redactUrl(value, key?)` from `sensitive.ts` applies just the URL rules, including nested JSON strings. Masked values become `REDACTED`, the string `<redacted>`.
74
76
 
75
- `redact.ts` applies that policy to structured values. `redact(value, sensitive?)` masks values under sensitive keys and credential text inside strings, summarises large collections and binary data, and stops cyclic payloads at a depth limit; use it for diagnostics. `redactWire(value, sensitive?)` applies the same masking without summaries or truncation; use it for failure data sent to a client.
77
+ `redact.ts` applies that policy to structured values. `redact(value, sensitive?)` masks values under sensitive keys and credential text inside strings, summarises large collections and binary data, and stops cyclic payloads at a depth limit; use it for diagnostics. `redactRecord(values, sensitive?)` masks every top-level record entry without limiting the number of keys, while applying diagnostic limits within each value. `redactWire(value, sensitive?)` applies the same masking without summaries or truncation; use it for failure data sent to a client.
76
78
 
77
79
  `redactCause.ts` applies it to Effect causes. `redactCause(cause, sensitive?)` rebuilds a cause with masked defects and keeps its typed failures, interruptions and annotations as they are, so the failure channel keeps its type. `redactDiagnosticCause(cause, sensitive?)` masks failures, defects and annotations for diagnostics, `redactDefect(defect, sensitive?)` masks one defect, and `redactingErrorReporter(reporter, sensitive?)` wraps an Effect error reporter so it only ever receives diagnostic-masked causes.
78
80
 
79
- The policy matches names, not values: it does not scan prose for personal data, so keep secrets out of free text and span names.
81
+ `schemaSensitiveKeys(group, extraKeys?)` from `schemaSensitiveKeys.ts` derives the key predicate from native RPC payload, success, error, defect and middleware error schemas. It includes nested sensitive annotations, Redacted schemas, encoded field names and additional application keys. Its `forRpc(tag)` method selects the schema-derived policy for one RPC; additional application keys apply to every RPC. Its `maskFailure(tag, reason)` method identifies whole error or defect roots that need masking. The host applies this predicate to logs, error reports, RPC failure data and exported traces.
82
+
83
+ The policy matches names and credential or URL shapes, not arbitrary values: it does not scan prose for personal data, so keep secrets out of free text and span names.
80
84
 
81
85
  ### Install and limits
82
86
 
package/dist/redact.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type SensitiveKey } from "#sensitive.ts";
2
2
  export declare function redact(value: unknown, sensitive?: SensitiveKey): unknown;
3
3
  export declare function redactWire(value: unknown, sensitive?: SensitiveKey): unknown;
4
+ export declare function redactRecord(values: Readonly<Record<string, unknown>>, sensitive?: SensitiveKey): Record<string, unknown>;
4
5
  //# sourceMappingURL=redact.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AACA,OAAO,EAA0D,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAyD1G,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,YAA6B,GAAG,OAAO,CAExF;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,YAA6B,GAAG,OAAO,CAE5F"}
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AACA,OAAO,EAA0D,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAyD1G,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,YAA6B,GAAG,OAAO,CAExF;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,YAA6B,GAAG,OAAO,CAE5F;AACD,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,GAAE,YAA6B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzI"}
package/dist/redact.js CHANGED
@@ -24,24 +24,24 @@ function entriesOf(value, sensitive, bounded) {
24
24
  const extra = entries.filter(([key]) => !["name", "message", "stack", "cause"].includes(key));
25
25
  return value.cause === undefined ? [...shape, ...extra] : [...shape, ...extra, ["cause", value.cause]];
26
26
  }
27
- function collection(value, sensitive, depth, bounded) {
27
+ function collection(value, sensitive, depth, bounded, parentKey) {
28
28
  if (Array.isArray(value)) {
29
- const items = value.slice(0, bounded ? MAX_ENTRIES : value.length).map((item) => walk(item, sensitive, depth + 1, bounded));
29
+ const items = value.slice(0, bounded ? MAX_ENTRIES : value.length).map((item) => walk(item, sensitive, depth + 1, bounded, parentKey));
30
30
  return bounded && value.length > MAX_ENTRIES ? [...items, `<${value.length - MAX_ENTRIES} more items>`] : items;
31
31
  }
32
32
  const entries = entriesOf(value, sensitive, bounded);
33
33
  const kept = entries.slice(0, bounded ? MAX_ENTRIES : entries.length).map(([key, nested]) => {
34
34
  const stackHeader = key === "stack" && typeof nested === "string" && (sensitive("name") || sensitive("message"));
35
- return [key, sensitive(key) || stackHeader ? REDACTED : walk(nested, sensitive, depth + 1, bounded)];
35
+ return [key, sensitive(key) || stackHeader ? REDACTED : walk(nested, sensitive, depth + 1, bounded, key)];
36
36
  });
37
37
  return Object.fromEntries(bounded && entries.length > MAX_ENTRIES ? [...kept, ["<truncated>", `${entries.length - MAX_ENTRIES} more keys`]] : kept);
38
38
  }
39
- function walk(value, sensitive, depth, bounded) {
39
+ function walk(value, sensitive, depth, bounded, key = "") {
40
40
  if (Redacted.isRedacted(value)) {
41
41
  return REDACTED;
42
42
  }
43
43
  if (Predicate.isString(value)) {
44
- return bounded ? redactText(value, sensitive) : redactText(value, sensitive, Number.POSITIVE_INFINITY);
44
+ return redactText(value, sensitive, bounded ? undefined : Number.POSITIVE_INFINITY, key);
45
45
  }
46
46
  if (!Predicate.isObjectOrArray(value)) {
47
47
  return value;
@@ -53,7 +53,7 @@ function walk(value, sensitive, depth, bounded) {
53
53
  if (bounded && depth >= MAX_DEPTH) {
54
54
  return "<truncated>";
55
55
  }
56
- return collection(value, sensitive, depth, bounded);
56
+ return collection(value, sensitive, depth, bounded, key);
57
57
  }
58
58
  export function redact(value, sensitive = isSensitiveKey) {
59
59
  return walk(value, sensitive, 0, true);
@@ -61,4 +61,7 @@ export function redact(value, sensitive = isSensitiveKey) {
61
61
  export function redactWire(value, sensitive = isSensitiveKey) {
62
62
  return walk(value, sensitive, 0, false);
63
63
  }
64
+ export function redactRecord(values, sensitive = isSensitiveKey) {
65
+ return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, sensitive(key) ? REDACTED : walk(value, sensitive, 0, true, key)]));
66
+ }
64
67
  //# sourceMappingURL=redact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type SchemaAST } from "effect";
2
+ export declare function marked(ast: SchemaAST.AST, seen?: Set<SchemaAST.AST>): boolean;
3
+ export declare function collectEncodedKeys(ast: SchemaAST.AST, keys: Set<string>): void;
4
+ export declare function maskedValue(ast: SchemaAST.AST, keys: ReadonlySet<string>, seen?: Set<SchemaAST.AST>): boolean;
5
+ export declare function collect(ast: SchemaAST.AST, nodes: Set<SchemaAST.AST>, encodings?: boolean): void;
6
+ export declare function collectFieldKeys(properties: SchemaAST.Objects["propertySignatures"], keys: Set<string>, sensitive: (ast: SchemaAST.AST) => boolean): void;
7
+ //# sourceMappingURL=schemaSensitiveAst.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaSensitiveAst.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveAst.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAsBnD,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAenF;AAOD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAcvE;AAOD,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAmBnH;AACD,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,UAAO,QAQtF;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,KAAK,OAAO,QAMlJ"}
@@ -0,0 +1,102 @@
1
+ import { Predicate } from "effect";
2
+ import { isSensitiveKey } from "#sensitive.ts";
3
+ function children(ast) {
4
+ switch (ast._tag) {
5
+ case "Objects":
6
+ return [...ast.propertySignatures.map((property) => property.type), ...ast.indexSignatures.flatMap((index) => [index.parameter, index.type])];
7
+ case "Arrays":
8
+ return [...ast.elements, ...ast.rest];
9
+ case "Union":
10
+ return ast.types;
11
+ case "Declaration":
12
+ return ast.typeParameters;
13
+ case "Suspend":
14
+ return [ast.thunk()];
15
+ default:
16
+ return [];
17
+ }
18
+ }
19
+ function sensitiveCheck(check) {
20
+ return check.annotations?.sensitive === true || (check._tag === "FilterGroup" && check.checks.some(sensitiveCheck));
21
+ }
22
+ export function marked(ast, seen = new Set()) {
23
+ if (seen.has(ast)) {
24
+ return false;
25
+ }
26
+ seen.add(ast);
27
+ if (ast.annotations?.sensitive === true
28
+ || ast.context?.annotations?.sensitive === true
29
+ || ast.checks?.some(sensitiveCheck)
30
+ || (Predicate.hasProperty(ast.annotations?.representation, "id") && ast.annotations.representation.id === "effect/schema/Redacted")) {
31
+ return true;
32
+ }
33
+ const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
34
+ return (ast.encoding?.some((link) => marked(link.to, seen)) ?? false) || nested.some((type) => marked(type, seen));
35
+ }
36
+ function containsSensitive(ast, keys) {
37
+ return (marked(ast)
38
+ || propertiesOf(ast).some((property) => typeof property.name === "string" && (keys.has(property.name) || isSensitiveKey(property.name))));
39
+ }
40
+ export function collectEncodedKeys(ast, keys) {
41
+ let source = ast;
42
+ let sensitive = false;
43
+ for (const link of ast.encoding ?? []) {
44
+ sensitive ||= containsSensitive(source, keys);
45
+ if (sensitive) {
46
+ for (const property of propertiesOf(link.to)) {
47
+ if (typeof property.name === "string") {
48
+ keys.add(property.name);
49
+ }
50
+ }
51
+ }
52
+ source = link.to;
53
+ }
54
+ }
55
+ function fixedOutput(ast) {
56
+ if (ast._tag === "Union") {
57
+ return ast.types.every(fixedOutput);
58
+ }
59
+ return ast._tag === "Objects" && ast.indexSignatures.length === 0;
60
+ }
61
+ export function maskedValue(ast, keys, seen = new Set()) {
62
+ if (seen.has(ast)) {
63
+ return false;
64
+ }
65
+ seen.add(ast);
66
+ if (marked(ast)) {
67
+ return true;
68
+ }
69
+ let source = ast;
70
+ let sensitive = false;
71
+ for (const link of ast.encoding ?? []) {
72
+ sensitive ||= containsSensitive(source, keys);
73
+ if (sensitive && !fixedOutput(link.to)) {
74
+ return true;
75
+ }
76
+ source = link.to;
77
+ }
78
+ const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
79
+ return nested.some((type) => maskedValue(type, keys, seen));
80
+ }
81
+ export function collect(ast, nodes, encodings = true) {
82
+ if (nodes.has(ast)) {
83
+ return;
84
+ }
85
+ nodes.add(ast);
86
+ for (const child of [...children(ast), ...(encodings ? (ast.encoding?.map((link) => link.to) ?? []) : [])]) {
87
+ collect(child, nodes, encodings);
88
+ }
89
+ }
90
+ function propertiesOf(ast) {
91
+ const nodes = new Set();
92
+ collect(ast, nodes, false);
93
+ return [...nodes].flatMap((node) => (node._tag === "Objects" ? node.propertySignatures : []));
94
+ }
95
+ export function collectFieldKeys(properties, keys, sensitive) {
96
+ for (const property of properties) {
97
+ if (typeof property.name === "string" && sensitive(property.type)) {
98
+ keys.add(property.name);
99
+ }
100
+ }
101
+ }
102
+ //# sourceMappingURL=schemaSensitiveAst.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaSensitiveAst.js","sourceRoot":"","sources":["../src/schemaSensitiveAst.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Rpc, type RpcGroup } from "effect/rpc";
2
+ export declare function schemaSensitiveKeys<R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>, extra?: readonly string[]): ((key: string) => boolean) & {
3
+ forRpc: (tag: string | undefined) => (key: string) => boolean;
4
+ maskFailure: (tag: string | undefined, reason: "Fail" | "Die") => boolean;
5
+ };
6
+ //# sourceMappingURL=schemaSensitiveKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaSensitiveKeys.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgChD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,MAAM,EAAO,UAOxF,MAAM;kBAIf,MAAM,GAAG,SAAS,WAJT,MAAM;uBAKV,MAAM,GAAG,SAAS,UAAU,MAAM,GAAG,KAAK;EAG9D"}
@@ -0,0 +1,47 @@
1
+ import { Rpc } from "effect/rpc";
2
+ import { collect, collectEncodedKeys, collectFieldKeys, marked, maskedValue } from "#schemaSensitiveAst.ts";
3
+ import { isSensitiveKey } from "#sensitive.ts";
4
+ function rpcSensitiveKeys(rpc, extra) {
5
+ const keys = new Set(extra);
6
+ const nodes = new Set();
7
+ const schemas = [
8
+ rpc.payloadSchema,
9
+ rpc.successSchema,
10
+ rpc.errorSchema,
11
+ rpc.defectSchema,
12
+ ...[...rpc.middlewares].map((m) => m.error),
13
+ ];
14
+ for (const schema of schemas) {
15
+ collect(schema.ast, nodes);
16
+ }
17
+ const properties = [...nodes].flatMap((ast) => (ast._tag === "Objects" ? ast.propertySignatures : []));
18
+ collectFieldKeys(properties, keys, marked);
19
+ let previousSize;
20
+ do {
21
+ previousSize = keys.size;
22
+ collectFieldKeys(properties, keys, (ast) => maskedValue(ast, keys));
23
+ for (const ast of nodes) {
24
+ collectEncodedKeys(ast, keys);
25
+ }
26
+ } while (keys.size !== previousSize);
27
+ return Object.assign((key) => keys.has(key) || isSensitiveKey(key), {
28
+ die: maskedValue(rpc.defectSchema.ast, keys),
29
+ fail: [rpc.errorSchema, ...[...rpc.middlewares].map((m) => m.error)].some((schema) => maskedValue(schema.ast, keys)),
30
+ });
31
+ }
32
+ export function schemaSensitiveKeys(group, extra = []) {
33
+ const policies = new Map();
34
+ for (const rpc of group.requests.values()) {
35
+ if (Rpc.isRpc(rpc)) {
36
+ policies.set(rpc._tag, rpcSensitiveKeys(rpc, extra));
37
+ }
38
+ }
39
+ function sensitive(key) {
40
+ return extra.includes(key) || isSensitiveKey(key) || [...policies.values()].some((policy) => policy(key));
41
+ }
42
+ return Object.assign(sensitive, {
43
+ forRpc: (tag) => (tag === undefined ? sensitive : (policies.get(tag) ?? sensitive)),
44
+ maskFailure: (tag, reason) => [...policies].some(([method, policy]) => (tag === undefined || tag === method) && (reason === "Fail" ? policy.fail : policy.die)),
45
+ });
46
+ }
47
+ //# sourceMappingURL=schemaSensitiveKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaSensitiveKeys.js","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  export declare const REDACTED = "<redacted>";
2
2
  export type SensitiveKey = (key: string) => boolean;
3
3
  export declare function isSensitiveKey(key: string): boolean;
4
- export declare function redactText(text: string, sensitive: SensitiveKey, maxLength?: number): string;
4
+ export declare function redactText(text: string, sensitive: SensitiveKey, maxLength?: number, key?: string): string;
5
5
  export declare function redactErrorStack(error: Error, sensitive: SensitiveKey): string | undefined;
6
+ export declare function redactUrl(value: string, key?: string): string;
6
7
  //# sourceMappingURL=sensitive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sensitive.d.ts","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,eAAe,CAAC;AAwBrC,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAQpD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AA8BD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,SAAa,GAAG,MAAM,CAGhG;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK1F"}
1
+ {"version":3,"file":"sensitive.d.ts","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,eAAe,CAAC;AAwBrC,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAQpD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAyBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,SAAa,EAAE,GAAG,SAAK,GAAG,MAAM,CAG1G;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK1F;AA8BD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAkBzD"}
package/dist/sensitive.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Option, Schema } from "effect";
1
2
  export const REDACTED = "<redacted>";
2
3
  const MAX_STRING = 2048;
3
4
  const SENSITIVE_PARTS = [
@@ -21,7 +22,7 @@ const SENSITIVE_PARTS = [
21
22
  "xsrf",
22
23
  ];
23
24
  const SENSITIVE_WORDS = ["otp", "pin", "cvv", "cvc", "ssn", "iban"];
24
- const SENSITIVE_NAMES = ["session", "pan", "sig"];
25
+ const SENSITIVE_NAMES = ["session", "pan", "sig", "db.user", "db.user.name", "db.connectionstring"];
25
26
  function wordsOf(key) {
26
27
  return key
27
28
  .replaceAll(/(?<lower>[a-z0-9])(?<upper>[A-Z])/gu, "$<lower> $<upper>")
@@ -38,7 +39,6 @@ export function isSensitiveKey(key) {
38
39
  const AUTH_SCHEME = /\b(?<scheme>Bearer|Basic)\s+[A-Za-z0-9%._~+/-]+=*/giu;
39
40
  const JWT = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/gu;
40
41
  const PRIVATE_KEY = /-----BEGIN (?<kind>(?:[A-Z0-9]+ )*PRIVATE KEY)-----[\s\S]*?-----END \k<kind>-----/gu;
41
- const URL_PASSWORD = /(?<authority>\/\/[^:/\s@]+:)[^@/\s]+@/gu;
42
42
  function redactAssignments(text, sensitive) {
43
43
  const matcher = /(?<key>[A-Za-z][\w.-]*)(?<separator>["']?\s*[=:]\s*["']?)(?<value>[^\s"'&,;]+)/gu;
44
44
  let result = "";
@@ -58,15 +58,11 @@ function redactAssignments(text, sensitive) {
58
58
  return result + text.slice(cursor);
59
59
  }
60
60
  function scrub(text, sensitive) {
61
- const credentials = text
62
- .replaceAll(PRIVATE_KEY, REDACTED)
63
- .replaceAll(AUTH_SCHEME, `$<scheme> ${REDACTED}`)
64
- .replaceAll(JWT, REDACTED)
65
- .replaceAll(URL_PASSWORD, `$<authority>${REDACTED}@`);
61
+ const credentials = text.replaceAll(PRIVATE_KEY, REDACTED).replaceAll(AUTH_SCHEME, `$<scheme> ${REDACTED}`).replaceAll(JWT, REDACTED);
66
62
  return redactAssignments(credentials, sensitive);
67
63
  }
68
- export function redactText(text, sensitive, maxLength = MAX_STRING) {
69
- const scrubbed = scrub(text, sensitive);
64
+ export function redactText(text, sensitive, maxLength = MAX_STRING, key = "") {
65
+ const scrubbed = scrub(redactUrl(text, key), sensitive);
70
66
  return scrubbed.length > maxLength ? `${scrubbed.slice(0, maxLength)}…<${scrubbed.length - maxLength} more chars>` : scrubbed;
71
67
  }
72
68
  export function redactErrorStack(error, sensitive) {
@@ -75,4 +71,41 @@ export function redactErrorStack(error, sensitive) {
75
71
  }
76
72
  return ["message", "name", "stack"].some((key) => sensitive(key)) ? REDACTED : redactText(error.stack, sensitive);
77
73
  }
74
+ function query(value) {
75
+ return value
76
+ .split("&")
77
+ .map((part) => (part === "" ? part : `${part.split("=", 1)[0]}=${REDACTED}`))
78
+ .join("&");
79
+ }
80
+ function url(value) {
81
+ const fragment = value.indexOf("#");
82
+ const target = fragment === -1 ? value : value.slice(0, fragment);
83
+ const separator = target.indexOf("?");
84
+ return ((separator === -1 ? target : `${target.slice(0, separator + 1)}${query(target.slice(separator + 1))}`).replaceAll(/(?<authority>(?:\b[a-z][a-z0-9+.-]*:)?\/\/)[^/?#]*@/giu, `$<authority>${REDACTED}@`) + (fragment === -1 ? "" : `#${REDACTED}`));
85
+ }
86
+ const structuredUrl = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown, {
87
+ reviver: (key, item) => (typeof item === "string" ? redactUrl(item, key) : item),
88
+ }));
89
+ function structured(value) {
90
+ return Option.getOrUndefined(Option.map(structuredUrl(value), (parsed) => JSON.stringify(parsed)));
91
+ }
92
+ export function redactUrl(value, key = "") {
93
+ if (/(?:^|[._-])(?:fragment|userinfo|username|password)$/iu.test(key)) {
94
+ return REDACTED;
95
+ }
96
+ if (/(?:^|[._-])query$/iu.test(key)) {
97
+ return url(`?${value}`).slice(1);
98
+ }
99
+ if (/(?:^|[._-])(?:url|uri|target)(?:$|[._-])/iu.test(key) || /(?:^|[._-])(?:referer|referrer|location|origin)$/iu.test(key)) {
100
+ return url(value);
101
+ }
102
+ if (/^\s*[[{]/u.test(value)) {
103
+ const redacted = structured(value);
104
+ if (redacted !== undefined) {
105
+ return redacted;
106
+ }
107
+ }
108
+ // Quotes and whitespace can belong to secret values, so free text has no safe closing delimiter.
109
+ return value.replaceAll(/(?:[a-z][a-z0-9+.-]*:\/\/|[/?#]).*/gisu, url);
110
+ }
78
111
  //# sourceMappingURL=sensitive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sensitive.js","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sensitive.js","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"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"}
@@ -51,5 +51,15 @@ declare const ServiceUnavailable_base: Schema.Class<ServiceUnavailable, Schema.T
51
51
  }>, import("effect/Cause").YieldableError>;
52
52
  export declare class ServiceUnavailable extends ServiceUnavailable_base {
53
53
  }
54
+ export declare function isNotFound(value: unknown): value is NotFound;
55
+ export declare function isUnauthorized(value: unknown): value is Unauthorized;
56
+ export declare function isForbidden(value: unknown): value is Forbidden;
57
+ export declare function isBadRequest(value: unknown): value is BadRequest;
58
+ export declare function isConflict(value: unknown): value is Conflict;
59
+ export declare function isPreconditionFailed(value: unknown): value is PreconditionFailed;
60
+ export declare function isTooManyRequests(value: unknown): value is TooManyRequests;
61
+ export declare function isAuthUnavailable(value: unknown): value is AuthUnavailable;
62
+ export declare function isInternalServerError(value: unknown): value is InternalServerError;
63
+ export declare function isServiceUnavailable(value: unknown): value is ServiceUnavailable;
54
64
  export {};
55
65
  //# sourceMappingURL=taxonomy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"taxonomy.d.ts","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAIhC,qBAAa,QAAS,SAAQ,aAAqD;CAAG;;;;AACtF,qBAAa,YAAa,SAAQ,iBAA6D;CAAG;;;;AAClG,qBAAa,SAAU,SAAQ,cAAuD;CAAG;;;;;AACzF,qBAAa,UAAW,SAAQ,eAAwD;CAAG;;;;;AAC3F,qBAAa,QAAS,SAAQ,aAAoD;CAAG;;;;AACrF,qBAAa,kBAAmB,SAAQ,uBAAyE;CAAG;;;;AACpH,qBAAa,eAAgB,SAAQ,oBAAmE;CAAG;;;;AAC3G,qBAAa,eAAgB,SAAQ,oBAAmE;CAAG;;;;AAC3G,qBAAa,mBAAoB,SAAQ,wBAA2E;CAAG;;;;AACvH,qBAAa,kBAAmB,SAAQ,uBAAyE;CAAG"}
1
+ {"version":3,"file":"taxonomy.d.ts","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAIhC,qBAAa,QAAS,SAAQ,aAAqD;CAAG;;;;AACtF,qBAAa,YAAa,SAAQ,iBAA6D;CAAG;;;;AAClG,qBAAa,SAAU,SAAQ,cAAuD;CAAG;;;;;AACzF,qBAAa,UAAW,SAAQ,eAAwD;CAAG;;;;;AAC3F,qBAAa,QAAS,SAAQ,aAAoD;CAAG;;;;AACrF,qBAAa,kBAAmB,SAAQ,uBAAyE;CAAG;;;;AACpH,qBAAa,eAAgB,SAAQ,oBAAmE;CAAG;;;;AAC3G,qBAAa,eAAgB,SAAQ,oBAAmE;CAAG;;;;AAC3G,qBAAa,mBAAoB,SAAQ,wBAA2E;CAAG;;;;AACvH,qBAAa,kBAAmB,SAAQ,uBAAyE;CAAG;AAEpH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AACD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF;AACD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AACD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AACD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AACD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF"}
package/dist/taxonomy.js CHANGED
@@ -21,4 +21,34 @@ export class InternalServerError extends Schema.TaggedError()("InternalServerErr
21
21
  }
22
22
  export class ServiceUnavailable extends Schema.TaggedError()("ServiceUnavailable", described) {
23
23
  }
24
+ export function isNotFound(value) {
25
+ return value instanceof NotFound;
26
+ }
27
+ export function isUnauthorized(value) {
28
+ return value instanceof Unauthorized;
29
+ }
30
+ export function isForbidden(value) {
31
+ return value instanceof Forbidden;
32
+ }
33
+ export function isBadRequest(value) {
34
+ return value instanceof BadRequest;
35
+ }
36
+ export function isConflict(value) {
37
+ return value instanceof Conflict;
38
+ }
39
+ export function isPreconditionFailed(value) {
40
+ return value instanceof PreconditionFailed;
41
+ }
42
+ export function isTooManyRequests(value) {
43
+ return value instanceof TooManyRequests;
44
+ }
45
+ export function isAuthUnavailable(value) {
46
+ return value instanceof AuthUnavailable;
47
+ }
48
+ export function isInternalServerError(value) {
49
+ return value instanceof InternalServerError;
50
+ }
51
+ export function isServiceUnavailable(value) {
52
+ return value instanceof ServiceUnavailable;
53
+ }
24
54
  //# sourceMappingURL=taxonomy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,SAAS,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAC7C,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AACtF,MAAM,OAAO,QAAS,SAAQ,MAAM,CAAC,WAAW,EAAY,CAAC,UAAU,EAAE,SAAS,CAAC;CAAG;AACtF,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,cAAc,EAAE,SAAS,CAAC;CAAG;AAClG,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,WAAW,EAAE,SAAS,CAAC;CAAG;AACzF,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,WAAW,EAAc,CAAC,YAAY,EAAE,QAAQ,CAAC;CAAG;AAC3F,MAAM,OAAO,QAAS,SAAQ,MAAM,CAAC,WAAW,EAAY,CAAC,UAAU,EAAE,QAAQ,CAAC;CAAG;AACrF,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAAC,oBAAoB,EAAE,SAAS,CAAC;CAAG;AACpH,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,iBAAiB,EAAE,SAAS,CAAC;CAAG;AAC3G,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,iBAAiB,EAAE,SAAS,CAAC;CAAG;AAC3G,MAAM,OAAO,mBAAoB,SAAQ,MAAM,CAAC,WAAW,EAAuB,CAAC,qBAAqB,EAAE,SAAS,CAAC;CAAG;AACvH,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAAC,oBAAoB,EAAE,SAAS,CAAC;CAAG"}
1
+ {"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,SAAS,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAC7C,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AACtF,MAAM,OAAO,QAAS,SAAQ,MAAM,CAAC,WAAW,EAAY,CAAC,UAAU,EAAE,SAAS,CAAC;CAAG;AACtF,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,cAAc,EAAE,SAAS,CAAC;CAAG;AAClG,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,WAAW,EAAE,SAAS,CAAC;CAAG;AACzF,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,WAAW,EAAc,CAAC,YAAY,EAAE,QAAQ,CAAC;CAAG;AAC3F,MAAM,OAAO,QAAS,SAAQ,MAAM,CAAC,WAAW,EAAY,CAAC,UAAU,EAAE,QAAQ,CAAC;CAAG;AACrF,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAAC,oBAAoB,EAAE,SAAS,CAAC;CAAG;AACpH,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,iBAAiB,EAAE,SAAS,CAAC;CAAG;AAC3G,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,iBAAiB,EAAE,SAAS,CAAC;CAAG;AAC3G,MAAM,OAAO,mBAAoB,SAAQ,MAAM,CAAC,WAAW,EAAuB,CAAC,qBAAqB,EAAE,SAAS,CAAC;CAAG;AACvH,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAAC,oBAAoB,EAAE,SAAS,CAAC;CAAG;AAEpH,MAAM,UAAU,UAAU,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,QAAQ,CAAC;AAClC,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,YAAY,CAAC;AACtC,CAAC;AACD,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,SAAS,CAAC;AACnC,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,KAAc;IAC1C,OAAO,KAAK,YAAY,UAAU,CAAC;AACpC,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,QAAQ,CAAC;AAClC,CAAC;AACD,MAAM,UAAU,oBAAoB,CAAC,KAAc;IAClD,OAAO,KAAK,YAAY,kBAAkB,CAAC;AAC5C,CAAC;AACD,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC/C,OAAO,KAAK,YAAY,eAAe,CAAC;AACzC,CAAC;AACD,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC/C,OAAO,KAAK,YAAY,eAAe,CAAC;AACzC,CAAC;AACD,MAAM,UAAU,qBAAqB,CAAC,KAAc;IACnD,OAAO,KAAK,YAAY,mBAAmB,CAAC;AAC7C,CAAC;AACD,MAAM,UAAU,oBAAoB,CAAC,KAAc;IAClD,OAAO,KAAK,YAAY,kBAAkB,CAAC;AAC5C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/errors",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Typed expected failures and secret-safe failure reporting for Effect applications",
5
5
  "keywords": [
6
6
  "effect"
@@ -45,7 +45,7 @@
45
45
  "README.md"
46
46
  ],
47
47
  "devDependencies": {
48
- "@shivaedev/quality": "0.48.1",
48
+ "@shivaedev/quality": "0.49.0",
49
49
  "@shivaedev/test": "0.12.0",
50
50
  "@types/node": "24.19.2",
51
51
  "effect": "4.0.6",
package/src/redact.ts CHANGED
@@ -25,24 +25,24 @@ function entriesOf(value: object, sensitive: SensitiveKey, bounded: boolean): [s
25
25
  const extra = entries.filter(([key]) => !["name", "message", "stack", "cause"].includes(key));
26
26
  return value.cause === undefined ? [...shape, ...extra] : [...shape, ...extra, ["cause", value.cause]];
27
27
  }
28
- function collection(value: object, sensitive: SensitiveKey, depth: number, bounded: boolean): unknown {
28
+ function collection(value: object, sensitive: SensitiveKey, depth: number, bounded: boolean, parentKey: string): unknown {
29
29
  if (Array.isArray(value)) {
30
- const items = value.slice(0, bounded ? MAX_ENTRIES : value.length).map((item) => walk(item, sensitive, depth + 1, bounded));
30
+ const items = value.slice(0, bounded ? MAX_ENTRIES : value.length).map((item) => walk(item, sensitive, depth + 1, bounded, parentKey));
31
31
  return bounded && value.length > MAX_ENTRIES ? [...items, `<${value.length - MAX_ENTRIES} more items>`] : items;
32
32
  }
33
33
  const entries = entriesOf(value, sensitive, bounded);
34
34
  const kept = entries.slice(0, bounded ? MAX_ENTRIES : entries.length).map(([key, nested]): [string, unknown] => {
35
35
  const stackHeader = key === "stack" && typeof nested === "string" && (sensitive("name") || sensitive("message"));
36
- return [key, sensitive(key) || stackHeader ? REDACTED : walk(nested, sensitive, depth + 1, bounded)];
36
+ return [key, sensitive(key) || stackHeader ? REDACTED : walk(nested, sensitive, depth + 1, bounded, key)];
37
37
  });
38
38
  return Object.fromEntries(bounded && entries.length > MAX_ENTRIES ? [...kept, ["<truncated>", `${entries.length - MAX_ENTRIES} more keys`]] : kept);
39
39
  }
40
- function walk(value: unknown, sensitive: SensitiveKey, depth: number, bounded: boolean): unknown {
40
+ function walk(value: unknown, sensitive: SensitiveKey, depth: number, bounded: boolean, key = ""): unknown {
41
41
  if (Redacted.isRedacted(value)) {
42
42
  return REDACTED;
43
43
  }
44
44
  if (Predicate.isString(value)) {
45
- return bounded ? redactText(value, sensitive) : redactText(value, sensitive, Number.POSITIVE_INFINITY);
45
+ return redactText(value, sensitive, bounded ? undefined : Number.POSITIVE_INFINITY, key);
46
46
  }
47
47
  if (!Predicate.isObjectOrArray(value)) {
48
48
  return value;
@@ -54,7 +54,7 @@ function walk(value: unknown, sensitive: SensitiveKey, depth: number, bounded: b
54
54
  if (bounded && depth >= MAX_DEPTH) {
55
55
  return "<truncated>";
56
56
  }
57
- return collection(value, sensitive, depth, bounded);
57
+ return collection(value, sensitive, depth, bounded, key);
58
58
  }
59
59
  export function redact(value: unknown, sensitive: SensitiveKey = isSensitiveKey): unknown {
60
60
  return walk(value, sensitive, 0, true);
@@ -62,3 +62,6 @@ export function redact(value: unknown, sensitive: SensitiveKey = isSensitiveKey)
62
62
  export function redactWire(value: unknown, sensitive: SensitiveKey = isSensitiveKey): unknown {
63
63
  return walk(value, sensitive, 0, false);
64
64
  }
65
+ export function redactRecord(values: Readonly<Record<string, unknown>>, sensitive: SensitiveKey = isSensitiveKey): Record<string, unknown> {
66
+ return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, sensitive(key) ? REDACTED : walk(value, sensitive, 0, true, key)]));
67
+ }
@@ -0,0 +1,106 @@
1
+ import { Predicate, type SchemaAST } from "effect";
2
+ import { isSensitiveKey } from "#sensitive.ts";
3
+
4
+ function children(ast: SchemaAST.AST): readonly SchemaAST.AST[] {
5
+ switch (ast._tag) {
6
+ case "Objects":
7
+ return [...ast.propertySignatures.map((property) => property.type), ...ast.indexSignatures.flatMap((index) => [index.parameter, index.type])];
8
+ case "Arrays":
9
+ return [...ast.elements, ...ast.rest];
10
+ case "Union":
11
+ return ast.types;
12
+ case "Declaration":
13
+ return ast.typeParameters;
14
+ case "Suspend":
15
+ return [ast.thunk()];
16
+ default:
17
+ return [];
18
+ }
19
+ }
20
+ function sensitiveCheck(check: SchemaAST.Check<never>): boolean {
21
+ return check.annotations?.sensitive === true || (check._tag === "FilterGroup" && check.checks.some(sensitiveCheck));
22
+ }
23
+ export function marked(ast: SchemaAST.AST, seen = new Set<SchemaAST.AST>()): boolean {
24
+ if (seen.has(ast)) {
25
+ return false;
26
+ }
27
+ seen.add(ast);
28
+ if (
29
+ ast.annotations?.sensitive === true
30
+ || ast.context?.annotations?.sensitive === true
31
+ || ast.checks?.some(sensitiveCheck)
32
+ || (Predicate.hasProperty(ast.annotations?.representation, "id") && ast.annotations.representation.id === "effect/schema/Redacted")
33
+ ) {
34
+ return true;
35
+ }
36
+ const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
37
+ return (ast.encoding?.some((link) => marked(link.to, seen)) ?? false) || nested.some((type) => marked(type, seen));
38
+ }
39
+ function containsSensitive(ast: SchemaAST.AST, keys: ReadonlySet<string>): boolean {
40
+ return (
41
+ marked(ast)
42
+ || propertiesOf(ast).some((property) => typeof property.name === "string" && (keys.has(property.name) || isSensitiveKey(property.name)))
43
+ );
44
+ }
45
+ export function collectEncodedKeys(ast: SchemaAST.AST, keys: Set<string>) {
46
+ let source = ast;
47
+ let sensitive = false;
48
+ for (const link of ast.encoding ?? []) {
49
+ sensitive ||= containsSensitive(source, keys);
50
+ if (sensitive) {
51
+ for (const property of propertiesOf(link.to)) {
52
+ if (typeof property.name === "string") {
53
+ keys.add(property.name);
54
+ }
55
+ }
56
+ }
57
+ source = link.to;
58
+ }
59
+ }
60
+ function fixedOutput(ast: SchemaAST.AST): boolean {
61
+ if (ast._tag === "Union") {
62
+ return ast.types.every(fixedOutput);
63
+ }
64
+ return ast._tag === "Objects" && ast.indexSignatures.length === 0;
65
+ }
66
+ export function maskedValue(ast: SchemaAST.AST, keys: ReadonlySet<string>, seen = new Set<SchemaAST.AST>()): boolean {
67
+ if (seen.has(ast)) {
68
+ return false;
69
+ }
70
+ seen.add(ast);
71
+ if (marked(ast)) {
72
+ return true;
73
+ }
74
+ let source = ast;
75
+ let sensitive = false;
76
+ for (const link of ast.encoding ?? []) {
77
+ sensitive ||= containsSensitive(source, keys);
78
+ if (sensitive && !fixedOutput(link.to)) {
79
+ return true;
80
+ }
81
+ source = link.to;
82
+ }
83
+ const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
84
+ return nested.some((type) => maskedValue(type, keys, seen));
85
+ }
86
+ export function collect(ast: SchemaAST.AST, nodes: Set<SchemaAST.AST>, encodings = true) {
87
+ if (nodes.has(ast)) {
88
+ return;
89
+ }
90
+ nodes.add(ast);
91
+ for (const child of [...children(ast), ...(encodings ? (ast.encoding?.map((link) => link.to) ?? []) : [])]) {
92
+ collect(child, nodes, encodings);
93
+ }
94
+ }
95
+ function propertiesOf(ast: SchemaAST.AST) {
96
+ const nodes = new Set<SchemaAST.AST>();
97
+ collect(ast, nodes, false);
98
+ return [...nodes].flatMap((node) => (node._tag === "Objects" ? node.propertySignatures : []));
99
+ }
100
+ export function collectFieldKeys(properties: SchemaAST.Objects["propertySignatures"], keys: Set<string>, sensitive: (ast: SchemaAST.AST) => boolean) {
101
+ for (const property of properties) {
102
+ if (typeof property.name === "string" && sensitive(property.type)) {
103
+ keys.add(property.name);
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,49 @@
1
+ import type { Schema, SchemaAST } from "effect";
2
+ import { Rpc, type RpcGroup } from "effect/rpc";
3
+ import { collect, collectEncodedKeys, collectFieldKeys, marked, maskedValue } from "#schemaSensitiveAst.ts";
4
+ import { isSensitiveKey } from "#sensitive.ts";
5
+
6
+ function rpcSensitiveKeys(rpc: Rpc.AnyWithProps, extra: readonly string[]) {
7
+ const keys = new Set(extra);
8
+ const nodes = new Set<SchemaAST.AST>();
9
+ const schemas: Schema.Top[] = [
10
+ rpc.payloadSchema,
11
+ rpc.successSchema,
12
+ rpc.errorSchema,
13
+ rpc.defectSchema,
14
+ ...[...rpc.middlewares].map((m) => m.error),
15
+ ];
16
+ for (const schema of schemas) {
17
+ collect(schema.ast, nodes);
18
+ }
19
+ const properties = [...nodes].flatMap((ast) => (ast._tag === "Objects" ? ast.propertySignatures : []));
20
+ collectFieldKeys(properties, keys, marked);
21
+ let previousSize: number;
22
+ do {
23
+ previousSize = keys.size;
24
+ collectFieldKeys(properties, keys, (ast) => maskedValue(ast, keys));
25
+ for (const ast of nodes) {
26
+ collectEncodedKeys(ast, keys);
27
+ }
28
+ } while (keys.size !== previousSize);
29
+ return Object.assign((key: string) => keys.has(key) || isSensitiveKey(key), {
30
+ die: maskedValue(rpc.defectSchema.ast, keys),
31
+ fail: [rpc.errorSchema, ...[...rpc.middlewares].map((m) => m.error)].some((schema) => maskedValue(schema.ast, keys)),
32
+ });
33
+ }
34
+ export function schemaSensitiveKeys<R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>, extra: readonly string[] = []) {
35
+ const policies = new Map<string, ReturnType<typeof rpcSensitiveKeys>>();
36
+ for (const rpc of group.requests.values()) {
37
+ if (Rpc.isRpc(rpc)) {
38
+ policies.set(rpc._tag, rpcSensitiveKeys(rpc, extra));
39
+ }
40
+ }
41
+ function sensitive(key: string) {
42
+ return extra.includes(key) || isSensitiveKey(key) || [...policies.values()].some((policy) => policy(key));
43
+ }
44
+ return Object.assign(sensitive, {
45
+ forRpc: (tag: string | undefined) => (tag === undefined ? sensitive : (policies.get(tag) ?? sensitive)),
46
+ maskFailure: (tag: string | undefined, reason: "Fail" | "Die") =>
47
+ [...policies].some(([method, policy]) => (tag === undefined || tag === method) && (reason === "Fail" ? policy.fail : policy.die)),
48
+ });
49
+ }
package/src/sensitive.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Option, Schema } from "effect";
2
+
1
3
  export const REDACTED = "<redacted>";
2
4
  const MAX_STRING = 2048;
3
5
  const SENSITIVE_PARTS = [
@@ -21,7 +23,7 @@ const SENSITIVE_PARTS = [
21
23
  "xsrf",
22
24
  ];
23
25
  const SENSITIVE_WORDS = ["otp", "pin", "cvv", "cvc", "ssn", "iban"];
24
- const SENSITIVE_NAMES = ["session", "pan", "sig"];
26
+ const SENSITIVE_NAMES = ["session", "pan", "sig", "db.user", "db.user.name", "db.connectionstring"];
25
27
  export type SensitiveKey = (key: string) => boolean;
26
28
  function wordsOf(key: string): string[] {
27
29
  return key
@@ -41,7 +43,6 @@ export function isSensitiveKey(key: string): boolean {
41
43
  const AUTH_SCHEME = /\b(?<scheme>Bearer|Basic)\s+[A-Za-z0-9%._~+/-]+=*/giu;
42
44
  const JWT = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/gu;
43
45
  const PRIVATE_KEY = /-----BEGIN (?<kind>(?:[A-Z0-9]+ )*PRIVATE KEY)-----[\s\S]*?-----END \k<kind>-----/gu;
44
- const URL_PASSWORD = /(?<authority>\/\/[^:/\s@]+:)[^@/\s]+@/gu;
45
46
  function redactAssignments(text: string, sensitive: SensitiveKey): string {
46
47
  const matcher = /(?<key>[A-Za-z][\w.-]*)(?<separator>["']?\s*[=:]\s*["']?)(?<value>[^\s"'&,;]+)/gu;
47
48
  let result = "";
@@ -60,15 +61,11 @@ function redactAssignments(text: string, sensitive: SensitiveKey): string {
60
61
  return result + text.slice(cursor);
61
62
  }
62
63
  function scrub(text: string, sensitive: SensitiveKey): string {
63
- const credentials = text
64
- .replaceAll(PRIVATE_KEY, REDACTED)
65
- .replaceAll(AUTH_SCHEME, `$<scheme> ${REDACTED}`)
66
- .replaceAll(JWT, REDACTED)
67
- .replaceAll(URL_PASSWORD, `$<authority>${REDACTED}@`);
64
+ const credentials = text.replaceAll(PRIVATE_KEY, REDACTED).replaceAll(AUTH_SCHEME, `$<scheme> ${REDACTED}`).replaceAll(JWT, REDACTED);
68
65
  return redactAssignments(credentials, sensitive);
69
66
  }
70
- export function redactText(text: string, sensitive: SensitiveKey, maxLength = MAX_STRING): string {
71
- const scrubbed = scrub(text, sensitive);
67
+ export function redactText(text: string, sensitive: SensitiveKey, maxLength = MAX_STRING, key = ""): string {
68
+ const scrubbed = scrub(redactUrl(text, key), sensitive);
72
69
  return scrubbed.length > maxLength ? `${scrubbed.slice(0, maxLength)}…<${scrubbed.length - maxLength} more chars>` : scrubbed;
73
70
  }
74
71
  export function redactErrorStack(error: Error, sensitive: SensitiveKey): string | undefined {
@@ -77,3 +74,51 @@ export function redactErrorStack(error: Error, sensitive: SensitiveKey): string
77
74
  }
78
75
  return ["message", "name", "stack"].some((key) => sensitive(key)) ? REDACTED : redactText(error.stack, sensitive);
79
76
  }
77
+
78
+ function query(value: string): string {
79
+ return value
80
+ .split("&")
81
+ .map((part) => (part === "" ? part : `${part.split("=", 1)[0]}=${REDACTED}`))
82
+ .join("&");
83
+ }
84
+
85
+ function url(value: string): string {
86
+ const fragment = value.indexOf("#");
87
+ const target = fragment === -1 ? value : value.slice(0, fragment);
88
+ const separator = target.indexOf("?");
89
+ return (
90
+ (separator === -1 ? target : `${target.slice(0, separator + 1)}${query(target.slice(separator + 1))}`).replaceAll(
91
+ /(?<authority>(?:\b[a-z][a-z0-9+.-]*:)?\/\/)[^/?#]*@/giu,
92
+ `$<authority>${REDACTED}@`,
93
+ ) + (fragment === -1 ? "" : `#${REDACTED}`)
94
+ );
95
+ }
96
+
97
+ const structuredUrl = Schema.decodeUnknownOption(
98
+ Schema.fromJsonString(Schema.Unknown, {
99
+ reviver: (key: string, item: unknown) => (typeof item === "string" ? redactUrl(item, key) : item),
100
+ }),
101
+ );
102
+ function structured(value: string): string | undefined {
103
+ return Option.getOrUndefined(Option.map(structuredUrl(value), (parsed) => JSON.stringify(parsed)));
104
+ }
105
+
106
+ export function redactUrl(value: string, key = ""): string {
107
+ if (/(?:^|[._-])(?:fragment|userinfo|username|password)$/iu.test(key)) {
108
+ return REDACTED;
109
+ }
110
+ if (/(?:^|[._-])query$/iu.test(key)) {
111
+ return url(`?${value}`).slice(1);
112
+ }
113
+ if (/(?:^|[._-])(?:url|uri|target)(?:$|[._-])/iu.test(key) || /(?:^|[._-])(?:referer|referrer|location|origin)$/iu.test(key)) {
114
+ return url(value);
115
+ }
116
+ if (/^\s*[[{]/u.test(value)) {
117
+ const redacted = structured(value);
118
+ if (redacted !== undefined) {
119
+ return redacted;
120
+ }
121
+ }
122
+ // Quotes and whitespace can belong to secret values, so free text has no safe closing delimiter.
123
+ return value.replaceAll(/(?:[a-z][a-z0-9+.-]*:\/\/|[/?#]).*/gisu, url);
124
+ }
package/src/taxonomy.ts CHANGED
@@ -12,3 +12,34 @@ export class TooManyRequests extends Schema.TaggedError<TooManyRequests>()("TooM
12
12
  export class AuthUnavailable extends Schema.TaggedError<AuthUnavailable>()("AuthUnavailable", described) {}
13
13
  export class InternalServerError extends Schema.TaggedError<InternalServerError>()("InternalServerError", described) {}
14
14
  export class ServiceUnavailable extends Schema.TaggedError<ServiceUnavailable>()("ServiceUnavailable", described) {}
15
+
16
+ export function isNotFound(value: unknown): value is NotFound {
17
+ return value instanceof NotFound;
18
+ }
19
+ export function isUnauthorized(value: unknown): value is Unauthorized {
20
+ return value instanceof Unauthorized;
21
+ }
22
+ export function isForbidden(value: unknown): value is Forbidden {
23
+ return value instanceof Forbidden;
24
+ }
25
+ export function isBadRequest(value: unknown): value is BadRequest {
26
+ return value instanceof BadRequest;
27
+ }
28
+ export function isConflict(value: unknown): value is Conflict {
29
+ return value instanceof Conflict;
30
+ }
31
+ export function isPreconditionFailed(value: unknown): value is PreconditionFailed {
32
+ return value instanceof PreconditionFailed;
33
+ }
34
+ export function isTooManyRequests(value: unknown): value is TooManyRequests {
35
+ return value instanceof TooManyRequests;
36
+ }
37
+ export function isAuthUnavailable(value: unknown): value is AuthUnavailable {
38
+ return value instanceof AuthUnavailable;
39
+ }
40
+ export function isInternalServerError(value: unknown): value is InternalServerError {
41
+ return value instanceof InternalServerError;
42
+ }
43
+ export function isServiceUnavailable(value: unknown): value is ServiceUnavailable {
44
+ return value instanceof ServiceUnavailable;
45
+ }