@jini-ai/core 0.3.0 → 0.4.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 +131 -0
- package/README.md +154 -14
- package/dist/agent-tools.d.ts +29 -0
- package/dist/agent-tools.js +2 -0
- package/dist/api-token-auth.d.ts +12 -5
- package/dist/api-token-auth.js +7 -7
- package/dist/bindings.d.ts +16 -5
- package/dist/bindings.js +7 -6
- package/dist/composition.d.ts +41 -0
- package/dist/composition.js +39 -0
- package/dist/contribution-registry.d.ts +16 -0
- package/dist/contribution-registry.js +12 -0
- package/dist/daemon.d.ts +12 -7
- package/dist/daemon.js +21 -9
- package/dist/gated-mutations/actor-identity.d.ts +20 -0
- package/dist/gated-mutations/actor-identity.js +31 -0
- package/dist/gated-mutations/gateway.d.ts +115 -0
- package/dist/gated-mutations/gateway.js +123 -0
- package/dist/gated-mutations/ports.d.ts +27 -0
- package/dist/gated-mutations/ports.js +2 -0
- package/dist/gated-mutations/token.d.ts +95 -0
- package/dist/gated-mutations/token.js +87 -0
- package/dist/gated-mutations.d.ts +5 -0
- package/dist/gated-mutations.js +5 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +6 -1
- package/dist/model-facing-tool-errors.d.ts +37 -0
- package/dist/model-facing-tool-errors.js +71 -0
- package/dist/naming.d.ts +31 -0
- package/dist/naming.js +33 -0
- package/dist/origin-validation.d.ts +64 -19
- package/dist/origin-validation.js +43 -33
- package/dist/pack-lifecycle.d.ts +19 -12
- package/dist/pack-lifecycle.js +14 -14
- package/dist/pack.d.ts +41 -13
- package/dist/pack.js +2 -2
- package/dist/primitives/http.d.ts +57 -0
- package/dist/primitives/http.js +2 -0
- package/dist/primitives/ids.d.ts +8 -0
- package/dist/primitives/ids.js +5 -0
- package/dist/primitives/index.d.ts +8 -0
- package/dist/primitives/index.js +8 -0
- package/dist/primitives/json.d.ts +10 -0
- package/dist/primitives/json.js +2 -0
- package/dist/primitives/logger.d.ts +26 -0
- package/dist/primitives/logger.js +17 -0
- package/dist/primitives/paths.d.ts +16 -0
- package/dist/primitives/paths.js +38 -0
- package/dist/primitives/result.d.ts +9 -0
- package/dist/primitives/result.js +2 -0
- package/dist/primitives/time.d.ts +17 -0
- package/dist/primitives/time.js +13 -0
- package/dist/redact.d.ts +43 -8
- package/dist/redact.js +121 -50
- package/dist/registration-kit.d.ts +323 -0
- package/dist/registration-kit.js +396 -0
- package/dist/text/index.d.ts +3 -0
- package/dist/text/index.js +2 -0
- package/dist/text/sanitize-untrusted-text.d.ts +22 -0
- package/dist/text/sanitize-untrusted-text.js +108 -0
- package/dist/token.d.ts +29 -2
- package/dist/token.js +22 -2
- package/dist/tool-registry.d.ts +60 -14
- package/dist/tool-registry.js +24 -9
- package/dist/tool-tokens.js +1 -1
- package/package.json +51 -7
- package/dist/api-token-auth.d.ts.map +0 -1
- package/dist/api-token-auth.js.map +0 -1
- package/dist/bindings.d.ts.map +0 -1
- package/dist/bindings.js.map +0 -1
- package/dist/compose.typecheck.d.ts +0 -2
- package/dist/compose.typecheck.d.ts.map +0 -1
- package/dist/compose.typecheck.js +0 -29
- package/dist/compose.typecheck.js.map +0 -1
- package/dist/daemon.d.ts.map +0 -1
- package/dist/daemon.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal.d.ts.map +0 -1
- package/dist/internal.js.map +0 -1
- package/dist/origin-validation.d.ts.map +0 -1
- package/dist/origin-validation.js.map +0 -1
- package/dist/pack-lifecycle.d.ts.map +0 -1
- package/dist/pack-lifecycle.js.map +0 -1
- package/dist/pack.d.ts.map +0 -1
- package/dist/pack.js.map +0 -1
- package/dist/principal.d.ts.map +0 -1
- package/dist/principal.js.map +0 -1
- package/dist/redact.d.ts.map +0 -1
- package/dist/redact.js.map +0 -1
- package/dist/token.d.ts.map +0 -1
- package/dist/token.js.map +0 -1
- package/dist/tool-registry.d.ts.map +0 -1
- package/dist/tool-registry.js.map +0 -1
- package/dist/tool-tokens.d.ts.map +0 -1
- package/dist/tool-tokens.js.map +0 -1
package/dist/pack.d.ts
CHANGED
|
@@ -26,8 +26,12 @@ import type { AnyToken, ManyToken, Token } from './token.js';
|
|
|
26
26
|
* silently falling through to a global container.
|
|
27
27
|
*/
|
|
28
28
|
export interface PackContainer {
|
|
29
|
-
get<T>(
|
|
30
|
-
|
|
29
|
+
get<T>(required: {
|
|
30
|
+
token: Token<T, string>;
|
|
31
|
+
}): T;
|
|
32
|
+
getMany<T>(required: {
|
|
33
|
+
token: ManyToken<T, string>;
|
|
34
|
+
}): T[];
|
|
31
35
|
}
|
|
32
36
|
export interface Pack<Deps extends readonly AnyToken<unknown, string>[] = readonly AnyToken<unknown, string>[], Services = unknown, Name extends string = string> {
|
|
33
37
|
readonly name: Name;
|
|
@@ -35,30 +39,54 @@ export interface Pack<Deps extends readonly AnyToken<unknown, string>[] = readon
|
|
|
35
39
|
readonly services: (c: PackContainer) => Services;
|
|
36
40
|
/**
|
|
37
41
|
* `{descriptor, handler, policy}` triples this pack contributes to the composition's shared
|
|
38
|
-
* `ToolRegistry`.
|
|
39
|
-
* pack's routes can assume its
|
|
42
|
+
* `ToolRegistry`. Composition roots must call `registerPackTools` exactly once per composed pack,
|
|
43
|
+
* before mounting any transport, so a pack's routes can assume its tools are already registered.
|
|
44
|
+
* This interface and `createDaemon` do not enforce that orchestration; repeated registration
|
|
45
|
+
* invokes the contribution again and duplicate tool IDs are rejected by the registry.
|
|
40
46
|
*
|
|
41
47
|
* Atomic with `http`/`cli` by construction: a pack that is not composed contributes neither its
|
|
42
48
|
* tools nor its routes. See this module's own doc for the failure mode that makes this
|
|
43
49
|
* load-bearing rather than a convenience.
|
|
44
50
|
*/
|
|
45
|
-
readonly tools?: (
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
readonly tools?: (required: {
|
|
52
|
+
services: Services;
|
|
53
|
+
}) => readonly ToolRegistration[];
|
|
54
|
+
readonly http?: (required: {
|
|
55
|
+
app: unknown;
|
|
56
|
+
services: Services;
|
|
57
|
+
}) => void;
|
|
58
|
+
readonly cli?: (required: {
|
|
59
|
+
reg: unknown;
|
|
60
|
+
services: Services;
|
|
61
|
+
}) => void;
|
|
48
62
|
/**
|
|
49
63
|
* Releases whatever this pack's `services` acquired (a pty manager, a database handle, an OAuth
|
|
50
64
|
* callback listener). Composition roots call these in reverse composition order, best-effort:
|
|
51
65
|
* one pack's failure to dispose must never prevent another's from running.
|
|
52
66
|
*/
|
|
53
|
-
readonly dispose?: (
|
|
67
|
+
readonly dispose?: (required: {
|
|
68
|
+
services: Services;
|
|
69
|
+
}) => Promise<void> | void;
|
|
70
|
+
}
|
|
71
|
+
export interface PackContributions<Services> {
|
|
72
|
+
tools?: (required: {
|
|
73
|
+
services: Services;
|
|
74
|
+
}) => readonly ToolRegistration[];
|
|
75
|
+
http?: (required: {
|
|
76
|
+
app: unknown;
|
|
77
|
+
services: Services;
|
|
78
|
+
}) => void;
|
|
79
|
+
cli?: (required: {
|
|
80
|
+
reg: unknown;
|
|
81
|
+
services: Services;
|
|
82
|
+
}) => void;
|
|
83
|
+
dispose?: (required: {
|
|
84
|
+
services: Services;
|
|
85
|
+
}) => Promise<void> | void;
|
|
54
86
|
}
|
|
55
87
|
export declare function definePack<const Name extends string, const Deps extends readonly AnyToken<unknown, string>[], Services>(def: {
|
|
56
88
|
name: Name;
|
|
57
89
|
deps: Deps;
|
|
58
90
|
services: (c: PackContainer) => Services;
|
|
59
|
-
|
|
60
|
-
http?: (app: unknown, services: Services) => void;
|
|
61
|
-
cli?: (reg: unknown, services: Services) => void;
|
|
62
|
-
dispose?: (services: Services) => Promise<void> | void;
|
|
63
|
-
}): Pack<Deps, Services, Name>;
|
|
91
|
+
}, optional?: PackContributions<Services>): Pack<Deps, Services, Name>;
|
|
64
92
|
//# sourceMappingURL=pack.d.ts.map
|
package/dist/pack.js
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** One shared contract keeps binary, mail and webhook consumers behind the same egress guard.
|
|
2
|
+
* A guarded request requires a socket idle budget; total elapsed time is opt-in. */
|
|
3
|
+
export type HttpRequest = {
|
|
4
|
+
/** HEAD supports certificate/header diagnostics without downloading the page body. */
|
|
5
|
+
method: "POST" | "GET" | "HEAD" | "PUT" | "PATCH" | "DELETE";
|
|
6
|
+
url: string;
|
|
7
|
+
headers: Readonly<Record<string, string>>;
|
|
8
|
+
/** Preserve the signed bytes: re-serialization between signing and sending changes the signature. */
|
|
9
|
+
body?: string;
|
|
10
|
+
/** Whole-operation deadline, including DNS, redirects and body reads. Off by default.
|
|
11
|
+
* Retry/backoff belongs to the caller; its deadline can cover the whole retry operation. */
|
|
12
|
+
totalDeadlineMs?: number;
|
|
13
|
+
/** Bound the whole operation, including DNS and body reads, beyond the per-attempt timeout. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Caller byte ceilings are bounded by the client policy, never a way to widen its cap. */
|
|
16
|
+
maxResponseBytes?: number;
|
|
17
|
+
} & ({
|
|
18
|
+
idleTimeoutMs: number; /** Legacy alias for the socket idle budget. */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
} | {
|
|
21
|
+
timeoutMs: number;
|
|
22
|
+
idleTimeoutMs?: number;
|
|
23
|
+
});
|
|
24
|
+
export interface HttpResponse {
|
|
25
|
+
status: number;
|
|
26
|
+
headers: Readonly<Record<string, string>>;
|
|
27
|
+
/** Bounded by the egress cap: a producer must not expose an unlimited text body through this port. */
|
|
28
|
+
bodyText: string;
|
|
29
|
+
/** Keep individual lines: Expires contains commas, so comma-splitting loses cookie boundaries. */
|
|
30
|
+
setCookies?: readonly string[];
|
|
31
|
+
/** UTF-8 decoding replaces invalid sequences and corrupts binary payloads. Expose the decompressed
|
|
32
|
+
* transport bytes here so binary consumers need not bypass DNS checks, peer pinning or redirects.
|
|
33
|
+
* Optional for older adapters/doubles; absence does not imply an empty payload. */
|
|
34
|
+
bodyBytes?: Uint8Array;
|
|
35
|
+
/** Coarse OR of text/byte clipping. A clipped image is corrupt, not merely smaller. Lossy UTF-8
|
|
36
|
+
* can expand invalid bytes into three-byte replacement characters and clip text even when all
|
|
37
|
+
* bytes fit, so binary consumers must use bodyBytesTruncated. Absence is an unknown verdict. */
|
|
38
|
+
bodyTruncated?: boolean;
|
|
39
|
+
/** Byte-specific completeness. A producer's unshaped truncation must count against both shapes
|
|
40
|
+
* rather than silently declaring bytes complete. Absent when no byte payload was supplied. */
|
|
41
|
+
bodyBytesTruncated?: boolean;
|
|
42
|
+
/** Provenance must name the guarded hop that supplied these bytes, not the requested URL or an
|
|
43
|
+
* unfollowed Location. Every followed hop is re-vetted. Older producers may omit this field,
|
|
44
|
+
* in which case consumers fall back to the request URL rather than inventing a blank source. */
|
|
45
|
+
finalUrl?: string;
|
|
46
|
+
}
|
|
47
|
+
export type RequestRedirect = "follow" | "error" | "manual";
|
|
48
|
+
/** Consumers receive the policy-enforcing client; the raw transport is a composition seam.
|
|
49
|
+
* Keeping construction at the host boundary prevents consumers from bypassing egress checks. */
|
|
50
|
+
export interface HttpClientPort {
|
|
51
|
+
send(required: {
|
|
52
|
+
request: HttpRequest;
|
|
53
|
+
}, optional?: {
|
|
54
|
+
redirect?: RequestRedirect;
|
|
55
|
+
}): Promise<HttpResponse>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Unbranded identifier; UUID-producing adapters and opaque host IDs share this port. */
|
|
2
|
+
export type UUID = string;
|
|
3
|
+
export interface IdGenerator {
|
|
4
|
+
newId(): string;
|
|
5
|
+
}
|
|
6
|
+
/** Uses the host's cryptographic UUID generator; no insecure random fallback. */
|
|
7
|
+
export declare function createRandomUuidGenerator(): IdGenerator;
|
|
8
|
+
//# sourceMappingURL=ids.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** JSON wire values shared by contracts and domain packages. */
|
|
2
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
3
|
+
export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
4
|
+
[key: string]: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
export type JsonObject = {
|
|
7
|
+
[key: string]: JsonValue;
|
|
8
|
+
};
|
|
9
|
+
export type JsonArray = JsonValue[];
|
|
10
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Host-independent logging contract: diagnostics travel as optional structured data. */
|
|
2
|
+
export interface Logger {
|
|
3
|
+
info(required: {
|
|
4
|
+
message: string;
|
|
5
|
+
}, optional?: {
|
|
6
|
+
meta?: Record<string, unknown>;
|
|
7
|
+
error?: unknown;
|
|
8
|
+
}): void;
|
|
9
|
+
warn(required: {
|
|
10
|
+
message: string;
|
|
11
|
+
}, optional?: {
|
|
12
|
+
meta?: Record<string, unknown>;
|
|
13
|
+
error?: unknown;
|
|
14
|
+
}): void;
|
|
15
|
+
error(required: {
|
|
16
|
+
message: string;
|
|
17
|
+
}, optional?: {
|
|
18
|
+
meta?: Record<string, unknown>;
|
|
19
|
+
error?: unknown;
|
|
20
|
+
}): void;
|
|
21
|
+
}
|
|
22
|
+
/** Minimal console adapter with a required host-owned prefix and structured metadata. */
|
|
23
|
+
export declare function createConsoleLogger({ prefix }: {
|
|
24
|
+
prefix: string;
|
|
25
|
+
}): Logger;
|
|
26
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Minimal console adapter with a required host-owned prefix and structured metadata. */
|
|
2
|
+
export function createConsoleLogger({ prefix }) {
|
|
3
|
+
const write = (level, message, optional) => {
|
|
4
|
+
const args = [prefix ? `${prefix} ${message}` : message];
|
|
5
|
+
if (optional.meta !== undefined)
|
|
6
|
+
args.push(optional.meta);
|
|
7
|
+
if (optional.error !== undefined)
|
|
8
|
+
args.push(optional.error);
|
|
9
|
+
console[level](...args);
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
info: ({ message }, optional = {}) => write('info', message, optional),
|
|
13
|
+
warn: ({ message }, optional = {}) => write('warn', message, optional),
|
|
14
|
+
error: ({ message }, optional = {}) => write('error', message, optional),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check lexical containment using whole directory segments, including equality.
|
|
3
|
+
* Hosts resolve cwd-relative paths and symlinks before calling: checking a textual
|
|
4
|
+
* prefix alone can permit traversal or a symlink escape. Keeping that effect outside
|
|
5
|
+
* this helper makes the kernel browser-safe. Windows hosts select case-insensitive
|
|
6
|
+
* comparison and backslash separators; drive roots and UNC share roots remain distinct.
|
|
7
|
+
* POSIX backslashes remain literal characters, so distinct directories cannot alias.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pathContains({ root, target }: {
|
|
10
|
+
root: string;
|
|
11
|
+
target: string;
|
|
12
|
+
}, { caseSensitive, separator }?: {
|
|
13
|
+
caseSensitive?: boolean;
|
|
14
|
+
separator?: '/' | '\\';
|
|
15
|
+
}): boolean;
|
|
16
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Pure lexical normalization of an already absolute path; no cwd, filesystem or symlink access. */
|
|
2
|
+
function normalizeAbsolutePath(value, separator) {
|
|
3
|
+
const path = separator === '\\' ? value.replace(/\\/g, '/') : value;
|
|
4
|
+
const drive = separator === '\\' ? /^[A-Za-z]:\//.exec(path)?.[0] : undefined;
|
|
5
|
+
const unc = separator === '\\' ? /^\/\/[^/]+\/[^/]+(?:\/|$)/.exec(path)?.[0] : undefined;
|
|
6
|
+
const prefix = drive ?? unc ?? (path.startsWith('/') ? '/' : undefined);
|
|
7
|
+
if (!prefix)
|
|
8
|
+
throw new RangeError('pathContains requires resolved absolute paths');
|
|
9
|
+
const segments = [];
|
|
10
|
+
for (const segment of path.slice(prefix.length).split('/')) {
|
|
11
|
+
if (!segment || segment === '.')
|
|
12
|
+
continue;
|
|
13
|
+
if (segment === '..')
|
|
14
|
+
segments.pop();
|
|
15
|
+
else
|
|
16
|
+
segments.push(segment);
|
|
17
|
+
}
|
|
18
|
+
return prefix.replace(/\/+$/, '') + '/' + segments.join('/');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check lexical containment using whole directory segments, including equality.
|
|
22
|
+
* Hosts resolve cwd-relative paths and symlinks before calling: checking a textual
|
|
23
|
+
* prefix alone can permit traversal or a symlink escape. Keeping that effect outside
|
|
24
|
+
* this helper makes the kernel browser-safe. Windows hosts select case-insensitive
|
|
25
|
+
* comparison and backslash separators; drive roots and UNC share roots remain distinct.
|
|
26
|
+
* POSIX backslashes remain literal characters, so distinct directories cannot alias.
|
|
27
|
+
*/
|
|
28
|
+
export function pathContains({ root, target }, { caseSensitive = true, separator = '/' } = {}) {
|
|
29
|
+
const normalize = (value) => {
|
|
30
|
+
const path = normalizeAbsolutePath(value, separator);
|
|
31
|
+
return caseSensitive ? path : path.toLowerCase();
|
|
32
|
+
};
|
|
33
|
+
const normalizedRoot = normalize(root);
|
|
34
|
+
const normalizedTarget = normalize(target);
|
|
35
|
+
const boundary = normalizedRoot.endsWith('/') ? normalizedRoot : normalizedRoot + '/';
|
|
36
|
+
return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(boundary);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Unbranded wire timestamp: hosts can share clocks without conversion adapters. */
|
|
2
|
+
export type ISODateTime = string;
|
|
3
|
+
/** Milliseconds since the Unix epoch. Zero-argument getters need no empty argument object. */
|
|
4
|
+
export interface Clock {
|
|
5
|
+
nowMs(): number;
|
|
6
|
+
}
|
|
7
|
+
/** Default wall clock; inject a Clock to control time in application code. */
|
|
8
|
+
export declare function createSystemClock(): Clock;
|
|
9
|
+
/** Converts epoch milliseconds using the standard UTC ISO representation. Invalid time throws. */
|
|
10
|
+
export declare function toIsoDateTime({ epochMs }: {
|
|
11
|
+
epochMs: number;
|
|
12
|
+
}): ISODateTime;
|
|
13
|
+
/** Samples the supplied clock once and formats its time in UTC. */
|
|
14
|
+
export declare function nowIso({ clock }: {
|
|
15
|
+
clock: Clock;
|
|
16
|
+
}): ISODateTime;
|
|
17
|
+
//# sourceMappingURL=time.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Default wall clock; inject a Clock to control time in application code. */
|
|
2
|
+
export function createSystemClock() {
|
|
3
|
+
return { nowMs: () => Date.now() };
|
|
4
|
+
}
|
|
5
|
+
/** Converts epoch milliseconds using the standard UTC ISO representation. Invalid time throws. */
|
|
6
|
+
export function toIsoDateTime({ epochMs }) {
|
|
7
|
+
return new Date(epochMs).toISOString();
|
|
8
|
+
}
|
|
9
|
+
/** Samples the supplied clock once and formats its time in UTC. */
|
|
10
|
+
export function nowIso({ clock }) {
|
|
11
|
+
return toIsoDateTime({ epochMs: clock.nowMs() });
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=time.js.map
|
package/dist/redact.d.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module redact
|
|
3
3
|
*
|
|
4
|
-
* Lexical secret / PII scrubber for telemetry payloads.
|
|
5
|
-
* OD's
|
|
6
|
-
*
|
|
4
|
+
* Lexical secret / PII scrubber for telemetry payloads. Originally a verbatim port of
|
|
5
|
+
* OD's daemon redactor — no product-identity strings or hardcoded env vars in the original,
|
|
6
|
+
* so no genericization was needed. The shared kernel now also covers the CLI/provider rule
|
|
7
|
+
* union and accepts explicit host secrets; the original categories and rationale stay here.
|
|
7
8
|
*
|
|
8
9
|
* Runs before any prompt or assistant text is sent to an external
|
|
9
|
-
* observability sink. The
|
|
10
|
+
* observability sink. The default policy is intentionally conservative:
|
|
10
11
|
* each one matches a well-defined token shape with extremely low
|
|
11
12
|
* false-positive rate (API keys have a fixed prefix, JWTs have the
|
|
12
13
|
* "header.payload.signature" triple, credit-card matches go through a Luhn
|
|
13
14
|
* check). What this file does NOT do — and any caller-facing copy must
|
|
14
15
|
* reflect that — is detect names, addresses, business secrets, or anything
|
|
15
16
|
* that requires understanding the meaning of the surrounding text. That's
|
|
16
|
-
* an ML / LLM problem this module doesn't take on.
|
|
17
|
+
* an ML / LLM problem this module doesn't take on. Callers can explicitly opt
|
|
18
|
+
* into `policy: 'aggressive'` to also mask bare 20+ character opaque runs;
|
|
19
|
+
* that CLI-style heuristic trades identifier/path readability for broader masking
|
|
20
|
+
* and must never be used by diagnostics or secret-scan guards.
|
|
17
21
|
*
|
|
18
22
|
* Output format: every match is replaced by `[REDACTED:<kind>]` so a
|
|
19
23
|
* reviewer reading a trace can see exactly which category fired without
|
|
@@ -27,21 +31,52 @@
|
|
|
27
31
|
* - AWS access key shape: 'AKIA' + 16 uppercase alphanumerics.
|
|
28
32
|
* - Luhn algorithm (credit cards): https://en.wikipedia.org/wiki/Luhn_algorithm
|
|
29
33
|
*/
|
|
34
|
+
/** Credential-shape vocabulary for secret-only redaction; no I/O or host dependencies. */
|
|
35
|
+
export interface SecretShapePattern {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly pattern: RegExp;
|
|
38
|
+
}
|
|
39
|
+
export declare const PEM_PATTERN_NAME = "PEM private key block";
|
|
40
|
+
export declare const SECRET_SHAPE_PATTERNS: readonly SecretShapePattern[];
|
|
41
|
+
export interface SecretRedactionPattern {
|
|
42
|
+
name: string;
|
|
43
|
+
regex: RegExp;
|
|
44
|
+
}
|
|
45
|
+
/** Optional caller-owned secrets and named lexical rules, without ambient credential lookup. */
|
|
46
|
+
export interface SecretRedactionOptions {
|
|
47
|
+
/** Conservative by default; aggressive also masks bare 20+ character opaque runs. */
|
|
48
|
+
policy?: 'conservative' | 'aggressive';
|
|
49
|
+
exactSecrets?: ReadonlyArray<string | undefined | null>;
|
|
50
|
+
extraPatterns?: readonly SecretRedactionPattern[];
|
|
51
|
+
}
|
|
52
|
+
export declare const LABELED_SECRET_RE: RegExp;
|
|
53
|
+
export declare const OPAQUE_TOKEN_RE: RegExp;
|
|
54
|
+
export declare const NON_SECRET_TOKEN_RE: RegExp;
|
|
30
55
|
/**
|
|
31
56
|
* Returns `input` with every recognised secret / PII pattern replaced by a
|
|
32
57
|
* `[REDACTED:<kind>]` marker. Idempotent — re-running on already redacted
|
|
33
|
-
* text only matches new tokens.
|
|
58
|
+
* text only matches new tokens. Defaults to conservative; `{ policy: 'aggressive' }`
|
|
59
|
+
* additionally masks bare 20+ character opaque runs. Exact secrets and extra patterns
|
|
60
|
+
* are honored under either policy.
|
|
34
61
|
*
|
|
35
62
|
* Empty / non-string input passes through unchanged so the caller can use
|
|
36
63
|
* this as a no-op on optional fields.
|
|
37
64
|
*/
|
|
38
|
-
export declare function redactSecrets(input
|
|
65
|
+
export declare function redactSecrets({ input }: {
|
|
66
|
+
input: string;
|
|
67
|
+
}, options?: SecretRedactionOptions): string;
|
|
39
68
|
/**
|
|
40
69
|
* Same as {@link redactSecrets} but also returns per-category counts so the
|
|
41
70
|
* caller can attach an audit summary to the trace metadata ('we stripped 2
|
|
42
71
|
* keys + 1 email before send').
|
|
72
|
+
*
|
|
73
|
+
* Exact secrets run first, longest first: lexical rules or a shorter supplied secret must not
|
|
74
|
+
* split a known credential and leave a suffix behind. Opt-in aggressive opaque rules precede
|
|
75
|
+
* PII rules for the same reason (a numeric token can also contain phone/card candidates).
|
|
43
76
|
*/
|
|
44
|
-
export declare function redactSecretsWithCounts(input
|
|
77
|
+
export declare function redactSecretsWithCounts({ input }: {
|
|
78
|
+
input: string;
|
|
79
|
+
}, options?: SecretRedactionOptions): {
|
|
45
80
|
redacted: string;
|
|
46
81
|
counts: Record<string, number>;
|
|
47
82
|
};
|