@aexhq/sdk 0.46.4-canary → 0.50.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/LICENSE +201 -0
- package/NOTICE +38 -0
- package/README.md +23 -31
- package/dist/client/aex.d.ts +33 -0
- package/dist/client/aex.js +98 -0
- package/dist/client/aex.js.map +1 -0
- package/dist/client/credentials.d.ts +25 -0
- package/dist/client/credentials.js +97 -0
- package/dist/client/credentials.js.map +1 -0
- package/dist/client/routing.d.ts +7 -0
- package/dist/client/routing.js +29 -0
- package/dist/client/routing.js.map +1 -0
- package/dist/downloads/download.d.ts +25 -0
- package/dist/downloads/download.js +53 -0
- package/dist/downloads/download.js.map +1 -0
- package/dist/generated/errors.d.ts +12 -0
- package/dist/generated/errors.js +81 -0
- package/dist/generated/errors.js.map +1 -0
- package/dist/generated/resources.d.ts +730 -0
- package/dist/generated/resources.js +606 -0
- package/dist/generated/resources.js.map +1 -0
- package/dist/generated/routes.d.ts +42 -0
- package/dist/generated/routes.js +2101 -0
- package/dist/generated/routes.js.map +1 -0
- package/dist/index.d.ts +20 -50
- package/dist/index.js +11 -62
- package/dist/index.js.map +1 -1
- package/dist/observations/stream.d.ts +1 -0
- package/dist/observations/stream.js +18 -0
- package/dist/observations/stream.js.map +1 -0
- package/dist/transport/errors.d.ts +60 -0
- package/dist/transport/errors.js +107 -0
- package/dist/transport/errors.js.map +1 -0
- package/dist/transport/pagination.d.ts +8 -0
- package/dist/transport/pagination.js +34 -0
- package/dist/transport/pagination.js.map +1 -0
- package/dist/transport/retry.d.ts +21 -0
- package/dist/transport/retry.js +37 -0
- package/dist/transport/retry.js.map +1 -0
- package/dist/transport/transport.d.ts +25 -0
- package/dist/transport/transport.js +28 -0
- package/dist/transport/transport.js.map +1 -0
- package/package.json +63 -30
- package/dist/_contracts/account-operations.d.ts +0 -101
- package/dist/_contracts/account-operations.js +0 -242
- package/dist/_contracts/account-types.d.ts +0 -461
- package/dist/_contracts/account-types.js +0 -1
- package/dist/_contracts/api-key.d.ts +0 -61
- package/dist/_contracts/api-key.js +0 -101
- package/dist/_contracts/api-routes.d.ts +0 -20
- package/dist/_contracts/api-routes.js +0 -109
- package/dist/_contracts/archive-limits.d.ts +0 -3
- package/dist/_contracts/archive-limits.js +0 -23
- package/dist/_contracts/asset-authoring.d.ts +0 -22
- package/dist/_contracts/asset-authoring.js +0 -106
- package/dist/_contracts/asset-bundle.d.ts +0 -64
- package/dist/_contracts/asset-bundle.js +0 -263
- package/dist/_contracts/asset-upload-helper.d.ts +0 -31
- package/dist/_contracts/asset-upload-helper.js +0 -84
- package/dist/_contracts/billing-admission.d.ts +0 -29
- package/dist/_contracts/billing-admission.js +0 -28
- package/dist/_contracts/bundle-manifest.d.ts +0 -89
- package/dist/_contracts/bundle-manifest.js +0 -158
- package/dist/_contracts/canonical-sha256.d.ts +0 -8
- package/dist/_contracts/canonical-sha256.js +0 -8
- package/dist/_contracts/connection-ticket.d.ts +0 -22
- package/dist/_contracts/connection-ticket.js +0 -54
- package/dist/_contracts/continuation-event.d.ts +0 -31
- package/dist/_contracts/continuation-event.js +0 -6
- package/dist/_contracts/contract-parse-error.d.ts +0 -12
- package/dist/_contracts/contract-parse-error.js +0 -51
- package/dist/_contracts/error-codes.d.ts +0 -26
- package/dist/_contracts/error-codes.js +0 -116
- package/dist/_contracts/error-factory.d.ts +0 -32
- package/dist/_contracts/error-factory.js +0 -174
- package/dist/_contracts/event-envelope.d.ts +0 -471
- package/dist/_contracts/event-envelope.js +0 -501
- package/dist/_contracts/event-stream-client.d.ts +0 -122
- package/dist/_contracts/event-stream-client.js +0 -445
- package/dist/_contracts/event-view.d.ts +0 -44
- package/dist/_contracts/event-view.js +0 -69
- package/dist/_contracts/failure-class.d.ts +0 -29
- package/dist/_contracts/failure-class.js +0 -73
- package/dist/_contracts/http.d.ts +0 -135
- package/dist/_contracts/http.js +0 -434
- package/dist/_contracts/ids.d.ts +0 -66
- package/dist/_contracts/ids.js +0 -119
- package/dist/_contracts/index.d.ts +0 -42
- package/dist/_contracts/index.js +0 -52
- package/dist/_contracts/internal.d.ts +0 -55
- package/dist/_contracts/internal.js +0 -113
- package/dist/_contracts/models.d.ts +0 -30
- package/dist/_contracts/models.js +0 -28
- package/dist/_contracts/operation-core.d.ts +0 -36
- package/dist/_contracts/operation-core.js +0 -70
- package/dist/_contracts/operations.d.ts +0 -218
- package/dist/_contracts/operations.js +0 -1496
- package/dist/_contracts/otlp-projection.d.ts +0 -78
- package/dist/_contracts/otlp-projection.js +0 -171
- package/dist/_contracts/post-hook.d.ts +0 -31
- package/dist/_contracts/post-hook.js +0 -61
- package/dist/_contracts/provider-fault.d.ts +0 -34
- package/dist/_contracts/provider-fault.js +0 -68
- package/dist/_contracts/retry-core.d.ts +0 -29
- package/dist/_contracts/retry-core.js +0 -79
- package/dist/_contracts/runner-event.d.ts +0 -117
- package/dist/_contracts/runner-event.js +0 -172
- package/dist/_contracts/runtime-kind.d.ts +0 -60
- package/dist/_contracts/runtime-kind.js +0 -70
- package/dist/_contracts/runtime-manifest.d.ts +0 -121
- package/dist/_contracts/runtime-manifest.js +0 -83
- package/dist/_contracts/runtime-security-profile.d.ts +0 -26
- package/dist/_contracts/runtime-security-profile.js +0 -73
- package/dist/_contracts/runtime-sizes.d.ts +0 -104
- package/dist/_contracts/runtime-sizes.js +0 -111
- package/dist/_contracts/runtime-types.d.ts +0 -618
- package/dist/_contracts/runtime-types.js +0 -58
- package/dist/_contracts/schemas/asset-bundle.d.ts +0 -70
- package/dist/_contracts/schemas/asset-bundle.js +0 -107
- package/dist/_contracts/schemas/asset-ref.d.ts +0 -61
- package/dist/_contracts/schemas/asset-ref.js +0 -118
- package/dist/_contracts/schemas/bundle-manifest.d.ts +0 -66
- package/dist/_contracts/schemas/bundle-manifest.js +0 -77
- package/dist/_contracts/schemas/index.d.ts +0 -32
- package/dist/_contracts/schemas/index.js +0 -30
- package/dist/_contracts/schemas/mcp-server.d.ts +0 -99
- package/dist/_contracts/schemas/mcp-server.js +0 -209
- package/dist/_contracts/schemas/models.d.ts +0 -29
- package/dist/_contracts/schemas/models.js +0 -51
- package/dist/_contracts/schemas/numeric.d.ts +0 -18
- package/dist/_contracts/schemas/numeric.js +0 -28
- package/dist/_contracts/schemas/post-hook.d.ts +0 -45
- package/dist/_contracts/schemas/post-hook.js +0 -68
- package/dist/_contracts/schemas/response-assets.d.ts +0 -75
- package/dist/_contracts/schemas/response-assets.js +0 -81
- package/dist/_contracts/schemas/response-billing.d.ts +0 -208
- package/dist/_contracts/schemas/response-billing.js +0 -139
- package/dist/_contracts/schemas/response-common.d.ts +0 -132
- package/dist/_contracts/schemas/response-common.js +0 -162
- package/dist/_contracts/schemas/response-identity.d.ts +0 -648
- package/dist/_contracts/schemas/response-identity.js +0 -131
- package/dist/_contracts/schemas/response-mcp-servers.d.ts +0 -51
- package/dist/_contracts/schemas/response-mcp-servers.js +0 -32
- package/dist/_contracts/schemas/response-secrets.d.ts +0 -50
- package/dist/_contracts/schemas/response-secrets.js +0 -32
- package/dist/_contracts/schemas/response-sessions-internal.d.ts +0 -200
- package/dist/_contracts/schemas/response-sessions-internal.js +0 -142
- package/dist/_contracts/schemas/response-sessions.d.ts +0 -1598
- package/dist/_contracts/schemas/response-sessions.js +0 -377
- package/dist/_contracts/schemas/response-webhooks.d.ts +0 -76
- package/dist/_contracts/schemas/response-webhooks.js +0 -42
- package/dist/_contracts/schemas/response-workspace.d.ts +0 -225
- package/dist/_contracts/schemas/response-workspace.js +0 -99
- package/dist/_contracts/schemas/runtime-kind.d.ts +0 -31
- package/dist/_contracts/schemas/runtime-kind.js +0 -29
- package/dist/_contracts/schemas/runtime-security-profile.d.ts +0 -28
- package/dist/_contracts/schemas/runtime-security-profile.js +0 -26
- package/dist/_contracts/schemas/runtime-sizes.d.ts +0 -70
- package/dist/_contracts/schemas/runtime-sizes.js +0 -127
- package/dist/_contracts/schemas/session-limits.d.ts +0 -34
- package/dist/_contracts/schemas/session-limits.js +0 -39
- package/dist/_contracts/schemas/session-machine.d.ts +0 -23
- package/dist/_contracts/schemas/session-machine.js +0 -24
- package/dist/_contracts/schemas/session-request-config.d.ts +0 -58
- package/dist/_contracts/schemas/session-request-config.js +0 -134
- package/dist/_contracts/schemas/session-webhook.d.ts +0 -11
- package/dist/_contracts/schemas/session-webhook.js +0 -38
- package/dist/_contracts/schemas/side-effect-audit.d.ts +0 -98
- package/dist/_contracts/schemas/side-effect-audit.js +0 -102
- package/dist/_contracts/schemas/submission-assets.d.ts +0 -117
- package/dist/_contracts/schemas/submission-assets.js +0 -147
- package/dist/_contracts/schemas/submission-body.d.ts +0 -251
- package/dist/_contracts/schemas/submission-body.js +0 -378
- package/dist/_contracts/schemas/submission-environment.d.ts +0 -79
- package/dist/_contracts/schemas/submission-environment.js +0 -179
- package/dist/_contracts/schemas/submission-request.d.ts +0 -158
- package/dist/_contracts/schemas/submission-request.js +0 -49
- package/dist/_contracts/schemas/submission-secrets.d.ts +0 -47
- package/dist/_contracts/schemas/submission-secrets.js +0 -108
- package/dist/_contracts/schemas/wire.d.ts +0 -118
- package/dist/_contracts/schemas/wire.js +0 -171
- package/dist/_contracts/schemas/workspace-resources.d.ts +0 -50
- package/dist/_contracts/schemas/workspace-resources.js +0 -87
- package/dist/_contracts/sdk-errors.d.ts +0 -212
- package/dist/_contracts/sdk-errors.js +0 -313
- package/dist/_contracts/sdk-secrets.d.ts +0 -67
- package/dist/_contracts/sdk-secrets.js +0 -427
- package/dist/_contracts/session-archive.d.ts +0 -16
- package/dist/_contracts/session-archive.js +0 -92
- package/dist/_contracts/session-artifacts.d.ts +0 -189
- package/dist/_contracts/session-artifacts.js +0 -264
- package/dist/_contracts/session-config.d.ts +0 -373
- package/dist/_contracts/session-config.js +0 -562
- package/dist/_contracts/session-cost-types.d.ts +0 -211
- package/dist/_contracts/session-cost-types.js +0 -69
- package/dist/_contracts/session-cost.d.ts +0 -8
- package/dist/_contracts/session-cost.js +0 -582
- package/dist/_contracts/session-custody.d.ts +0 -165
- package/dist/_contracts/session-custody.js +0 -345
- package/dist/_contracts/session-file-query.d.ts +0 -14
- package/dist/_contracts/session-file-query.js +0 -178
- package/dist/_contracts/session-record.d.ts +0 -112
- package/dist/_contracts/session-record.js +0 -165
- package/dist/_contracts/session-retention.d.ts +0 -201
- package/dist/_contracts/session-retention.js +0 -450
- package/dist/_contracts/side-effect-audit.d.ts +0 -126
- package/dist/_contracts/side-effect-audit.js +0 -520
- package/dist/_contracts/sse.d.ts +0 -74
- package/dist/_contracts/sse.js +0 -227
- package/dist/_contracts/stable.d.ts +0 -45
- package/dist/_contracts/stable.js +0 -62
- package/dist/_contracts/status.d.ts +0 -25
- package/dist/_contracts/status.js +0 -57
- package/dist/_contracts/submission-limits.d.ts +0 -61
- package/dist/_contracts/submission-limits.js +0 -60
- package/dist/_contracts/submission.d.ts +0 -547
- package/dist/_contracts/submission.js +0 -812
- package/dist/_contracts/suggest.d.ts +0 -15
- package/dist/_contracts/suggest.js +0 -53
- package/dist/_contracts/testing/response-bindings.d.ts +0 -45
- package/dist/_contracts/testing/response-bindings.js +0 -256
- package/dist/_contracts/testing/wire-conformance-entry.d.ts +0 -10
- package/dist/_contracts/testing/wire-conformance-entry.js +0 -8
- package/dist/_contracts/testing/wire-conformance.d.ts +0 -169
- package/dist/_contracts/testing/wire-conformance.js +0 -276
- package/dist/_contracts/turn-trace.d.ts +0 -28
- package/dist/_contracts/turn-trace.js +0 -1
- package/dist/_contracts/unknown-field-error.d.ts +0 -13
- package/dist/_contracts/unknown-field-error.js +0 -21
- package/dist/_contracts/value-guards.d.ts +0 -20
- package/dist/_contracts/value-guards.js +0 -34
- package/dist/_contracts/webhook-verify.d.ts +0 -34
- package/dist/_contracts/webhook-verify.js +0 -93
- package/dist/_contracts/wire-observer.d.ts +0 -49
- package/dist/_contracts/wire-observer.js +0 -34
- package/dist/_contracts/workflow-status.d.ts +0 -7
- package/dist/_contracts/workflow-status.js +0 -43
- package/dist/_contracts/workspace-resources.d.ts +0 -98
- package/dist/_contracts/workspace-resources.js +0 -39
- package/dist/archive-limits.d.ts +0 -1
- package/dist/archive-limits.js +0 -2
- package/dist/archive-limits.js.map +0 -1
- package/dist/asset-upload.d.ts +0 -47
- package/dist/asset-upload.js +0 -269
- package/dist/asset-upload.js.map +0 -1
- package/dist/bundle.d.ts +0 -9
- package/dist/bundle.js +0 -20
- package/dist/bundle.js.map +0 -1
- package/dist/canonical-zip.d.ts +0 -68
- package/dist/canonical-zip.js +0 -355
- package/dist/canonical-zip.js.map +0 -1
- package/dist/cli.mjs +0 -12048
- package/dist/cli.mjs.sha256 +0 -1
- package/dist/client-types.d.ts +0 -192
- package/dist/client-types.js +0 -2
- package/dist/client-types.js.map +0 -1
- package/dist/client.d.ts +0 -464
- package/dist/client.js +0 -1207
- package/dist/client.js.map +0 -1
- package/dist/event-projection.d.ts +0 -22
- package/dist/event-projection.js +0 -380
- package/dist/event-projection.js.map +0 -1
- package/dist/fetch-archive.d.ts +0 -16
- package/dist/fetch-archive.js +0 -252
- package/dist/fetch-archive.js.map +0 -1
- package/dist/file.d.ts +0 -96
- package/dist/file.js +0 -272
- package/dist/file.js.map +0 -1
- package/dist/instructions.d.ts +0 -20
- package/dist/instructions.js +0 -40
- package/dist/instructions.js.map +0 -1
- package/dist/legacy-session-provider-fault.d.ts +0 -7
- package/dist/legacy-session-provider-fault.js +0 -38
- package/dist/legacy-session-provider-fault.js.map +0 -1
- package/dist/mcp-server.d.ts +0 -84
- package/dist/mcp-server.js +0 -117
- package/dist/mcp-server.js.map +0 -1
- package/dist/node-fs.d.ts +0 -29
- package/dist/node-fs.js +0 -19
- package/dist/node-fs.js.map +0 -1
- package/dist/node-walk.d.ts +0 -69
- package/dist/node-walk.js +0 -151
- package/dist/node-walk.js.map +0 -1
- package/dist/path-basename.d.ts +0 -5
- package/dist/path-basename.js +0 -9
- package/dist/path-basename.js.map +0 -1
- package/dist/retry.d.ts +0 -70
- package/dist/retry.js +0 -155
- package/dist/retry.js.map +0 -1
- package/dist/secret.d.ts +0 -65
- package/dist/secret.js +0 -110
- package/dist/secret.js.map +0 -1
- package/dist/session-validate.d.ts +0 -100
- package/dist/session-validate.js +0 -303
- package/dist/session-validate.js.map +0 -1
- package/dist/skill.d.ts +0 -99
- package/dist/skill.js +0 -169
- package/dist/skill.js.map +0 -1
- package/dist/submission-wire.d.ts +0 -13
- package/dist/submission-wire.js +0 -69
- package/dist/submission-wire.js.map +0 -1
- package/dist/tool.d.ts +0 -41
- package/dist/tool.js +0 -76
- package/dist/tool.js.map +0 -1
- package/dist/version.d.ts +0 -9
- package/dist/version.js +0 -10
- package/dist/version.js.map +0 -1
- package/docs/authentication.md +0 -125
- package/docs/billing.md +0 -164
- package/docs/cleanup.md +0 -27
- package/docs/concepts/agent-tools.md +0 -47
- package/docs/concepts/composition.md +0 -60
- package/docs/concepts/providers-and-runtimes.md +0 -121
- package/docs/concepts/sessions.md +0 -51
- package/docs/concepts/subagents.md +0 -35
- package/docs/credentials.md +0 -116
- package/docs/defaults.md +0 -51
- package/docs/errors.md +0 -258
- package/docs/events.md +0 -143
- package/docs/files.md +0 -130
- package/docs/limits-and-quotas.md +0 -114
- package/docs/limits.md +0 -51
- package/docs/mcp.md +0 -47
- package/docs/networking.md +0 -114
- package/docs/provider-runtime-capabilities.md +0 -32
- package/docs/public-surface.json +0 -73
- package/docs/quickstart.md +0 -135
- package/docs/release.md +0 -44
- package/docs/retries.md +0 -108
- package/docs/secrets.md +0 -141
- package/docs/session-config.md +0 -51
- package/docs/session-record.md +0 -58
- package/docs/skills.md +0 -65
- package/docs/telemetry.md +0 -66
- package/docs/testing.md +0 -35
- package/docs/vision-skills.md +0 -94
- package/docs/webhooks.md +0 -143
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Transform } from "node:stream";
|
|
2
|
-
export type PublicSafeStructuralReason = "forbidden_field_name" | "uninspectable_value";
|
|
3
|
-
export type PublicSafeSecretReason = "bearer_token" | "provider_key" | "signed_url" | "object_store_key" | "vault_id" | "private_resource_handle" | "high_entropy_token";
|
|
4
|
-
export interface PublicSafeFinding<Reason extends string> {
|
|
5
|
-
readonly path: string;
|
|
6
|
-
readonly reason: Reason | PublicSafeStructuralReason;
|
|
7
|
-
readonly valueLength?: number;
|
|
8
|
-
}
|
|
9
|
-
export interface PublicSafeStringPattern<Reason extends string> {
|
|
10
|
-
readonly reason: Reason;
|
|
11
|
-
readonly regex: RegExp;
|
|
12
|
-
readonly accept?: (match: string) => boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface PublicSafePatternMatch<Reason extends string> {
|
|
15
|
-
readonly reason: Reason;
|
|
16
|
-
readonly path: string;
|
|
17
|
-
readonly value: string;
|
|
18
|
-
readonly match: string;
|
|
19
|
-
}
|
|
20
|
-
export interface PublicSafeScannerConfig<Reason extends string> {
|
|
21
|
-
readonly patterns: readonly PublicSafeStringPattern<Reason>[];
|
|
22
|
-
readonly isForbiddenFieldName: (key: string, path: string) => boolean;
|
|
23
|
-
readonly isPatternExempt?: (match: PublicSafePatternMatch<Reason>) => boolean;
|
|
24
|
-
readonly maxDepth?: number;
|
|
25
|
-
readonly maxVisitedValues?: number;
|
|
26
|
-
}
|
|
27
|
-
/** The only bare content identity the platform mints. */
|
|
28
|
-
export declare function isPlatformContentDigest(candidate: string): boolean;
|
|
29
|
-
export declare function looksHighEntropySecret(value: string): boolean;
|
|
30
|
-
export declare function publicSafeCharClassCount(value: string): number;
|
|
31
|
-
export declare function publicSafeShannonBits(value: string): number;
|
|
32
|
-
export declare const PUBLIC_SAFE_SECRET_PATTERNS: readonly PublicSafeStringPattern<Exclude<PublicSafeSecretReason, "private_resource_handle">>[];
|
|
33
|
-
/** Extra entropy policy for consumers whose identifier slots admit `_`. */
|
|
34
|
-
export declare function underscoredHighEntropyPattern(): PublicSafeStringPattern<"high_entropy_token">;
|
|
35
|
-
export declare function privateResourceHandlePattern(keywords: readonly string[], separators?: "_:-" | "_:"): PublicSafeStringPattern<"private_resource_handle">;
|
|
36
|
-
export declare function createForbiddenFieldNamePredicate(names: readonly string[]): (key: string, path: string) => boolean;
|
|
37
|
-
export declare function scanPublicSafePayload<Reason extends string>(input: unknown, config: PublicSafeScannerConfig<Reason>): readonly PublicSafeFinding<Reason>[];
|
|
38
|
-
export declare class SecretString {
|
|
39
|
-
#private;
|
|
40
|
-
constructor(value: string, label?: string);
|
|
41
|
-
unwrap(): string;
|
|
42
|
-
toString(): string;
|
|
43
|
-
toJSON(): string;
|
|
44
|
-
}
|
|
45
|
-
export declare function redactSecrets<T>(value: T): T;
|
|
46
|
-
/**
|
|
47
|
-
* Redact every secret-shaped run in `input`.
|
|
48
|
-
*
|
|
49
|
-
* `known` is an OPTIONAL belt-and-suspenders set of literal values to also mask
|
|
50
|
-
* (e.g. creds the caller happens to have loaded). Correctness does NOT depend on
|
|
51
|
-
* it — every shape above is caught with or without seeding — but masking known
|
|
52
|
-
* values first removes any residual substring of a value the shapes split.
|
|
53
|
-
*/
|
|
54
|
-
export declare function redactString(input: string, known?: Iterable<string>): string;
|
|
55
|
-
export declare function containsSecretLikeValue(input: string): boolean;
|
|
56
|
-
/**
|
|
57
|
-
* A line-buffered `Transform` that redacts secrets BEFORE bytes touch disk or
|
|
58
|
-
* console. Pipe a child process's stdout/stderr through it
|
|
59
|
-
* (`child.stdout.pipe(createRedactingStream()).pipe(process.stdout)`) so a
|
|
60
|
-
* secret can never be written and "cleaned up after"; the secret you didn't
|
|
61
|
-
* recognise is the one already on disk.
|
|
62
|
-
*
|
|
63
|
-
* Buffers by line so a secret split across a chunk boundary is still redacted:
|
|
64
|
-
* a partial trailing line is held until the next chunk (or `flush`) completes
|
|
65
|
-
* it. `known` is forwarded to `redactString` for optional value seeding.
|
|
66
|
-
*/
|
|
67
|
-
export declare function createRedactingStream(known?: Iterable<string>): Transform;
|
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { Transform } from "node:stream";
|
|
2
|
-
const DEFAULT_MAX_DEPTH = 64;
|
|
3
|
-
const DEFAULT_MAX_VISITED_VALUES = 100_000;
|
|
4
|
-
const ENTROPY_BITS_PER_CHAR = 3.0;
|
|
5
|
-
const MIN_CHAR_CLASSES = 2;
|
|
6
|
-
const HIGH_ENTROPY_NO_DIGIT_MIN_LEN = 40;
|
|
7
|
-
/** The only bare content identity the platform mints. */
|
|
8
|
-
export function isPlatformContentDigest(candidate) {
|
|
9
|
-
return /^[0-9a-f]{64}$/.test(candidate);
|
|
10
|
-
}
|
|
11
|
-
export function looksHighEntropySecret(value) {
|
|
12
|
-
return value.split("-").some(isOpaqueSecretRun);
|
|
13
|
-
}
|
|
14
|
-
export function publicSafeCharClassCount(value) {
|
|
15
|
-
let count = 0;
|
|
16
|
-
if (/[a-z]/.test(value))
|
|
17
|
-
count++;
|
|
18
|
-
if (/[A-Z]/.test(value))
|
|
19
|
-
count++;
|
|
20
|
-
if (/[0-9]/.test(value))
|
|
21
|
-
count++;
|
|
22
|
-
return count;
|
|
23
|
-
}
|
|
24
|
-
export function publicSafeShannonBits(value) {
|
|
25
|
-
if (value.length === 0)
|
|
26
|
-
return 0;
|
|
27
|
-
const counts = new Map();
|
|
28
|
-
for (const char of value) {
|
|
29
|
-
counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
30
|
-
}
|
|
31
|
-
let bits = 0;
|
|
32
|
-
for (const count of counts.values()) {
|
|
33
|
-
const probability = count / value.length;
|
|
34
|
-
bits -= probability * Math.log2(probability);
|
|
35
|
-
}
|
|
36
|
-
return bits;
|
|
37
|
-
}
|
|
38
|
-
function isOpaqueSecretRun(value) {
|
|
39
|
-
if (publicSafeCharClassCount(value) < MIN_CHAR_CLASSES)
|
|
40
|
-
return false;
|
|
41
|
-
if (publicSafeShannonBits(value) < ENTROPY_BITS_PER_CHAR)
|
|
42
|
-
return false;
|
|
43
|
-
return /[0-9]/.test(value) || value.length >= HIGH_ENTROPY_NO_DIGIT_MIN_LEN;
|
|
44
|
-
}
|
|
45
|
-
export const PUBLIC_SAFE_SECRET_PATTERNS = Object.freeze([
|
|
46
|
-
Object.freeze({
|
|
47
|
-
reason: "bearer_token",
|
|
48
|
-
regex: /\b(Bearer)\s+[A-Za-z0-9._~+/=-]{8,}/i
|
|
49
|
-
}),
|
|
50
|
-
Object.freeze({
|
|
51
|
-
reason: "provider_key",
|
|
52
|
-
regex: /\b(?:sk-[A-Za-z0-9_-]{16,}|xox[baprs]-[A-Za-z0-9-]{8,}|AIza[A-Za-z0-9_-]{8,})/i
|
|
53
|
-
}),
|
|
54
|
-
Object.freeze({
|
|
55
|
-
reason: "signed_url",
|
|
56
|
-
regex: /\bhttps?:\/\/[^\s"'<>]*(?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId|X-Goog-Signature|X-Goog-Credential|[?&]sig=)[^\s"'<>]*/i
|
|
57
|
-
}),
|
|
58
|
-
Object.freeze({
|
|
59
|
-
reason: "object_store_key",
|
|
60
|
-
regex: /(^|[\s"'`])(?:sessions|assets)\/[^?<#\s"'`]+/i
|
|
61
|
-
}),
|
|
62
|
-
Object.freeze({
|
|
63
|
-
reason: "vault_id",
|
|
64
|
-
regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
65
|
-
}),
|
|
66
|
-
Object.freeze({
|
|
67
|
-
reason: "high_entropy_token",
|
|
68
|
-
regex: /\b[A-Za-z0-9-]{40,}\b/,
|
|
69
|
-
accept: looksHighEntropySecret
|
|
70
|
-
})
|
|
71
|
-
]);
|
|
72
|
-
/** Extra entropy policy for consumers whose identifier slots admit `_`. */
|
|
73
|
-
export function underscoredHighEntropyPattern() {
|
|
74
|
-
return Object.freeze({
|
|
75
|
-
reason: "high_entropy_token",
|
|
76
|
-
regex: /\b[A-Za-z0-9-]{3,}_[A-Za-z0-9_-]{36,}\b/,
|
|
77
|
-
accept: (match) => looksHighEntropySecret(match.replaceAll("_", "-"))
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
export function privateResourceHandlePattern(keywords, separators = "_:-") {
|
|
81
|
-
const source = keywords.map(escapePublicSafeRegex).join("|");
|
|
82
|
-
return Object.freeze({
|
|
83
|
-
reason: "private_resource_handle",
|
|
84
|
-
regex: new RegExp(`\\b(?:${source})[${separators}][A-Za-z0-9][A-Za-z0-9_-]{7,}\\b`, "i"),
|
|
85
|
-
accept: isMintedResourceHandle
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
function isMintedResourceHandle(match) {
|
|
89
|
-
const separatorIndex = match.search(/[_:-]/);
|
|
90
|
-
return separatorIndex >= 0 && /\d/.test(match.slice(separatorIndex + 1));
|
|
91
|
-
}
|
|
92
|
-
function escapePublicSafeRegex(value) {
|
|
93
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
94
|
-
}
|
|
95
|
-
export function createForbiddenFieldNamePredicate(names) {
|
|
96
|
-
const normalized = new Set(names.map((name) => name.toLowerCase()));
|
|
97
|
-
return (key) => normalized.has(key.toLowerCase());
|
|
98
|
-
}
|
|
99
|
-
export function scanPublicSafePayload(input, config) {
|
|
100
|
-
const findings = [];
|
|
101
|
-
const seen = new WeakSet();
|
|
102
|
-
const stack = [
|
|
103
|
-
{ value: input, path: "$", depth: 0 }
|
|
104
|
-
];
|
|
105
|
-
const maxDepth = config.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
106
|
-
const maxVisitedValues = config.maxVisitedValues ?? DEFAULT_MAX_VISITED_VALUES;
|
|
107
|
-
let visited = 0;
|
|
108
|
-
while (stack.length > 0) {
|
|
109
|
-
const current = stack.pop();
|
|
110
|
-
visited++;
|
|
111
|
-
if (visited > maxVisitedValues || current.depth > maxDepth) {
|
|
112
|
-
findings.push(freezePublicSafeFinding({ path: current.path, reason: "uninspectable_value" }));
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
if (typeof current.value === "string") {
|
|
116
|
-
scanPublicSafeString(current.value, current.path, config, findings);
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
if (current.value === null || typeof current.value !== "object")
|
|
120
|
-
continue;
|
|
121
|
-
if (seen.has(current.value)) {
|
|
122
|
-
findings.push(freezePublicSafeFinding({ path: current.path, reason: "uninspectable_value" }));
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
seen.add(current.value);
|
|
126
|
-
let keys;
|
|
127
|
-
try {
|
|
128
|
-
keys = Object.keys(current.value);
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
findings.push(freezePublicSafeFinding({ path: current.path, reason: "uninspectable_value" }));
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
const children = [];
|
|
135
|
-
for (const key of keys) {
|
|
136
|
-
const childPath = Array.isArray(current.value) && /^\d+$/.test(key)
|
|
137
|
-
? `${current.path}[${key}]`
|
|
138
|
-
: `${current.path}.${key}`;
|
|
139
|
-
let forbidden = false;
|
|
140
|
-
try {
|
|
141
|
-
forbidden = config.isForbiddenFieldName(key, childPath);
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
findings.push(freezePublicSafeFinding({ path: childPath, reason: "uninspectable_value" }));
|
|
145
|
-
}
|
|
146
|
-
if (forbidden) {
|
|
147
|
-
findings.push(freezePublicSafeFinding({ path: childPath, reason: "forbidden_field_name" }));
|
|
148
|
-
}
|
|
149
|
-
let descriptor;
|
|
150
|
-
try {
|
|
151
|
-
descriptor = Object.getOwnPropertyDescriptor(current.value, key);
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
findings.push(freezePublicSafeFinding({ path: childPath, reason: "uninspectable_value" }));
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (!descriptor || !("value" in descriptor)) {
|
|
158
|
-
findings.push(freezePublicSafeFinding({ path: childPath, reason: "uninspectable_value" }));
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
children.push({ value: descriptor.value, path: childPath, depth: current.depth + 1 });
|
|
162
|
-
}
|
|
163
|
-
for (let index = children.length - 1; index >= 0; index--)
|
|
164
|
-
stack.push(children[index]);
|
|
165
|
-
}
|
|
166
|
-
return Object.freeze(findings);
|
|
167
|
-
}
|
|
168
|
-
function scanPublicSafeString(value, path, config, findings) {
|
|
169
|
-
for (const pattern of config.patterns) {
|
|
170
|
-
let matches;
|
|
171
|
-
try {
|
|
172
|
-
matches = matchingPublicSafeSequences(pattern, value);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
findings.push(freezePublicSafeFinding({ path, reason: "uninspectable_value" }));
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
for (const match of matches) {
|
|
179
|
-
let exempt = false;
|
|
180
|
-
try {
|
|
181
|
-
exempt = config.isPatternExempt?.({ reason: pattern.reason, path, value, match }) ?? false;
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
184
|
-
findings.push(freezePublicSafeFinding({ path, reason: "uninspectable_value" }));
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
if (!exempt) {
|
|
188
|
-
findings.push(freezePublicSafeFinding({ path, reason: pattern.reason, valueLength: value.length }));
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function matchingPublicSafeSequences(pattern, value) {
|
|
195
|
-
const flags = pattern.regex.flags.includes("g") ? pattern.regex.flags : `${pattern.regex.flags}g`;
|
|
196
|
-
const regex = new RegExp(pattern.regex.source, flags);
|
|
197
|
-
const matches = [];
|
|
198
|
-
let match;
|
|
199
|
-
while ((match = regex.exec(value)) !== null) {
|
|
200
|
-
if (!pattern.accept || pattern.accept(match[0]))
|
|
201
|
-
matches.push(match[0]);
|
|
202
|
-
if (match.index === regex.lastIndex)
|
|
203
|
-
regex.lastIndex++;
|
|
204
|
-
}
|
|
205
|
-
return matches;
|
|
206
|
-
}
|
|
207
|
-
function freezePublicSafeFinding(finding) {
|
|
208
|
-
return Object.freeze(finding);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Value-AGNOSTIC secret patterns: each matches a SHAPE, not a known value.
|
|
212
|
-
* Correctness must not depend on seeding the redactor with the literal
|
|
213
|
-
* secret — the two real leaks this project hit were a database password that
|
|
214
|
-
* survived a naive `sed` mask (as a substring) and an Anthropic key surfaced in
|
|
215
|
-
* a deploy CLI's describe output that the harness NEVER loaded. A value-seeded
|
|
216
|
-
* redactor is blind to both; these patterns catch them by form.
|
|
217
|
-
*
|
|
218
|
-
* Ordering matters: structured shapes (connection strings, auth headers, JWT)
|
|
219
|
-
* come BEFORE the generic key/entropy catch-alls so the more descriptive
|
|
220
|
-
* `[REDACTED …]` label wins on overlapping matches.
|
|
221
|
-
*/
|
|
222
|
-
const SECRET_PATTERNS = [
|
|
223
|
-
// postgres / postgresql connection strings — redact the whole URI so the
|
|
224
|
-
// embedded password can never survive as a substring (the `sed`-mask leak).
|
|
225
|
-
/\bpostgres(?:ql)?:\/\/[^\s"']+/gi,
|
|
226
|
-
// aex workspace / proxy tokens: apt_… / ant_….
|
|
227
|
-
/\b(?:apt|ant)_[A-Za-z0-9_-]{16,}/g,
|
|
228
|
-
// aex self-describing workspace API key (one-time reveal from createWorkspace /
|
|
229
|
-
// createApiKey): aex_<plane>_<region>_<workspaceId>_<secret>_<crc>. Anchored on
|
|
230
|
-
// the full 6-part shape so the whole key masks as one label (the entropy
|
|
231
|
-
// catch-all would otherwise redact only its dense segments, leaving the
|
|
232
|
-
// `aex_<plane>_<region>_` prefix behind). Never matches `api.aex.dev`.
|
|
233
|
-
/\baex_(?:dev|prd)_[a-z0-9]+_[a-z0-9]+_[A-Za-z0-9]+_[a-z0-9]+/gi,
|
|
234
|
-
// aex account PAT (control-plane): aexu_<opaque>. Distinct prefix from the
|
|
235
|
-
// workspace-key family so a PAT masks by shape even when short.
|
|
236
|
-
/\baexu_[A-Za-z0-9_-]{16,}/g,
|
|
237
|
-
// AWS access key id + secret access key shapes.
|
|
238
|
-
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,
|
|
239
|
-
/\baws_secret_access_key["'\s:=]+[A-Za-z0-9/+=]{40}/gi,
|
|
240
|
-
// JWT-shaped: header.payload.signature, each base64url, header starts `eyJ`.
|
|
241
|
-
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,
|
|
242
|
-
// Keyword-introduced secret assignments (bearer/token/api_key/…).
|
|
243
|
-
/(?:bearer|token|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret)["'\s:=]+[A-Za-z0-9_\-./+=]{12,}/gi
|
|
244
|
-
];
|
|
245
|
-
const SDK_SHARED_SECRET_PATTERNS = PUBLIC_SAFE_SECRET_PATTERNS.filter((pattern) => pattern.reason === "bearer_token" ||
|
|
246
|
-
pattern.reason === "provider_key" ||
|
|
247
|
-
pattern.reason === "signed_url");
|
|
248
|
-
const REDACTED = "[REDACTED]";
|
|
249
|
-
/**
|
|
250
|
-
* Generic high-entropy token catch-all, applied AFTER the named patterns.
|
|
251
|
-
* Catches the secret nobody recognised: any long base64url/hex-ish run that is
|
|
252
|
-
* BOTH high-entropy AND character-class-diverse.
|
|
253
|
-
*
|
|
254
|
-
* The candidate run deliberately EXCLUDES `_`: secrets are contiguous opaque
|
|
255
|
-
* runs, whereas `SCREAMING_SNAKE_CASE` env names and `snake_case` identifiers
|
|
256
|
-
* are `_`-separated words — excluding `_` breaks those into sub-24 fragments so
|
|
257
|
-
* they are never eaten. The
|
|
258
|
-
* class-diversity gate (≥2 of lower/upper/digit) then keeps the remaining
|
|
259
|
-
* single-class runs (all-lowercase module paths like `internal/modules/esm`)
|
|
260
|
-
* while still catching mixed-case/alnum secret blobs. Entropy alone cannot
|
|
261
|
-
* separate these — `the_quick…` (4.16) out-scores a real key prefix.
|
|
262
|
-
*/
|
|
263
|
-
const HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9+/=-]{24,}/g;
|
|
264
|
-
/**
|
|
265
|
-
* A mixed-case run with no digit and < this length is treated as a benign
|
|
266
|
-
* identifier, not a secret. Real opaque secrets are alnum-mixed (carry a
|
|
267
|
-
* digit) or very long; digit-free camelCase identifiers like
|
|
268
|
-
* `asyncEntryPointWithESMLoader` / `getReadableStreamController` (which
|
|
269
|
-
* appear in stack traces the diagnostic bundle captures) are 24–39 chars and
|
|
270
|
-
* digit-free — eating them would gut debuggability. The length escape hatch
|
|
271
|
-
* still catches the rare long digit-free secret.
|
|
272
|
-
*/
|
|
273
|
-
/**
|
|
274
|
-
* Canonical aex session-id hex: exactly 32 lowercase hex chars directly preceded
|
|
275
|
-
* by `ses_`. The HIGH_ENTROPY_CANDIDATE class excludes `_`, so the candidate
|
|
276
|
-
* candidate for a session id is the bare hex — dense enough to trip the entropy gate.
|
|
277
|
-
* Masking it destroys the ONE identifier every error message needs for
|
|
278
|
-
* traceability (`cancel via aex.sessions.open("ses_[REDACTED]")` is useless
|
|
279
|
-
* guidance). A session id is not a credential: it grants nothing without the
|
|
280
|
-
* bearer token. Mirrors the platform-side redactor's canonical-id exemption.
|
|
281
|
-
*/
|
|
282
|
-
function isCanonicalSessionIdHex(input, matchStart, match) {
|
|
283
|
-
if (!/^[0-9a-f]{32}$/.test(match))
|
|
284
|
-
return false;
|
|
285
|
-
return input.slice(Math.max(0, matchStart - 4), matchStart) === "ses_";
|
|
286
|
-
}
|
|
287
|
-
export class SecretString {
|
|
288
|
-
#value;
|
|
289
|
-
constructor(value, label = "secret") {
|
|
290
|
-
if (!value) {
|
|
291
|
-
throw new Error(`${label} is required`);
|
|
292
|
-
}
|
|
293
|
-
this.#value = value;
|
|
294
|
-
}
|
|
295
|
-
unwrap() {
|
|
296
|
-
return this.#value;
|
|
297
|
-
}
|
|
298
|
-
toString() {
|
|
299
|
-
return REDACTED;
|
|
300
|
-
}
|
|
301
|
-
toJSON() {
|
|
302
|
-
return REDACTED;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
export function redactSecrets(value) {
|
|
306
|
-
if (typeof value === "string") {
|
|
307
|
-
return redactString(value);
|
|
308
|
-
}
|
|
309
|
-
if (Array.isArray(value)) {
|
|
310
|
-
return value.map((item) => redactSecrets(item));
|
|
311
|
-
}
|
|
312
|
-
if (value && typeof value === "object") {
|
|
313
|
-
const out = {};
|
|
314
|
-
for (const [key, item] of Object.entries(value)) {
|
|
315
|
-
if (isSecretKey(key)) {
|
|
316
|
-
out[key] = REDACTED;
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
out[key] = redactSecrets(item);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return out;
|
|
323
|
-
}
|
|
324
|
-
return value;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Redact every secret-shaped run in `input`.
|
|
328
|
-
*
|
|
329
|
-
* `known` is an OPTIONAL belt-and-suspenders set of literal values to also mask
|
|
330
|
-
* (e.g. creds the caller happens to have loaded). Correctness does NOT depend on
|
|
331
|
-
* it — every shape above is caught with or without seeding — but masking known
|
|
332
|
-
* values first removes any residual substring of a value the shapes split.
|
|
333
|
-
*/
|
|
334
|
-
export function redactString(input, known = []) {
|
|
335
|
-
let out = input;
|
|
336
|
-
for (const value of known) {
|
|
337
|
-
if (value && value.length >= 4) {
|
|
338
|
-
out = out.split(value).join(REDACTED);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
out = SDK_SHARED_SECRET_PATTERNS.reduce((current, pattern) => current.replace(new RegExp(pattern.regex.source, pattern.regex.flags.includes("g")
|
|
342
|
-
? pattern.regex.flags
|
|
343
|
-
: `${pattern.regex.flags}g`), (match, captured) => typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED), out);
|
|
344
|
-
out = SECRET_PATTERNS.reduce((current, pattern) => current.replace(pattern, (match, captured) => typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED), out);
|
|
345
|
-
return out.replace(HIGH_ENTROPY_CANDIDATE, (match, offset, whole) => !isCanonicalSessionIdHex(whole, offset, match) &&
|
|
346
|
-
!isPlatformContentDigest(match) &&
|
|
347
|
-
looksHighEntropySecret(match)
|
|
348
|
-
? REDACTED
|
|
349
|
-
: match);
|
|
350
|
-
}
|
|
351
|
-
export function containsSecretLikeValue(input) {
|
|
352
|
-
if ([...SECRET_PATTERNS, ...SDK_SHARED_SECRET_PATTERNS.map((pattern) => pattern.regex)].some((pattern) => {
|
|
353
|
-
pattern.lastIndex = 0;
|
|
354
|
-
return pattern.test(input);
|
|
355
|
-
})) {
|
|
356
|
-
return true;
|
|
357
|
-
}
|
|
358
|
-
HIGH_ENTROPY_CANDIDATE.lastIndex = 0;
|
|
359
|
-
let candidate;
|
|
360
|
-
while ((candidate = HIGH_ENTROPY_CANDIDATE.exec(input)) !== null) {
|
|
361
|
-
if (isCanonicalSessionIdHex(input, candidate.index, candidate[0])) {
|
|
362
|
-
continue;
|
|
363
|
-
}
|
|
364
|
-
if (isPlatformContentDigest(candidate[0])) {
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
if (looksHighEntropySecret(candidate[0])) {
|
|
368
|
-
return true;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* A line-buffered `Transform` that redacts secrets BEFORE bytes touch disk or
|
|
375
|
-
* console. Pipe a child process's stdout/stderr through it
|
|
376
|
-
* (`child.stdout.pipe(createRedactingStream()).pipe(process.stdout)`) so a
|
|
377
|
-
* secret can never be written and "cleaned up after"; the secret you didn't
|
|
378
|
-
* recognise is the one already on disk.
|
|
379
|
-
*
|
|
380
|
-
* Buffers by line so a secret split across a chunk boundary is still redacted:
|
|
381
|
-
* a partial trailing line is held until the next chunk (or `flush`) completes
|
|
382
|
-
* it. `known` is forwarded to `redactString` for optional value seeding.
|
|
383
|
-
*/
|
|
384
|
-
export function createRedactingStream(known = []) {
|
|
385
|
-
const knownValues = [...known];
|
|
386
|
-
let carry = "";
|
|
387
|
-
return new Transform({
|
|
388
|
-
transform(chunk, _encoding, callback) {
|
|
389
|
-
carry += chunk.toString();
|
|
390
|
-
const lastNewline = carry.lastIndexOf("\n");
|
|
391
|
-
if (lastNewline === -1) {
|
|
392
|
-
callback();
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
const ready = carry.slice(0, lastNewline + 1);
|
|
396
|
-
carry = carry.slice(lastNewline + 1);
|
|
397
|
-
callback(null, redactString(ready, knownValues));
|
|
398
|
-
},
|
|
399
|
-
flush(callback) {
|
|
400
|
-
if (carry === "") {
|
|
401
|
-
callback();
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
const tail = carry;
|
|
405
|
-
carry = "";
|
|
406
|
-
callback(null, redactString(tail, knownValues));
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Wire keys that contain a secret-looking word but name a QUANTITY, not a
|
|
412
|
-
* credential. Same argument as the canonical-session-id exemption above: masking
|
|
413
|
-
* them destroys the one number the message exists to carry, and the value grants
|
|
414
|
-
* nothing to whoever reads it.
|
|
415
|
-
*
|
|
416
|
-
* `llm_token_usd` is the free model-usage allowance dimension. It is the field a
|
|
417
|
-
* `402 insufficient_credits` body is read for — "$0.00 of $2.00 left this month"
|
|
418
|
-
* — and the substring `token` in a dimension name is a coincidence of the
|
|
419
|
-
* metering vocabulary, not a credential. The name is fixed by the hosted
|
|
420
|
-
* allowance schema, so it cannot be spelled around on the client.
|
|
421
|
-
*/
|
|
422
|
-
const NON_SECRET_KEYS = new Set(["llm_token_usd"]);
|
|
423
|
-
function isSecretKey(key) {
|
|
424
|
-
if (NON_SECRET_KEYS.has(key))
|
|
425
|
-
return false;
|
|
426
|
-
return /(?:api[_-]?key|authorization|token|secret|password|credential)/i.test(key);
|
|
427
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { AexEvent } from "./event-envelope.js";
|
|
2
|
-
import { type SessionRecordArchiveEntryForRedactionV1, type SessionRecordArtifactSummaryV1, type SessionRecordDownloadErrorV1 } from "./session-record.js";
|
|
3
|
-
import type { Session } from "./runtime-types.js";
|
|
4
|
-
export interface SessionArchiveEntry extends SessionRecordArchiveEntryForRedactionV1 {
|
|
5
|
-
readonly path: string;
|
|
6
|
-
readonly bytes: Uint8Array;
|
|
7
|
-
}
|
|
8
|
-
export interface CollectedSessionArchiveArtifacts {
|
|
9
|
-
readonly entries: readonly SessionArchiveEntry[];
|
|
10
|
-
readonly captured: readonly SessionRecordArtifactSummaryV1[];
|
|
11
|
-
readonly errors: readonly SessionRecordDownloadErrorV1[];
|
|
12
|
-
}
|
|
13
|
-
export declare function buildSessionArchive(sessionId: string, session: Session, events: readonly AexEvent[], files: CollectedSessionArchiveArtifacts): Uint8Array;
|
|
14
|
-
export declare function buildSessionFilesArchive(sessionId: string, files: CollectedSessionArchiveArtifacts): Uint8Array;
|
|
15
|
-
export declare function buildSessionEventsArchive(sessionId: string, events: readonly AexEvent[]): Uint8Array;
|
|
16
|
-
export declare function buildSessionMetadataArchive(sessionId: string, session: Session): Uint8Array;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { strToU8, zipSync } from "fflate";
|
|
2
|
-
import { isRecord } from "./value-guards.js";
|
|
3
|
-
import { assertSessionRecordArchivePublicSafeV1, buildSessionRecordDownloadManifestV1 } from "./session-record.js";
|
|
4
|
-
export function buildSessionArchive(sessionId, session, events, files) {
|
|
5
|
-
const submissionSnapshot = extractSubmissionSnapshot(session);
|
|
6
|
-
const costTelemetry = extractCostTelemetry(session);
|
|
7
|
-
const manifest = buildSessionRecordDownloadManifestV1({
|
|
8
|
-
sessionId,
|
|
9
|
-
sessionFiles: files.captured,
|
|
10
|
-
errors: files.errors,
|
|
11
|
-
typedEventCount: events.length,
|
|
12
|
-
...(submissionSnapshot ? { submission: { status: "present" } } : {}),
|
|
13
|
-
...(costTelemetry ? { cost: { status: "present" } } : {})
|
|
14
|
-
});
|
|
15
|
-
return zipEntries([
|
|
16
|
-
jsonEntry("metadata/session.json", session),
|
|
17
|
-
...(submissionSnapshot ? [jsonEntry("metadata/submission.json", submissionSnapshot)] : []),
|
|
18
|
-
...(costTelemetry ? [jsonEntry("metadata/cost.json", costTelemetry)] : []),
|
|
19
|
-
jsonlEntry("events/events.jsonl", events),
|
|
20
|
-
...files.entries,
|
|
21
|
-
jsonEntry("manifest.json", manifest)
|
|
22
|
-
]);
|
|
23
|
-
}
|
|
24
|
-
export function buildSessionFilesArchive(sessionId, files) {
|
|
25
|
-
return zipEntries([
|
|
26
|
-
...files.entries,
|
|
27
|
-
jsonEntry("manifest.json", {
|
|
28
|
-
sessionId,
|
|
29
|
-
namespace: "files",
|
|
30
|
-
files: files.captured,
|
|
31
|
-
errors: files.errors
|
|
32
|
-
})
|
|
33
|
-
]);
|
|
34
|
-
}
|
|
35
|
-
export function buildSessionEventsArchive(sessionId, events) {
|
|
36
|
-
return zipEntries([
|
|
37
|
-
jsonlEntry("events.jsonl", events),
|
|
38
|
-
jsonEntry("manifest.json", {
|
|
39
|
-
sessionId,
|
|
40
|
-
namespace: "events",
|
|
41
|
-
files: [{ path: "events.jsonl", role: "typed_events", status: "present", recordCount: events.length }],
|
|
42
|
-
errors: []
|
|
43
|
-
})
|
|
44
|
-
]);
|
|
45
|
-
}
|
|
46
|
-
export function buildSessionMetadataArchive(sessionId, session) {
|
|
47
|
-
return zipEntries([
|
|
48
|
-
jsonEntry("session.json", session),
|
|
49
|
-
jsonEntry("manifest.json", {
|
|
50
|
-
sessionId,
|
|
51
|
-
namespace: "metadata",
|
|
52
|
-
files: [{ path: "session.json", role: "session_metadata", status: "present" }],
|
|
53
|
-
errors: []
|
|
54
|
-
})
|
|
55
|
-
]);
|
|
56
|
-
}
|
|
57
|
-
function zipEntries(entries) {
|
|
58
|
-
assertSessionRecordArchivePublicSafeV1(entries);
|
|
59
|
-
const files = {};
|
|
60
|
-
for (const entry of entries) {
|
|
61
|
-
files[entry.path] = [entry.bytes, { mtime: ZIP_EPOCH }];
|
|
62
|
-
}
|
|
63
|
-
return zipSync(files);
|
|
64
|
-
}
|
|
65
|
-
/** Fixed ZIP timestamp: session archives must not depend on the wall clock. */
|
|
66
|
-
const ZIP_EPOCH = new Date(Date.UTC(1980, 0, 1));
|
|
67
|
-
function jsonEntry(path, value) {
|
|
68
|
-
return {
|
|
69
|
-
path,
|
|
70
|
-
bytes: strToU8(JSON.stringify(value, null, 2)),
|
|
71
|
-
contentType: "application/json; charset=utf-8"
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function jsonlEntry(path, events) {
|
|
75
|
-
return {
|
|
76
|
-
path,
|
|
77
|
-
bytes: strToU8(events.map((event) => JSON.stringify(event)).join("\n")),
|
|
78
|
-
contentType: "application/jsonl; charset=utf-8"
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function extractSubmissionSnapshot(session) {
|
|
82
|
-
const raw = session.submission;
|
|
83
|
-
if (!isRecord(raw) || raw.kind !== "submission" || !isRecord(raw.submission)) {
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
submission: raw.submission
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function extractCostTelemetry(session) {
|
|
91
|
-
return session.costTelemetry;
|
|
92
|
-
}
|