@aexhq/sdk 0.37.3 → 0.38.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/README.md +8 -8
- package/dist/_contracts/event-stream-client.d.ts +11 -0
- package/dist/_contracts/event-stream-client.js +45 -5
- package/dist/_contracts/http.d.ts +1 -1
- package/dist/_contracts/http.js +85 -13
- package/dist/_contracts/operations.d.ts +1 -1
- package/dist/_contracts/operations.js +43 -4
- package/dist/_contracts/provider-support.d.ts +2 -2
- package/dist/_contracts/provider-support.js +1 -1
- package/dist/_contracts/run-retention.d.ts +1 -1
- package/dist/_contracts/run-unit.d.ts +1 -1
- package/dist/_contracts/run-unit.js +12 -9
- package/dist/_contracts/runtime-types.d.ts +21 -9
- package/dist/_contracts/sdk-errors.d.ts +44 -2
- package/dist/_contracts/sdk-errors.js +104 -2
- package/dist/_contracts/sdk-secrets.js +18 -1
- package/dist/_contracts/side-effect-audit.d.ts +4 -4
- package/dist/_contracts/side-effect-audit.js +6 -6
- package/dist/_contracts/submission.d.ts +1 -1
- package/dist/asset-upload.js +8 -41
- package/dist/asset-upload.js.map +1 -1
- package/dist/cli.mjs +327 -87
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +20 -6
- package/dist/client.js +148 -18
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/retry.js +66 -6
- package/dist/retry.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +16 -7
- package/docs/billing.md +3 -3
- package/docs/concepts/composition.md +1 -1
- package/docs/concepts/providers-and-runtimes.md +1 -1
- package/docs/concepts/runs.md +1 -1
- package/docs/concepts/subagents.md +6 -3
- package/docs/credentials.md +7 -9
- package/docs/defaults.md +3 -3
- package/docs/errors.md +8 -4
- package/docs/events.md +5 -5
- package/docs/limits-and-quotas.md +3 -3
- package/docs/networking.md +1 -1
- package/docs/outputs.md +2 -2
- package/docs/provider-runtime-capabilities.md +3 -3
- package/docs/public-surface.json +2 -2
- package/docs/quickstart.md +4 -4
- package/docs/retries.md +1 -1
- package/docs/run-config.md +1 -1
- package/docs/run-record.md +1 -1
- package/docs/secrets.md +4 -4
- package/docs/skills.md +1 -1
- package/docs/testing.md +1 -1
- package/docs/vision-skills.md +1 -1
- package/docs/webhooks.md +4 -4
- package/examples/feature-tour.ts +3 -3
- package/package.json +2 -2
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export type AexErrorCode = "RUN_CONFIG_INVALID" | "CREDENTIAL_INVALID" | "PROVIDER_ERROR" | "RUN_STATE_ERROR" | "CLEANUP_ERROR" | "RUNTIME_UNSUPPORTED" | "API_ERROR";
|
|
1
|
+
export type AexErrorCode = "RUN_CONFIG_INVALID" | "CREDENTIAL_INVALID" | "PROVIDER_ERROR" | "RUN_STATE_ERROR" | "CLEANUP_ERROR" | "RUNTIME_UNSUPPORTED" | "API_ERROR" | "NETWORK_ERROR";
|
|
2
2
|
export declare class AexError extends Error {
|
|
3
3
|
readonly code: AexErrorCode;
|
|
4
4
|
readonly details?: unknown;
|
|
5
|
-
constructor(code: AexErrorCode, message: string, details?: unknown
|
|
5
|
+
constructor(code: AexErrorCode, message: string, details?: unknown, options?: {
|
|
6
|
+
readonly cause?: unknown;
|
|
7
|
+
});
|
|
6
8
|
}
|
|
7
9
|
export declare class RunConfigValidationError extends AexError {
|
|
8
10
|
constructor(message: string, details?: unknown);
|
|
@@ -32,3 +34,43 @@ export declare class AexApiError extends AexError {
|
|
|
32
34
|
readonly body: unknown;
|
|
33
35
|
constructor(status: number, message: string, body: unknown);
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a BFF-bound request fails BEFORE any HTTP response exists — DNS
|
|
39
|
+
* failure, connection refused, TLS error, socket reset. Wraps the raw fetch
|
|
40
|
+
* rejection (whose undici form is a bare `TypeError: fetch failed` with the
|
|
41
|
+
* useful code hidden on `cause.code`) into a message that names the request
|
|
42
|
+
* and the transport failure, e.g.
|
|
43
|
+
* `POST api.aex.dev/assets/presign failed: ECONNREFUSED (connect ECONNREFUSED 127.0.0.1:443)`.
|
|
44
|
+
* The original rejection is preserved on `cause`.
|
|
45
|
+
*/
|
|
46
|
+
export declare class AexNetworkError extends AexError {
|
|
47
|
+
readonly method: string;
|
|
48
|
+
/** Request host — never carries credentials or the query string. */
|
|
49
|
+
readonly host: string;
|
|
50
|
+
readonly path: string;
|
|
51
|
+
/** Transport failure code (e.g. `ECONNREFUSED`), when detectable. */
|
|
52
|
+
readonly causeCode: string | undefined;
|
|
53
|
+
/** Attempts made when a retry layer exhausted its budget; `1` otherwise. */
|
|
54
|
+
readonly attempts: number;
|
|
55
|
+
constructor(args: {
|
|
56
|
+
readonly method: string;
|
|
57
|
+
readonly host: string;
|
|
58
|
+
readonly path: string;
|
|
59
|
+
readonly cause: unknown;
|
|
60
|
+
/** Set by the retry layer when it gave up: appended to the message. */
|
|
61
|
+
readonly attempts?: number;
|
|
62
|
+
readonly elapsedMs?: number;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Best-effort transport error code (`ECONNREFUSED`, `ENOTFOUND`, …): checks
|
|
67
|
+
* `err.code`, then `err.cause.code` (where undici hides it), then falls back
|
|
68
|
+
* to an `E…`-shaped token in the message.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractErrorCode(err: unknown): string | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Redact a URL down to protocol + host + path: credentials become
|
|
73
|
+
* `[redacted]@` and any query string becomes `?[redacted]` (presigned URLs
|
|
74
|
+
* carry signatures there). Tolerates unparseable input.
|
|
75
|
+
*/
|
|
76
|
+
export declare function redactUrl(url: string): string;
|
|
@@ -2,8 +2,8 @@ import { redactSecrets } from "./sdk-secrets.js";
|
|
|
2
2
|
export class AexError extends Error {
|
|
3
3
|
code;
|
|
4
4
|
details;
|
|
5
|
-
constructor(code, message, details) {
|
|
6
|
-
super(redactSecrets(message));
|
|
5
|
+
constructor(code, message, details, options) {
|
|
6
|
+
super(redactSecrets(message), options?.cause === undefined ? undefined : { cause: options.cause });
|
|
7
7
|
this.name = this.constructor.name;
|
|
8
8
|
this.code = code;
|
|
9
9
|
this.details = details === undefined ? undefined : redactSecrets(details);
|
|
@@ -49,4 +49,106 @@ export class AexApiError extends AexError {
|
|
|
49
49
|
this.body = redactSecrets(body);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Thrown when a BFF-bound request fails BEFORE any HTTP response exists — DNS
|
|
54
|
+
* failure, connection refused, TLS error, socket reset. Wraps the raw fetch
|
|
55
|
+
* rejection (whose undici form is a bare `TypeError: fetch failed` with the
|
|
56
|
+
* useful code hidden on `cause.code`) into a message that names the request
|
|
57
|
+
* and the transport failure, e.g.
|
|
58
|
+
* `POST api.aex.dev/assets/presign failed: ECONNREFUSED (connect ECONNREFUSED 127.0.0.1:443)`.
|
|
59
|
+
* The original rejection is preserved on `cause`.
|
|
60
|
+
*/
|
|
61
|
+
export class AexNetworkError extends AexError {
|
|
62
|
+
method;
|
|
63
|
+
/** Request host — never carries credentials or the query string. */
|
|
64
|
+
host;
|
|
65
|
+
path;
|
|
66
|
+
/** Transport failure code (e.g. `ECONNREFUSED`), when detectable. */
|
|
67
|
+
causeCode;
|
|
68
|
+
/** Attempts made when a retry layer exhausted its budget; `1` otherwise. */
|
|
69
|
+
attempts;
|
|
70
|
+
constructor(args) {
|
|
71
|
+
const causeCode = extractErrorCode(args.cause);
|
|
72
|
+
super("NETWORK_ERROR", networkErrorMessage(args, causeCode), { method: args.method, host: args.host, path: args.path, ...(causeCode ? { code: causeCode } : {}) }, { cause: args.cause });
|
|
73
|
+
this.method = args.method;
|
|
74
|
+
this.host = args.host;
|
|
75
|
+
this.path = args.path;
|
|
76
|
+
this.causeCode = causeCode;
|
|
77
|
+
this.attempts = args.attempts ?? 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function networkErrorMessage(args, causeCode) {
|
|
81
|
+
const target = args.host ? `${args.host}${args.path}` : "request";
|
|
82
|
+
const detail = shortCauseMessage(args.cause, causeCode);
|
|
83
|
+
const suffix = args.attempts === undefined
|
|
84
|
+
? ""
|
|
85
|
+
: ` after ${args.attempts} attempt${args.attempts === 1 ? "" : "s"} over ${args.elapsedMs ?? 0}ms`;
|
|
86
|
+
let message = `${args.method} ${target} failed`;
|
|
87
|
+
if (causeCode)
|
|
88
|
+
message += `: ${causeCode}`;
|
|
89
|
+
if (detail)
|
|
90
|
+
message += causeCode ? ` (${detail})` : `: ${detail}`;
|
|
91
|
+
return message + suffix;
|
|
92
|
+
}
|
|
93
|
+
/** The innermost useful message off the rejection, URL-redacted and bounded. */
|
|
94
|
+
function shortCauseMessage(cause, causeCode) {
|
|
95
|
+
const nested = cause instanceof Error && cause.cause instanceof Error ? cause.cause : cause;
|
|
96
|
+
const message = nested instanceof Error ? nested.message || nested.name : typeof nested === "string" ? nested : undefined;
|
|
97
|
+
if (!message || message === causeCode)
|
|
98
|
+
return undefined;
|
|
99
|
+
return message.replace(/https?:\/\/[^\s<>"'`]+/g, (raw) => redactUrl(raw)).slice(0, 200);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Best-effort transport error code (`ECONNREFUSED`, `ENOTFOUND`, …): checks
|
|
103
|
+
* `err.code`, then `err.cause.code` (where undici hides it), then falls back
|
|
104
|
+
* to an `E…`-shaped token in the message.
|
|
105
|
+
*/
|
|
106
|
+
export function extractErrorCode(err) {
|
|
107
|
+
const code = stringProperty(err, "code");
|
|
108
|
+
if (code)
|
|
109
|
+
return code;
|
|
110
|
+
const cause = objectProperty(err, "cause");
|
|
111
|
+
const causeCode = stringProperty(cause, "code");
|
|
112
|
+
if (causeCode)
|
|
113
|
+
return causeCode;
|
|
114
|
+
const match = /\bE[A-Z0-9_]+\b/.exec(errorMessageOf(err));
|
|
115
|
+
return match?.[0];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Redact a URL down to protocol + host + path: credentials become
|
|
119
|
+
* `[redacted]@` and any query string becomes `?[redacted]` (presigned URLs
|
|
120
|
+
* carry signatures there). Tolerates unparseable input.
|
|
121
|
+
*/
|
|
122
|
+
export function redactUrl(url) {
|
|
123
|
+
try {
|
|
124
|
+
const parsed = new URL(url);
|
|
125
|
+
const auth = parsed.username || parsed.password ? "[redacted]@" : "";
|
|
126
|
+
const query = parsed.search ? "?[redacted]" : "";
|
|
127
|
+
return `${parsed.protocol}//${auth}${parsed.host}${parsed.pathname}${query}`;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
const withoutAuth = url.replace(/\/\/[^/?#\s]+@/, "//[redacted]@");
|
|
131
|
+
const queryStart = withoutAuth.indexOf("?");
|
|
132
|
+
return queryStart === -1 ? withoutAuth : `${withoutAuth.slice(0, queryStart)}?[redacted]`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function errorMessageOf(err) {
|
|
136
|
+
if (err instanceof Error)
|
|
137
|
+
return err.message || err.name;
|
|
138
|
+
if (typeof err === "string")
|
|
139
|
+
return err;
|
|
140
|
+
return String(err);
|
|
141
|
+
}
|
|
142
|
+
function objectProperty(value, key) {
|
|
143
|
+
if (!value || typeof value !== "object")
|
|
144
|
+
return undefined;
|
|
145
|
+
const prop = value[key];
|
|
146
|
+
return prop && typeof prop === "object" ? prop : undefined;
|
|
147
|
+
}
|
|
148
|
+
function stringProperty(value, key) {
|
|
149
|
+
if (!value || typeof value !== "object")
|
|
150
|
+
return undefined;
|
|
151
|
+
const prop = value[key];
|
|
152
|
+
return typeof prop === "string" && prop.length > 0 ? prop : undefined;
|
|
153
|
+
}
|
|
52
154
|
//# sourceMappingURL=sdk-errors.js.map
|
|
@@ -61,6 +61,20 @@ const MIN_CHAR_CLASSES = 2;
|
|
|
61
61
|
* still catches the rare long digit-free secret.
|
|
62
62
|
*/
|
|
63
63
|
const HIGH_ENTROPY_NO_DIGIT_MIN_LEN = 40;
|
|
64
|
+
/**
|
|
65
|
+
* Canonical aex run-id hex: exactly 32 lowercase hex chars directly preceded
|
|
66
|
+
* by `run_`. The HIGH_ENTROPY_CANDIDATE class excludes `_`, so the candidate
|
|
67
|
+
* run for a run id is the bare hex — dense enough to trip the entropy gate.
|
|
68
|
+
* Masking it destroys the ONE identifier every error message needs for
|
|
69
|
+
* traceability (`cancel via openSession("run_[REDACTED]")` is useless
|
|
70
|
+
* guidance). A run id is not a credential: it grants nothing without the
|
|
71
|
+
* bearer token. Mirrors the platform-side redactor's canonical-id exemption.
|
|
72
|
+
*/
|
|
73
|
+
function isCanonicalRunIdHex(input, matchStart, match) {
|
|
74
|
+
if (!/^[0-9a-f]{32}$/.test(match))
|
|
75
|
+
return false;
|
|
76
|
+
return input.slice(Math.max(0, matchStart - 4), matchStart) === "run_";
|
|
77
|
+
}
|
|
64
78
|
export class SecretString {
|
|
65
79
|
#value;
|
|
66
80
|
constructor(value, label = "secret") {
|
|
@@ -119,7 +133,7 @@ export function redactString(input, known = []) {
|
|
|
119
133
|
// Patterns with a captured prefix (Authorization header) keep the
|
|
120
134
|
// prefix; the rest replace the whole match.
|
|
121
135
|
typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED), out);
|
|
122
|
-
return out.replace(HIGH_ENTROPY_CANDIDATE, (match) => looksHighEntropySecret(match) ? REDACTED : match);
|
|
136
|
+
return out.replace(HIGH_ENTROPY_CANDIDATE, (match, offset, whole) => !isCanonicalRunIdHex(whole, offset, match) && looksHighEntropySecret(match) ? REDACTED : match);
|
|
123
137
|
}
|
|
124
138
|
export function containsSecretLikeValue(input) {
|
|
125
139
|
if (SECRET_PATTERNS.some((pattern) => {
|
|
@@ -131,6 +145,9 @@ export function containsSecretLikeValue(input) {
|
|
|
131
145
|
HIGH_ENTROPY_CANDIDATE.lastIndex = 0;
|
|
132
146
|
let candidate;
|
|
133
147
|
while ((candidate = HIGH_ENTROPY_CANDIDATE.exec(input)) !== null) {
|
|
148
|
+
if (isCanonicalRunIdHex(input, candidate.index, candidate[0])) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
134
151
|
if (looksHighEntropySecret(candidate[0])) {
|
|
135
152
|
return true;
|
|
136
153
|
}
|
|
@@ -2,15 +2,15 @@ import type { RunProvider } from "./submission.js";
|
|
|
2
2
|
export declare const SIDE_EFFECT_AUDIT_SCHEMA_VERSION = 1;
|
|
3
3
|
export declare const SIDE_EFFECT_AUDIT_REDACTION_SCANNER_VERSION = 1;
|
|
4
4
|
export declare const SIDE_EFFECT_AUDIT_KIND = "aex.side_effect_audit.v1";
|
|
5
|
-
export declare const SIDE_EFFECT_AUDIT_ACTIONS: readonly ["run.submit.accepted", "run.submit.rejected", "run.cancel.requested", "run.delete.requested", "run.delete.completed", "run.delete.failed", "run.download.requested", "run.output.downloaded", "run.log.downloaded", "run.event.downloaded", "workspace.asset.uploaded", "workspace.asset.deleted", "proxy.endpoint.called", "mcp.credential.accessed", "mcp.proxy.called", "provider.proxy.called", "custody.manifest.written", "custody.transition.recorded", "runtime.cleanup.completed", "runtime.cleanup.failed", "terminal_redrive.attempted", "terminal_redrive.completed", "
|
|
5
|
+
export declare const SIDE_EFFECT_AUDIT_ACTIONS: readonly ["run.submit.accepted", "run.submit.rejected", "run.cancel.requested", "run.delete.requested", "run.delete.completed", "run.delete.failed", "run.download.requested", "run.output.downloaded", "run.log.downloaded", "run.event.downloaded", "workspace.asset.uploaded", "workspace.asset.deleted", "proxy.endpoint.called", "mcp.credential.accessed", "mcp.proxy.called", "provider.proxy.called", "custody.manifest.written", "custody.transition.recorded", "runtime.cleanup.completed", "runtime.cleanup.failed", "terminal_redrive.attempted", "terminal_redrive.completed", "api_key.created", "api_key.deleted", "api_key.used"];
|
|
6
6
|
export type SideEffectAuditAction = (typeof SIDE_EFFECT_AUDIT_ACTIONS)[number];
|
|
7
|
-
export declare const SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES: readonly ["user", "
|
|
7
|
+
export declare const SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES: readonly ["user", "api_key", "system", "runtime"];
|
|
8
8
|
export type SideEffectAuditActorPrincipalType = (typeof SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES)[number];
|
|
9
9
|
export declare const SIDE_EFFECT_AUDIT_SOURCE_PLANES: readonly ["dashboard", "api", "runtime", "system"];
|
|
10
10
|
export type SideEffectAuditSourcePlane = (typeof SIDE_EFFECT_AUDIT_SOURCE_PLANES)[number];
|
|
11
|
-
export declare const SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS: readonly ["dashboard_auth", "
|
|
11
|
+
export declare const SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS: readonly ["dashboard_auth", "api_key", "runner_token", "system"];
|
|
12
12
|
export type SideEffectAuditAuthenticationKind = (typeof SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS)[number];
|
|
13
|
-
export declare const SIDE_EFFECT_AUDIT_TARGET_TYPES: readonly ["workspace", "run", "proxy_endpoint", "mcp_credential", "mcp_proxy", "provider_proxy", "output_archive", "run_output", "run_log", "run_event_stream", "workspace_asset", "custody_manifest", "custody_transition", "cleanup", "deletion", "terminal_redrive", "
|
|
13
|
+
export declare const SIDE_EFFECT_AUDIT_TARGET_TYPES: readonly ["workspace", "run", "proxy_endpoint", "mcp_credential", "mcp_proxy", "provider_proxy", "output_archive", "run_output", "run_log", "run_event_stream", "workspace_asset", "custody_manifest", "custody_transition", "cleanup", "deletion", "terminal_redrive", "api_key"];
|
|
14
14
|
export type SideEffectAuditTargetType = (typeof SIDE_EFFECT_AUDIT_TARGET_TYPES)[number];
|
|
15
15
|
export declare const SIDE_EFFECT_AUDIT_OUTCOMES: readonly ["accepted", "rejected", "succeeded", "failed", "denied", "canceled", "pending"];
|
|
16
16
|
export type SideEffectAuditOutcome = (typeof SIDE_EFFECT_AUDIT_OUTCOMES)[number];
|
|
@@ -24,13 +24,13 @@ export const SIDE_EFFECT_AUDIT_ACTIONS = [
|
|
|
24
24
|
"runtime.cleanup.failed",
|
|
25
25
|
"terminal_redrive.attempted",
|
|
26
26
|
"terminal_redrive.completed",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
27
|
+
"api_key.created",
|
|
28
|
+
"api_key.deleted",
|
|
29
|
+
"api_key.used"
|
|
30
30
|
];
|
|
31
31
|
export const SIDE_EFFECT_AUDIT_ACTOR_PRINCIPAL_TYPES = [
|
|
32
32
|
"user",
|
|
33
|
-
"
|
|
33
|
+
"api_key",
|
|
34
34
|
"system",
|
|
35
35
|
"runtime"
|
|
36
36
|
];
|
|
@@ -42,7 +42,7 @@ export const SIDE_EFFECT_AUDIT_SOURCE_PLANES = [
|
|
|
42
42
|
];
|
|
43
43
|
export const SIDE_EFFECT_AUDIT_AUTHENTICATION_KINDS = [
|
|
44
44
|
"dashboard_auth",
|
|
45
|
-
"
|
|
45
|
+
"api_key",
|
|
46
46
|
"runner_token",
|
|
47
47
|
"system"
|
|
48
48
|
];
|
|
@@ -63,7 +63,7 @@ export const SIDE_EFFECT_AUDIT_TARGET_TYPES = [
|
|
|
63
63
|
"cleanup",
|
|
64
64
|
"deletion",
|
|
65
65
|
"terminal_redrive",
|
|
66
|
-
"
|
|
66
|
+
"api_key"
|
|
67
67
|
];
|
|
68
68
|
export const SIDE_EFFECT_AUDIT_OUTCOMES = [
|
|
69
69
|
"accepted",
|
|
@@ -397,7 +397,7 @@ export interface RunMachine {
|
|
|
397
397
|
/**
|
|
398
398
|
* Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
|
|
399
399
|
* design** — token-authenticated clients never name the workspace
|
|
400
|
-
* because it is derived from their API
|
|
400
|
+
* because it is derived from their API key on the server. The BFF
|
|
401
401
|
* route resolves the workspace from the token and injects it before
|
|
402
402
|
* calling the parser. The dashboard UI (Auth.js user principal,
|
|
403
403
|
* multi-workspace) is the only caller that supplies `workspaceId`
|
package/dist/asset-upload.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* 3. POST /assets/finalize → confirms the object exists (HEAD only).
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
|
+
import { extractErrorCode, redactUrl } from "./_contracts/index.js";
|
|
22
23
|
const DIRECT_UPLOAD_MAX_ATTEMPTS = 3;
|
|
23
24
|
/**
|
|
24
25
|
* Upload `bytes` to the hosted API's content-addressable asset store via the
|
|
@@ -37,17 +38,13 @@ export async function uploadAsset(args) {
|
|
|
37
38
|
}
|
|
38
39
|
const contentHashHeader = `sha256:${actual}`;
|
|
39
40
|
// ---- Step 1: presign (control plane) ----
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
throw err;
|
|
50
|
-
}
|
|
41
|
+
// A network failure here surfaces as the transport's AexNetworkError,
|
|
42
|
+
// which already names the method, host, path, and transport code.
|
|
43
|
+
const presign = await args.http.request("/assets/presign", {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "content-type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ hash: contentHashHeader, sizeBytes: args.bytes.byteLength })
|
|
47
|
+
});
|
|
51
48
|
// Dedup hit — identical bytes already vaulted under this workspace.
|
|
52
49
|
if (presign.exists) {
|
|
53
50
|
const contentHash = presign.contentHash ?? contentHashHeader;
|
|
@@ -164,26 +161,9 @@ function errorMessage(err) {
|
|
|
164
161
|
return err;
|
|
165
162
|
return String(err);
|
|
166
163
|
}
|
|
167
|
-
function extractErrorCode(err) {
|
|
168
|
-
const code = stringProperty(err, "code");
|
|
169
|
-
if (code)
|
|
170
|
-
return code;
|
|
171
|
-
const cause = objectProperty(err, "cause");
|
|
172
|
-
const causeCode = stringProperty(cause, "code");
|
|
173
|
-
if (causeCode)
|
|
174
|
-
return causeCode;
|
|
175
|
-
const match = /\bE[A-Z0-9_]+\b/.exec(errorMessage(err));
|
|
176
|
-
return match?.[0];
|
|
177
|
-
}
|
|
178
164
|
function isNamedError(err, name) {
|
|
179
165
|
return stringProperty(err, "name") === name;
|
|
180
166
|
}
|
|
181
|
-
function objectProperty(value, key) {
|
|
182
|
-
if (!value || typeof value !== "object")
|
|
183
|
-
return undefined;
|
|
184
|
-
const prop = value[key];
|
|
185
|
-
return prop && typeof prop === "object" ? prop : undefined;
|
|
186
|
-
}
|
|
187
167
|
function stringProperty(value, key) {
|
|
188
168
|
if (!value || typeof value !== "object")
|
|
189
169
|
return undefined;
|
|
@@ -201,19 +181,6 @@ function redactUrlPreservingTrailingPunctuation(raw) {
|
|
|
201
181
|
const candidate = trailing ? raw.slice(0, -trailing.length) : raw;
|
|
202
182
|
return `${redactUrl(candidate)}${trailing}`;
|
|
203
183
|
}
|
|
204
|
-
function redactUrl(url) {
|
|
205
|
-
try {
|
|
206
|
-
const parsed = new URL(url);
|
|
207
|
-
const auth = parsed.username || parsed.password ? "[redacted]@" : "";
|
|
208
|
-
const query = parsed.search ? "?[redacted]" : "";
|
|
209
|
-
return `${parsed.protocol}//${auth}${parsed.host}${parsed.pathname}${query}`;
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
const withoutAuth = url.replace(/\/\/[^/?#\s]+@/, "//[redacted]@");
|
|
213
|
-
const queryStart = withoutAuth.indexOf("?");
|
|
214
|
-
return queryStart === -1 ? withoutAuth : `${withoutAuth.slice(0, queryStart)}?[redacted]`;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
184
|
function bufferToHex(buffer) {
|
|
218
185
|
const view = new Uint8Array(buffer);
|
|
219
186
|
let out = "";
|
package/dist/asset-upload.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-upload.js","sourceRoot":"","sources":["../src/asset-upload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"asset-upload.js","sourceRoot":"","sources":["../src/asset-upload.ts"],"names":[],"mappings":"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"}
|