@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,135 +0,0 @@
|
|
|
1
|
-
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
2
|
-
/**
|
|
3
|
-
* Sink for local debug traces. Receives one preformatted line per HTTP
|
|
4
|
-
* round-trip (method, path, status, elapsed). NEVER carries the auth
|
|
5
|
-
* header, request/response bodies, or query string — purely a local
|
|
6
|
-
* diagnostic; nothing is uploaded. The SDK wires this to `console.error`
|
|
7
|
-
* when `debug` is set; the CLI wires it to stderr under `--debug`.
|
|
8
|
-
*/
|
|
9
|
-
export type DebugSink = (line: string) => void;
|
|
10
|
-
/**
|
|
11
|
-
* Tunables for the shared retry policy. All fields are optional; omit the whole
|
|
12
|
-
* object to accept {@link HTTP_RETRY_POLICY}, or pass `false` where a client
|
|
13
|
-
* accepts it to turn retrying off entirely.
|
|
14
|
-
*/
|
|
15
|
-
export interface HttpRetryOptions {
|
|
16
|
-
/**
|
|
17
|
-
* Maximum attempts INCLUDING the first try. Default `4` (one try + three
|
|
18
|
-
* retries). `1` performs a single attempt with no retries (but still maps a
|
|
19
|
-
* final rate-limit status to {@link AexRateLimitError}).
|
|
20
|
-
*/
|
|
21
|
-
readonly maxAttempts?: number;
|
|
22
|
-
/**
|
|
23
|
-
* Base delay (ms) for the exponential backoff — the nominal wait before the
|
|
24
|
-
* first retry, doubling each subsequent retry. Default `500`.
|
|
25
|
-
*/
|
|
26
|
-
readonly initialDelayMs?: number;
|
|
27
|
-
/** Upper bound (ms) on any single backoff wait. Default `20_000`. */
|
|
28
|
-
readonly maxDelayMs?: number;
|
|
29
|
-
/**
|
|
30
|
-
* Overall wall-clock budget (ms) across all attempts. Once the next backoff
|
|
31
|
-
* would push past this, the loop stops and surfaces the last error. Default
|
|
32
|
-
* `120_000`.
|
|
33
|
-
*/
|
|
34
|
-
readonly maxElapsedMs?: number;
|
|
35
|
-
}
|
|
36
|
-
/** A fully resolved {@link HttpRetryOptions} — every field decided. */
|
|
37
|
-
export interface HttpRetryPolicy {
|
|
38
|
-
readonly maxAttempts: number;
|
|
39
|
-
readonly initialDelayMs: number;
|
|
40
|
-
readonly maxDelayMs: number;
|
|
41
|
-
readonly maxElapsedMs: number;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* The single default policy. Identity matters: every client that accepts the
|
|
45
|
-
* defaults resolves to THIS object, which is what the SDK/CLI fitness test
|
|
46
|
-
* asserts.
|
|
47
|
-
*/
|
|
48
|
-
export declare const HTTP_RETRY_POLICY: HttpRetryPolicy;
|
|
49
|
-
/** Resolve caller options over {@link HTTP_RETRY_POLICY}, clamping to sane bounds. */
|
|
50
|
-
export declare function resolveHttpRetryPolicy(options: HttpRetryOptions | undefined): HttpRetryPolicy;
|
|
51
|
-
/** Hooks the retry policy needs, injectable so tests run without real timers. */
|
|
52
|
-
export interface HttpRetryDeps {
|
|
53
|
-
readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
54
|
-
readonly random?: () => number;
|
|
55
|
-
readonly now?: () => number;
|
|
56
|
-
/** Optional redacted trace of each backoff decision (the CLI's `--debug`). */
|
|
57
|
-
readonly debug?: DebugSink;
|
|
58
|
-
}
|
|
59
|
-
/** {@link HttpRetryDeps} with every hook decided. */
|
|
60
|
-
export interface ResolvedHttpRetryDeps {
|
|
61
|
-
readonly sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
62
|
-
readonly random: () => number;
|
|
63
|
-
readonly now: () => number;
|
|
64
|
-
}
|
|
65
|
-
export declare function resolveHttpRetryDeps(deps: HttpRetryDeps | undefined): ResolvedHttpRetryDeps;
|
|
66
|
-
/**
|
|
67
|
-
* The ONE scheduling decision: how long to wait before retrying the 1-based
|
|
68
|
-
* `attempt` that just failed, or `undefined` when the attempt count or the
|
|
69
|
-
* wall-clock budget is spent. Full-jitter exponential backoff with the server's
|
|
70
|
-
* `Retry-After` as a floor, both from `retry-core.ts`.
|
|
71
|
-
*
|
|
72
|
-
* Every retry loop in the repo (API transport, direct upload PUT, multipart
|
|
73
|
-
* part PUT) calls this instead of re-deriving the arithmetic.
|
|
74
|
-
*/
|
|
75
|
-
export declare function nextHttpRetryDelayMs(args: {
|
|
76
|
-
readonly policy: HttpRetryPolicy;
|
|
77
|
-
readonly attempt: number;
|
|
78
|
-
readonly startedAtMs: number;
|
|
79
|
-
readonly deps: ResolvedHttpRetryDeps;
|
|
80
|
-
readonly retryAfterMs?: number | undefined;
|
|
81
|
-
}): number | undefined;
|
|
82
|
-
/**
|
|
83
|
-
* Safe reads are retry-eligible directly; any mutation is eligible only when it
|
|
84
|
-
* carries a stable `Idempotency-Key`, so a replayed write cannot double-bill.
|
|
85
|
-
*/
|
|
86
|
-
export declare function isHttpRetryEligible(input: Parameters<FetchLike>[0], init: Parameters<FetchLike>[1]): boolean;
|
|
87
|
-
/**
|
|
88
|
-
* Wrap a {@link FetchLike} with the shared bounded-retry loop. `retry === false`
|
|
89
|
-
* disables the layer entirely (the input fetch is returned unchanged). Otherwise
|
|
90
|
-
* an eligible request is retried on a network error OR a retryable status
|
|
91
|
-
* (429/500/502/503/504/529 per `retry-core.ts`), and an exhausted
|
|
92
|
-
* rate-limit/overloaded status surfaces {@link AexRateLimitError}.
|
|
93
|
-
*/
|
|
94
|
-
export declare function withHttpRetry(fetchImpl: FetchLike, retry: HttpRetryOptions | false | undefined, deps?: HttpRetryDeps): FetchLike;
|
|
95
|
-
export interface HttpClientOptions {
|
|
96
|
-
/**
|
|
97
|
-
* API plane root. Optional — defaults to `AEX_DEFAULT_BASE_URL`
|
|
98
|
-
* (`https://api.aex.dev`). Self-hosted deployments override with their
|
|
99
|
-
* own URL; no env var consults this value.
|
|
100
|
-
*/
|
|
101
|
-
readonly baseUrl?: string;
|
|
102
|
-
readonly apiKey: string;
|
|
103
|
-
readonly fetch?: FetchLike;
|
|
104
|
-
/** When set, every request emits a redacted one-line trace here. */
|
|
105
|
-
readonly debug?: DebugSink;
|
|
106
|
-
/**
|
|
107
|
-
* Retry policy for this transport, applied through {@link withHttpRetry}.
|
|
108
|
-
* OMITTED (or `false`) means one attempt per request: every host opts in
|
|
109
|
-
* explicitly — the SDK and the CLI both pass {@link HTTP_RETRY_POLICY} — so
|
|
110
|
-
* there is exactly one place the numbers live.
|
|
111
|
-
*/
|
|
112
|
-
readonly retry?: HttpRetryOptions | false;
|
|
113
|
-
/** Injectable clock/RNG/sleep for the retry loop; tests only. */
|
|
114
|
-
readonly retryDeps?: HttpRetryDeps;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Thin transport used by every BFF-bound operation. The SDK class and
|
|
118
|
-
* the CLI subcommands BOTH build an `HttpClient` and pass it to the
|
|
119
|
-
* operations module — so they cannot drift in how they auth, encode
|
|
120
|
-
* query parameters, or decode error responses.
|
|
121
|
-
*/
|
|
122
|
-
export declare class HttpClient {
|
|
123
|
-
#private;
|
|
124
|
-
constructor(options: HttpClientOptions);
|
|
125
|
-
/**
|
|
126
|
-
* The retry policy this transport resolved, or `null` when retrying is off.
|
|
127
|
-
* Exposed so the SDK↔CLI fitness test can assert both hosts landed on the
|
|
128
|
-
* SAME policy object rather than on two sets of equal-looking numbers.
|
|
129
|
-
*/
|
|
130
|
-
get retryPolicy(): HttpRetryPolicy | null;
|
|
131
|
-
request<T>(path: string, init?: RequestInit, query?: Record<string, string>): Promise<T>;
|
|
132
|
-
download(path: string, init?: RequestInit, query?: Record<string, string>): Promise<{
|
|
133
|
-
readonly response: Response;
|
|
134
|
-
}>;
|
|
135
|
-
}
|
package/dist/_contracts/http.js
DELETED
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
import { AexError, AexNetworkError, AexRateLimitError, extractErrorCode, redactUrl } from "./sdk-errors.js";
|
|
2
|
-
import { apiErrorFromResponse } from "./error-factory.js";
|
|
3
|
-
import { AEX_DEFAULT_BASE_URL } from "./stable.js";
|
|
4
|
-
import { abortableSleep, computeRetryDelayMs, isRateLimitHttpStatus, isRetryableHttpStatus, tryParseRetryAfterMs } from "./retry-core.js";
|
|
5
|
-
import { reportWireResponse } from "./wire-observer.js";
|
|
6
|
-
/**
|
|
7
|
-
* The single default policy. Identity matters: every client that accepts the
|
|
8
|
-
* defaults resolves to THIS object, which is what the SDK/CLI fitness test
|
|
9
|
-
* asserts.
|
|
10
|
-
*/
|
|
11
|
-
export const HTTP_RETRY_POLICY = Object.freeze({
|
|
12
|
-
maxAttempts: 4,
|
|
13
|
-
initialDelayMs: 500,
|
|
14
|
-
maxDelayMs: 20_000,
|
|
15
|
-
maxElapsedMs: 120_000
|
|
16
|
-
});
|
|
17
|
-
/** Resolve caller options over {@link HTTP_RETRY_POLICY}, clamping to sane bounds. */
|
|
18
|
-
export function resolveHttpRetryPolicy(options) {
|
|
19
|
-
// Identity-preserving: an omitted policy, or the shared default handed back in,
|
|
20
|
-
// resolves to the SAME object — so a host that accepts the defaults is
|
|
21
|
-
// observably on the one policy, not on a private copy of its numbers.
|
|
22
|
-
if (options === undefined || options === HTTP_RETRY_POLICY)
|
|
23
|
-
return HTTP_RETRY_POLICY;
|
|
24
|
-
const maxAttempts = Math.max(1, Math.floor(options.maxAttempts ?? HTTP_RETRY_POLICY.maxAttempts));
|
|
25
|
-
const initialDelayMs = Math.max(0, options.initialDelayMs ?? HTTP_RETRY_POLICY.initialDelayMs);
|
|
26
|
-
const maxDelayMs = Math.max(initialDelayMs, options.maxDelayMs ?? HTTP_RETRY_POLICY.maxDelayMs);
|
|
27
|
-
const maxElapsedMs = Math.max(0, options.maxElapsedMs ?? HTTP_RETRY_POLICY.maxElapsedMs);
|
|
28
|
-
return { maxAttempts, initialDelayMs, maxDelayMs, maxElapsedMs };
|
|
29
|
-
}
|
|
30
|
-
export function resolveHttpRetryDeps(deps) {
|
|
31
|
-
return {
|
|
32
|
-
sleep: deps?.sleep ?? abortableSleep,
|
|
33
|
-
random: deps?.random ?? Math.random,
|
|
34
|
-
now: deps?.now ?? Date.now
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* The ONE scheduling decision: how long to wait before retrying the 1-based
|
|
39
|
-
* `attempt` that just failed, or `undefined` when the attempt count or the
|
|
40
|
-
* wall-clock budget is spent. Full-jitter exponential backoff with the server's
|
|
41
|
-
* `Retry-After` as a floor, both from `retry-core.ts`.
|
|
42
|
-
*
|
|
43
|
-
* Every retry loop in the repo (API transport, direct upload PUT, multipart
|
|
44
|
-
* part PUT) calls this instead of re-deriving the arithmetic.
|
|
45
|
-
*/
|
|
46
|
-
export function nextHttpRetryDelayMs(args) {
|
|
47
|
-
if (args.attempt >= args.policy.maxAttempts)
|
|
48
|
-
return undefined;
|
|
49
|
-
const delayMs = computeRetryDelayMs(args.policy, args.attempt, args.deps.random, args.retryAfterMs);
|
|
50
|
-
if (args.deps.now() - args.startedAtMs + delayMs > args.policy.maxElapsedMs)
|
|
51
|
-
return undefined;
|
|
52
|
-
return delayMs;
|
|
53
|
-
}
|
|
54
|
-
const SAFE_READ_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
|
|
55
|
-
/**
|
|
56
|
-
* Safe reads are retry-eligible directly; any mutation is eligible only when it
|
|
57
|
-
* carries a stable `Idempotency-Key`, so a replayed write cannot double-bill.
|
|
58
|
-
*/
|
|
59
|
-
export function isHttpRetryEligible(input, init) {
|
|
60
|
-
const request = typeof Request !== "undefined" && input instanceof Request ? input : undefined;
|
|
61
|
-
const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
|
|
62
|
-
if (SAFE_READ_METHODS.has(method))
|
|
63
|
-
return true;
|
|
64
|
-
const idempotencyKey = new Headers(init?.headers ?? request?.headers).get("idempotency-key");
|
|
65
|
-
return typeof idempotencyKey === "string" && idempotencyKey.trim().length > 0;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Wrap a {@link FetchLike} with the shared bounded-retry loop. `retry === false`
|
|
69
|
-
* disables the layer entirely (the input fetch is returned unchanged). Otherwise
|
|
70
|
-
* an eligible request is retried on a network error OR a retryable status
|
|
71
|
-
* (429/500/502/503/504/529 per `retry-core.ts`), and an exhausted
|
|
72
|
-
* rate-limit/overloaded status surfaces {@link AexRateLimitError}.
|
|
73
|
-
*/
|
|
74
|
-
export function withHttpRetry(fetchImpl, retry, deps = {}) {
|
|
75
|
-
if (retry === false)
|
|
76
|
-
return fetchImpl;
|
|
77
|
-
const policy = resolveHttpRetryPolicy(retry);
|
|
78
|
-
const resolved = resolveHttpRetryDeps(deps);
|
|
79
|
-
const debug = deps.debug;
|
|
80
|
-
return async (input, init) => {
|
|
81
|
-
if (!isHttpRetryEligible(input, init))
|
|
82
|
-
return fetchImpl(input, init);
|
|
83
|
-
const startedAtMs = resolved.now();
|
|
84
|
-
const signal = init?.signal ?? undefined;
|
|
85
|
-
for (let attempt = 1;; attempt += 1) {
|
|
86
|
-
let response;
|
|
87
|
-
try {
|
|
88
|
-
response = await fetchImpl(input, init);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
// A caller-initiated abort is terminal, never transient.
|
|
92
|
-
if (isAbortError(err))
|
|
93
|
-
throw err;
|
|
94
|
-
const delayMs = nextHttpRetryDelayMs({ policy, attempt, startedAtMs, deps: resolved });
|
|
95
|
-
if (delayMs === undefined) {
|
|
96
|
-
throw networkRetryExhausted(err, input, init, attempt, resolved.now() - startedAtMs);
|
|
97
|
-
}
|
|
98
|
-
traceRetry(debug, input, init, `transient ${extractErrorCode(err) ?? "network"}`, attempt, policy, delayMs);
|
|
99
|
-
await resolved.sleep(delayMs, signal);
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
// Success or a definitive (non-retryable) response — hand straight back so
|
|
103
|
-
// the transport reads/throws exactly as it does without the retry layer.
|
|
104
|
-
if (!isRetryableHttpStatus(response.status))
|
|
105
|
-
return response;
|
|
106
|
-
const retryAfterMs = tryParseRetryAfterMs(response.headers.get("retry-after"), resolved.now());
|
|
107
|
-
const delayMs = nextHttpRetryDelayMs({ policy, attempt, startedAtMs, deps: resolved, retryAfterMs });
|
|
108
|
-
if (delayMs !== undefined) {
|
|
109
|
-
await drain(response);
|
|
110
|
-
traceRetry(debug, input, init, `status ${response.status}`, attempt, policy, delayMs);
|
|
111
|
-
await resolved.sleep(delayMs, signal);
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
// Retries exhausted (or budget spent). A rate-limit/overloaded status
|
|
115
|
-
// becomes a structured throttle error; any other transient status falls
|
|
116
|
-
// through to the transport's normal AexApiError.
|
|
117
|
-
if (isRateLimitHttpStatus(response.status)) {
|
|
118
|
-
const body = withResponseRequestId(await readJson(response).catch(() => ({})), response.headers);
|
|
119
|
-
throw new AexRateLimitError({
|
|
120
|
-
status: response.status,
|
|
121
|
-
attempts: attempt,
|
|
122
|
-
source: "api",
|
|
123
|
-
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
124
|
-
body
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return response;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
function traceRetry(debug, input, init, reason, attempt, policy, delayMs) {
|
|
132
|
-
if (!debug)
|
|
133
|
-
return;
|
|
134
|
-
const method = (init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
135
|
-
const path = requestUrl(input)?.pathname ?? "";
|
|
136
|
-
debug(`[aex] ${method} ${path} ${reason} attempt ${attempt}/${policy.maxAttempts}; retrying in ${delayMs}ms`);
|
|
137
|
-
}
|
|
138
|
-
function isAbortError(err) {
|
|
139
|
-
return err?.name === "AbortError";
|
|
140
|
-
}
|
|
141
|
-
/** Discard a retryable response body so the connection can be reused. */
|
|
142
|
-
async function drain(response) {
|
|
143
|
-
try {
|
|
144
|
-
if (response.body && typeof response.body.cancel === "function") {
|
|
145
|
-
await response.body.cancel();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
await response.text();
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
// Draining is best-effort; a discarded retryable response never surfaces.
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Wrap the last network-error rejection once retries are exhausted, so the
|
|
156
|
-
* surfaced error states how many attempts were made over how many ms and
|
|
157
|
-
* preserves the raw rejection on `cause`. An {@link AexNetworkError} from an
|
|
158
|
-
* inner transport is annotated — rebuilt with the same request context and its
|
|
159
|
-
* original cause — rather than double-wrapped.
|
|
160
|
-
*/
|
|
161
|
-
function networkRetryExhausted(err, input, init, attempts, elapsedMs) {
|
|
162
|
-
if (err instanceof AexNetworkError) {
|
|
163
|
-
return new AexNetworkError({
|
|
164
|
-
method: err.method,
|
|
165
|
-
host: err.host,
|
|
166
|
-
path: err.path,
|
|
167
|
-
cause: err.cause ?? err,
|
|
168
|
-
attempts,
|
|
169
|
-
elapsedMs
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
const url = requestUrl(input);
|
|
173
|
-
const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
|
|
174
|
-
return new AexNetworkError({
|
|
175
|
-
method: method.toUpperCase(),
|
|
176
|
-
host: url?.host ?? "",
|
|
177
|
-
path: url?.pathname ?? "",
|
|
178
|
-
cause: err,
|
|
179
|
-
attempts,
|
|
180
|
-
elapsedMs
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
function requestUrl(input) {
|
|
184
|
-
try {
|
|
185
|
-
if (input instanceof URL)
|
|
186
|
-
return input;
|
|
187
|
-
return new URL(typeof input === "string" ? input : input.url);
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Thin transport used by every BFF-bound operation. The SDK class and
|
|
195
|
-
* the CLI subcommands BOTH build an `HttpClient` and pass it to the
|
|
196
|
-
* operations module — so they cannot drift in how they auth, encode
|
|
197
|
-
* query parameters, or decode error responses.
|
|
198
|
-
*/
|
|
199
|
-
export class HttpClient {
|
|
200
|
-
#baseUrl;
|
|
201
|
-
#apiKey;
|
|
202
|
-
#fetch;
|
|
203
|
-
#debug;
|
|
204
|
-
#retryPolicy;
|
|
205
|
-
constructor(options) {
|
|
206
|
-
if (!options.apiKey) {
|
|
207
|
-
throw new Error("HttpClient: apiKey is required");
|
|
208
|
-
}
|
|
209
|
-
const raw = options.baseUrl ?? AEX_DEFAULT_BASE_URL;
|
|
210
|
-
const normalized = raw.endsWith("/") ? raw : `${raw}/`;
|
|
211
|
-
try {
|
|
212
|
-
this.#baseUrl = new URL(normalized);
|
|
213
|
-
}
|
|
214
|
-
catch (err) {
|
|
215
|
-
throw new Error(`HttpClient: invalid aex baseUrl ${JSON.stringify(redactUrl(raw))} — ` +
|
|
216
|
-
`expected an absolute URL like "${AEX_DEFAULT_BASE_URL}"`, { cause: err });
|
|
217
|
-
}
|
|
218
|
-
this.#apiKey = options.apiKey;
|
|
219
|
-
this.#debug = options.debug;
|
|
220
|
-
const retry = options.retry ?? false;
|
|
221
|
-
this.#retryPolicy = retry === false ? null : resolveHttpRetryPolicy(retry);
|
|
222
|
-
this.#fetch = withHttpRetry(options.fetch ?? fetch, retry, {
|
|
223
|
-
...options.retryDeps,
|
|
224
|
-
...(this.#debug ? { debug: this.#debug } : {})
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* The retry policy this transport resolved, or `null` when retrying is off.
|
|
229
|
-
* Exposed so the SDK↔CLI fitness test can assert both hosts landed on the
|
|
230
|
-
* SAME policy object rather than on two sets of equal-looking numbers.
|
|
231
|
-
*/
|
|
232
|
-
get retryPolicy() {
|
|
233
|
-
return this.#retryPolicy;
|
|
234
|
-
}
|
|
235
|
-
/** Emit a redacted round-trip trace (no auth header, body, or query). */
|
|
236
|
-
#trace(method, url, status, startedMs) {
|
|
237
|
-
this.#debug?.(`[aex] ${(method ?? "GET").toUpperCase()} ${url.pathname} -> ${status} ${Date.now() - startedMs}ms`);
|
|
238
|
-
}
|
|
239
|
-
async request(path, init = {}, query = {}) {
|
|
240
|
-
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
241
|
-
for (const [key, value] of Object.entries(query)) {
|
|
242
|
-
url.searchParams.set(key, value);
|
|
243
|
-
}
|
|
244
|
-
const headers = {
|
|
245
|
-
accept: "application/json",
|
|
246
|
-
authorization: `Bearer ${this.#apiKey}`,
|
|
247
|
-
...normalizeHeaders(init.headers)
|
|
248
|
-
};
|
|
249
|
-
if (init.body !== undefined && init.body !== null && !headers["content-type"]) {
|
|
250
|
-
// Default to JSON only for string-shaped bodies. FormData / Blob /
|
|
251
|
-
// ArrayBuffer / streams set their own content-type (and FormData
|
|
252
|
-
// specifically needs fetch to compute the multipart boundary), so
|
|
253
|
-
// we leave content-type untouched for non-string bodies.
|
|
254
|
-
if (typeof init.body === "string") {
|
|
255
|
-
headers["content-type"] = "application/json";
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const method = methodOf(init.method);
|
|
259
|
-
const startedMs = Date.now();
|
|
260
|
-
try {
|
|
261
|
-
const response = await this.#fetch(url, { ...init, headers });
|
|
262
|
-
this.#trace(method, url, response.status, startedMs);
|
|
263
|
-
const body = await readJson(response);
|
|
264
|
-
// C4: the harness validates real server bytes against the response
|
|
265
|
-
// schemas. Every JSON response the SDK, the CLI and the user-test suites
|
|
266
|
-
// receive passes through this one call, which is why the gate attaches
|
|
267
|
-
// here instead of at each of ~120 call sites.
|
|
268
|
-
//
|
|
269
|
-
// It stays on the INNER single attempt, not around the retry loop: the loop
|
|
270
|
-
// now lives in `withHttpRetry`, and a retried request must report each
|
|
271
|
-
// response it actually received, not just the last one.
|
|
272
|
-
//
|
|
273
|
-
// Reported BEFORE the non-2xx throw, and with the RAW body rather than the
|
|
274
|
-
// `withResponseRequestId` enrichment below: the generated spec declares an
|
|
275
|
-
// error envelope for every operation, and a harness that only ever saw 2xx
|
|
276
|
-
// could not check it. `origin` travels too — the control plane serves
|
|
277
|
-
// different bodies at two paths the data plane also uses, so matching on
|
|
278
|
-
// path alone would manufacture violations in a two-plane process.
|
|
279
|
-
reportWireResponse(() => ({
|
|
280
|
-
method,
|
|
281
|
-
origin: url.origin,
|
|
282
|
-
path: url.pathname,
|
|
283
|
-
status: response.status,
|
|
284
|
-
body
|
|
285
|
-
}));
|
|
286
|
-
if (!response.ok) {
|
|
287
|
-
const errorBody = withResponseRequestId(body, response.headers);
|
|
288
|
-
throw apiErrorFromResponse({
|
|
289
|
-
status: response.status,
|
|
290
|
-
body: errorBody,
|
|
291
|
-
message: extractErrorMessage(errorBody)
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
return body;
|
|
295
|
-
}
|
|
296
|
-
catch (err) {
|
|
297
|
-
throw toNetworkError(method, url, err, Date.now() - startedMs);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
async download(path, init = {}, query = {}) {
|
|
301
|
-
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
302
|
-
for (const [key, value] of Object.entries(query)) {
|
|
303
|
-
url.searchParams.set(key, value);
|
|
304
|
-
}
|
|
305
|
-
const headers = {
|
|
306
|
-
authorization: `Bearer ${this.#apiKey}`,
|
|
307
|
-
...normalizeHeaders(init.headers)
|
|
308
|
-
};
|
|
309
|
-
const method = methodOf(init.method);
|
|
310
|
-
const startedMs = Date.now();
|
|
311
|
-
try {
|
|
312
|
-
const response = await this.#fetch(url, { ...init, headers });
|
|
313
|
-
this.#trace(method, url, response.status, startedMs);
|
|
314
|
-
if (!response.ok) {
|
|
315
|
-
const body = await readJson(response);
|
|
316
|
-
// C4: a download's SUCCESS body is bytes, not JSON, so there is nothing
|
|
317
|
-
// to validate on that path — but its FAILURE body is the same error
|
|
318
|
-
// envelope every other route returns, and it is the only way the harness
|
|
319
|
-
// observes the routes reached through `download()` at all.
|
|
320
|
-
reportWireResponse(() => ({
|
|
321
|
-
method,
|
|
322
|
-
origin: url.origin,
|
|
323
|
-
path: url.pathname,
|
|
324
|
-
status: response.status,
|
|
325
|
-
body
|
|
326
|
-
}));
|
|
327
|
-
const errorBody = withResponseRequestId(body, response.headers);
|
|
328
|
-
throw apiErrorFromResponse({
|
|
329
|
-
status: response.status,
|
|
330
|
-
body: errorBody,
|
|
331
|
-
message: extractErrorMessage(errorBody)
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
return { response };
|
|
335
|
-
}
|
|
336
|
-
catch (err) {
|
|
337
|
-
throw toNetworkError(method, url, err, Date.now() - startedMs);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
function methodOf(method) {
|
|
342
|
-
return (method ?? "GET").toUpperCase();
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Wrap a fetch rejection into an {@link AexNetworkError} carrying the
|
|
346
|
-
* request's method + redacted host/path. Caller-initiated aborts and
|
|
347
|
-
* already-structured aex errors (the retry policy's AexRateLimitError or its
|
|
348
|
-
* attempt-annotated AexNetworkError) pass through untouched.
|
|
349
|
-
*/
|
|
350
|
-
function toNetworkError(method, url, err, elapsedMs) {
|
|
351
|
-
if (err instanceof AexError)
|
|
352
|
-
return err;
|
|
353
|
-
// `DOMException` is not an `Error` subclass in every runtime, so match aborts by name.
|
|
354
|
-
if (isAbortError(err))
|
|
355
|
-
return err;
|
|
356
|
-
return new AexNetworkError({
|
|
357
|
-
method: (method ?? "GET").toUpperCase(),
|
|
358
|
-
host: url.host,
|
|
359
|
-
path: url.pathname,
|
|
360
|
-
cause: err,
|
|
361
|
-
elapsedMs
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
function normalizeHeaders(headers) {
|
|
365
|
-
if (!headers)
|
|
366
|
-
return {};
|
|
367
|
-
if (headers instanceof Headers)
|
|
368
|
-
return Object.fromEntries(headers.entries());
|
|
369
|
-
if (Array.isArray(headers))
|
|
370
|
-
return Object.fromEntries(headers);
|
|
371
|
-
return headers;
|
|
372
|
-
}
|
|
373
|
-
async function readJson(response) {
|
|
374
|
-
const text = await response.text();
|
|
375
|
-
if (text.length === 0)
|
|
376
|
-
return {};
|
|
377
|
-
try {
|
|
378
|
-
return JSON.parse(text);
|
|
379
|
-
}
|
|
380
|
-
catch {
|
|
381
|
-
return { raw: text };
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
function withResponseRequestId(body, headers) {
|
|
385
|
-
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
386
|
-
return body;
|
|
387
|
-
const record = body;
|
|
388
|
-
if (typeof record.requestId === "string" && record.requestId.trim())
|
|
389
|
-
return body;
|
|
390
|
-
const requestId = responseRequestId(headers);
|
|
391
|
-
return requestId ? { ...record, requestId } : body;
|
|
392
|
-
}
|
|
393
|
-
function responseRequestId(headers) {
|
|
394
|
-
for (const name of ["x-request-id", "request-id"]) {
|
|
395
|
-
const value = headers.get(name)?.trim();
|
|
396
|
-
if (value)
|
|
397
|
-
return value;
|
|
398
|
-
}
|
|
399
|
-
return undefined;
|
|
400
|
-
}
|
|
401
|
-
function extractErrorMessage(body) {
|
|
402
|
-
if (body && typeof body === "object") {
|
|
403
|
-
const obj = body;
|
|
404
|
-
if (typeof obj.error === "string") {
|
|
405
|
-
// A 409 `session_busy` body carries the session's CURRENT status.
|
|
406
|
-
// Surface it: a send to a deleted (or cancelling/suspending) session
|
|
407
|
-
// otherwise reads as merely "busy", which is misleading for a session
|
|
408
|
-
// that will never accept a turn again.
|
|
409
|
-
const status = body.status;
|
|
410
|
-
if (obj.error === "session_busy" && typeof status === "string") {
|
|
411
|
-
return `session_busy (session status: ${status})`;
|
|
412
|
-
}
|
|
413
|
-
// Most aex API rejections are `{error: <code>, message: <human detail>}`.
|
|
414
|
-
// Keep the stable code first, but don't drop the server's actionable
|
|
415
|
-
// detail (e.g. asset_snapshot_source_missing's "upload and finalize it
|
|
416
|
-
// before referencing it").
|
|
417
|
-
if (typeof obj.message === "string" && obj.message.length > 0 && obj.message !== obj.error) {
|
|
418
|
-
return `${obj.error}: ${obj.message}`;
|
|
419
|
-
}
|
|
420
|
-
return obj.error;
|
|
421
|
-
}
|
|
422
|
-
if (obj.error && typeof obj.error === "object" && "message" in obj.error) {
|
|
423
|
-
const message = obj.error.message;
|
|
424
|
-
if (typeof message === "string")
|
|
425
|
-
return message;
|
|
426
|
-
}
|
|
427
|
-
// aex API error envelope: `{ ok:false, code, message }`. Surface
|
|
428
|
-
// the server's message so structured rejections (e.g. runtime support)
|
|
429
|
-
// aren't flattened to the generic fallback below.
|
|
430
|
-
if (typeof obj.message === "string")
|
|
431
|
-
return obj.message;
|
|
432
|
-
}
|
|
433
|
-
return "aex API request failed";
|
|
434
|
-
}
|
package/dist/_contracts/ids.d.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The identifier authority for every aex entity.
|
|
3
|
-
*
|
|
4
|
-
* One module declares the format, mints the value, and exports the parser.
|
|
5
|
-
* Every other site — database CHECK constraint, HTTP handler, dashboard URL,
|
|
6
|
-
* log line, span attribute, test fixture — imports from here.
|
|
7
|
-
*
|
|
8
|
-
* An identifier has exactly ONE string form: `<prefix>_<32 lowercase hex>`. It
|
|
9
|
-
* is the same bytes in Aurora, in the API response, in the dashboard URL, in
|
|
10
|
-
* the log line, and in the telemetry attribute. There is deliberately no
|
|
11
|
-
* normalizer and no coercer: a value that must be reshaped to be compared has
|
|
12
|
-
* already drifted, so `assertId` throws instead.
|
|
13
|
-
*
|
|
14
|
-
* This module is isomorphic — `crypto.getRandomValues` only, no `node:crypto`,
|
|
15
|
-
* no `Buffer` — because `@aexhq/contracts` ships to browser and edge runtimes and
|
|
16
|
-
* declares no runtime dependency beyond `fflate`. The token pepper and its HMAC
|
|
17
|
-
* stay private in `@aexhq/contract-core`; nothing secret lives here.
|
|
18
|
-
*/
|
|
19
|
-
/**
|
|
20
|
-
* Every identifier kind and its wire prefix. A new entity kind is a new entry
|
|
21
|
-
* here, never a new generator.
|
|
22
|
-
*/
|
|
23
|
-
export declare const ID_PREFIXES: {
|
|
24
|
-
readonly workspace: "wsp";
|
|
25
|
-
readonly session: "ses";
|
|
26
|
-
readonly resource: "wres";
|
|
27
|
-
readonly mcp: "mcp";
|
|
28
|
-
readonly secret: "sec";
|
|
29
|
-
readonly org: "org";
|
|
30
|
-
readonly team: "team";
|
|
31
|
-
readonly user: "usr";
|
|
32
|
-
readonly apiKey: "key";
|
|
33
|
-
readonly idempotency: "idem";
|
|
34
|
-
};
|
|
35
|
-
export type IdKind = keyof typeof ID_PREFIXES;
|
|
36
|
-
export type IdPrefix = (typeof ID_PREFIXES)[IdKind];
|
|
37
|
-
/** `wsp_5fc4b90e55af46cf9938b70f988e431d` — the only form of a workspace id. */
|
|
38
|
-
export type Id<K extends IdKind> = `${(typeof ID_PREFIXES)[K]}_${string}`;
|
|
39
|
-
export declare const ID_KINDS: readonly IdKind[];
|
|
40
|
-
/** The regex source for one kind, e.g. `^wsp_[0-9a-f]{32}$`. */
|
|
41
|
-
export declare function idPatternSource(kind: IdKind): string;
|
|
42
|
-
/** The compiled anchored pattern for one kind. Case-sensitive by design. */
|
|
43
|
-
export declare function idPattern(kind: IdKind): RegExp;
|
|
44
|
-
/**
|
|
45
|
-
* Mint a fresh identifier of `kind`.
|
|
46
|
-
*
|
|
47
|
-
* Fails loudly when no CSPRNG is reachable rather than degrading to
|
|
48
|
-
* `Math.random`: a guessable workspace or session id is a tenancy boundary
|
|
49
|
-
* failure, not a portability inconvenience.
|
|
50
|
-
*/
|
|
51
|
-
export declare function newId<K extends IdKind>(kind: K): Id<K>;
|
|
52
|
-
/** True when `value` is a well-formed identifier of exactly `kind`. */
|
|
53
|
-
export declare function isId<K extends IdKind>(kind: K, value: unknown): value is Id<K>;
|
|
54
|
-
/**
|
|
55
|
-
* Narrow `value` to an identifier of `kind`, or throw.
|
|
56
|
-
*
|
|
57
|
-
* The message names the kind, the expected shape, and the value it got, because
|
|
58
|
-
* the caller's next action is to find whichever layer produced the wrong form.
|
|
59
|
-
*/
|
|
60
|
-
export declare function assertId<K extends IdKind>(kind: K, value: unknown, label?: string): Id<K>;
|
|
61
|
-
/**
|
|
62
|
-
* The kind `value` belongs to, or `undefined`. Used by generic surfaces (audit
|
|
63
|
-
* rows, error messages) that accept several kinds; a call site that knows the
|
|
64
|
-
* kind must use {@link assertId} instead.
|
|
65
|
-
*/
|
|
66
|
-
export declare function idKindOf(value: unknown): IdKind | undefined;
|