run402 1.45.0 → 1.47.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/cli.mjs +6 -10
- package/lib/blob.mjs +60 -5
- package/lib/cdn.mjs +130 -0
- package/package.json +1 -1
- package/sdk/dist/namespaces/blobs.d.ts +41 -1
- package/sdk/dist/namespaces/blobs.d.ts.map +1 -1
- package/sdk/dist/namespaces/blobs.js +254 -3
- package/sdk/dist/namespaces/blobs.js.map +1 -1
- package/sdk/dist/namespaces/blobs.types.d.ts +226 -2
- package/sdk/dist/namespaces/blobs.types.d.ts.map +1 -1
- package/lib/storage.mjs +0 -125
package/cli.mjs
CHANGED
|
@@ -28,9 +28,9 @@ Commands:
|
|
|
28
28
|
deploy Deploy a full-stack app or static site (requires active tier)
|
|
29
29
|
functions Manage serverless functions (deploy, invoke, logs, list, delete)
|
|
30
30
|
secrets Manage project secrets (set, list, delete)
|
|
31
|
-
blob Direct-to-S3 blob storage (put, get, ls, rm, sign) — up to 5 TiB
|
|
32
|
-
storage Legacy file storage (deprecated — sunset 2026-06-01, use 'blob')
|
|
31
|
+
blob Direct-to-S3 blob storage (put, get, ls, rm, sign, diagnose) — up to 5 TiB
|
|
33
32
|
sites Deploy static sites
|
|
33
|
+
cdn CloudFront CDN diagnostics (wait-fresh) for public blob URLs
|
|
34
34
|
subdomains Manage custom subdomains (claim, list, delete)
|
|
35
35
|
domains Manage custom domains (add, list, status, delete)
|
|
36
36
|
apps Browse and manage the app marketplace
|
|
@@ -115,17 +115,13 @@ switch (cmd) {
|
|
|
115
115
|
await run(sub, rest);
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
|
-
case "
|
|
119
|
-
|
|
120
|
-
"run402 storage is deprecated — sunset 2026-06-01. Use `run402 blob` instead.\n" +
|
|
121
|
-
"See https://run402.com/docs/blob#migration\n\n",
|
|
122
|
-
);
|
|
123
|
-
const { run } = await import("./lib/storage.mjs");
|
|
118
|
+
case "blob": {
|
|
119
|
+
const { run } = await import("./lib/blob.mjs");
|
|
124
120
|
await run(sub, rest);
|
|
125
121
|
break;
|
|
126
122
|
}
|
|
127
|
-
case "
|
|
128
|
-
const { run } = await import("./lib/
|
|
123
|
+
case "cdn": {
|
|
124
|
+
const { run } = await import("./lib/cdn.mjs");
|
|
129
125
|
await run(sub, rest);
|
|
130
126
|
break;
|
|
131
127
|
}
|
package/lib/blob.mjs
CHANGED
|
@@ -46,6 +46,7 @@ Usage:
|
|
|
46
46
|
run402 blob ls [options]
|
|
47
47
|
run402 blob rm <key> [options]
|
|
48
48
|
run402 blob sign <key> [options]
|
|
49
|
+
run402 blob diagnose <url> [options]
|
|
49
50
|
|
|
50
51
|
Options:
|
|
51
52
|
--project <id> Project ID (defaults to active project from 'run402 projects use')
|
|
@@ -150,6 +151,32 @@ Options:
|
|
|
150
151
|
|
|
151
152
|
Examples:
|
|
152
153
|
run402 blob sign reports/2025-q4.pdf --project abc123 --ttl 600
|
|
154
|
+
`,
|
|
155
|
+
diagnose: `run402 blob diagnose — Inspect the live CDN state for a public blob URL
|
|
156
|
+
|
|
157
|
+
Usage:
|
|
158
|
+
run402 blob diagnose <url> [options]
|
|
159
|
+
|
|
160
|
+
Arguments:
|
|
161
|
+
<url> Full blob URL (e.g. https://app.run402.com/_blob/avatar.png)
|
|
162
|
+
|
|
163
|
+
Options:
|
|
164
|
+
--project <id> Project ID (defaults to active project)
|
|
165
|
+
|
|
166
|
+
Output:
|
|
167
|
+
- Prints the JSON envelope on stdout (parseable by agent shell loops).
|
|
168
|
+
- Vantage caveat ("# probed once from gateway-us-east-1; not a global view")
|
|
169
|
+
on stderr — visible to TTY operators, ignored by piped consumers.
|
|
170
|
+
|
|
171
|
+
Exit codes:
|
|
172
|
+
0 observed SHA matches the gateway's expected SHA
|
|
173
|
+
1 observed SHA does not match (or probe returned no SHA)
|
|
174
|
+
|
|
175
|
+
Agent loop pattern:
|
|
176
|
+
until run402 blob diagnose <url>; do sleep 1; done
|
|
177
|
+
|
|
178
|
+
Examples:
|
|
179
|
+
run402 blob diagnose https://app.run402.com/_blob/avatar.png
|
|
153
180
|
`,
|
|
154
181
|
};
|
|
155
182
|
|
|
@@ -445,6 +472,33 @@ async function rm(projectId, argv) {
|
|
|
445
472
|
// sign
|
|
446
473
|
// ---------------------------------------------------------------------------
|
|
447
474
|
|
|
475
|
+
async function diagnose(projectId, argv) {
|
|
476
|
+
const opts = parseArgs(argv);
|
|
477
|
+
opts.project = opts.project || projectId;
|
|
478
|
+
const resolvedId = resolveProjectId(opts.project);
|
|
479
|
+
if (opts.positional.length === 0) die("URL required");
|
|
480
|
+
const url = opts.positional[0];
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const env = await getSdk().blobs.diagnoseUrl(resolvedId, url);
|
|
484
|
+
// Always print the JSON envelope for agent consumption (parseable).
|
|
485
|
+
console.log(JSON.stringify(env, null, 2));
|
|
486
|
+
// Vantage caveat to stderr so a TTY operator sees it; agent shell loops
|
|
487
|
+
// that pipe stdout into another tool aren't affected.
|
|
488
|
+
process.stderr.write(
|
|
489
|
+
`\n# probed once from ${env.vantage}; not a global view\n`,
|
|
490
|
+
);
|
|
491
|
+
// Exit code: 0 if observed === expected, 1 otherwise. Lets agents
|
|
492
|
+
// shell-script `until run402 blob diagnose <url>; do sleep 1; done`.
|
|
493
|
+
if (env.observedSha256 && env.observedSha256 === env.expectedSha256) {
|
|
494
|
+
process.exit(0);
|
|
495
|
+
}
|
|
496
|
+
process.exit(1);
|
|
497
|
+
} catch (err) {
|
|
498
|
+
reportSdkError(err);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
448
502
|
async function sign(projectId, argv) {
|
|
449
503
|
const opts = parseArgs(argv);
|
|
450
504
|
opts.project = opts.project || projectId;
|
|
@@ -518,11 +572,12 @@ export async function run(sub, args) {
|
|
|
518
572
|
}
|
|
519
573
|
const defaultProject = process.env.RUN402_PROJECT ?? null;
|
|
520
574
|
switch (sub) {
|
|
521
|
-
case "put":
|
|
522
|
-
case "get":
|
|
523
|
-
case "ls":
|
|
524
|
-
case "rm":
|
|
525
|
-
case "sign":
|
|
575
|
+
case "put": await put(defaultProject, args); break;
|
|
576
|
+
case "get": await get(defaultProject, args); break;
|
|
577
|
+
case "ls": await ls(defaultProject, args); break;
|
|
578
|
+
case "rm": await rm(defaultProject, args); break;
|
|
579
|
+
case "sign": await sign(defaultProject, args); break;
|
|
580
|
+
case "diagnose": await diagnose(defaultProject, args); break;
|
|
526
581
|
default:
|
|
527
582
|
console.error(`Unknown subcommand: ${sub}`);
|
|
528
583
|
console.log(HELP);
|
package/lib/cdn.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run402 cdn — CloudFront CDN diagnostics for public blob URLs.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* run402 cdn wait-fresh <url> --sha <sha256> [--timeout <seconds>] [--project <id>]
|
|
6
|
+
*
|
|
7
|
+
* Wraps the SDK's `client.blobs.waitFresh(...)`. Polls the gateway diagnose
|
|
8
|
+
* endpoint until the URL serves the expected SHA, then exits 0. On timeout,
|
|
9
|
+
* exits 1 (agent shell loops can chain a fallback action).
|
|
10
|
+
*
|
|
11
|
+
* **Mutable URLs only.** For immutable URLs (the `immutableUrl` field
|
|
12
|
+
* returned by `run402 blob put --immutable`), no waiting is needed — they
|
|
13
|
+
* are bound to a SHA at upload time and never previously cached.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { resolveProjectId } from "./config.mjs";
|
|
17
|
+
import { getSdk } from "./sdk.mjs";
|
|
18
|
+
import { reportSdkError } from "./sdk-errors.mjs";
|
|
19
|
+
|
|
20
|
+
const HELP = `run402 cdn — CloudFront CDN diagnostics for public blob URLs
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
run402 cdn wait-fresh <url> --sha <sha256> [options]
|
|
24
|
+
|
|
25
|
+
Subcommands:
|
|
26
|
+
wait-fresh Poll the CDN until a mutable URL serves the expected SHA-256
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
run402 cdn wait-fresh https://app.run402.com/_blob/avatar.png --sha abc...
|
|
30
|
+
|
|
31
|
+
For details: run402 cdn wait-fresh --help
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const SUB_HELP = {
|
|
35
|
+
"wait-fresh": `run402 cdn wait-fresh — Poll the CDN for an expected SHA on a mutable URL
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
run402 cdn wait-fresh <url> --sha <sha256> [options]
|
|
39
|
+
|
|
40
|
+
Arguments:
|
|
41
|
+
<url> Full mutable blob URL to poll (e.g.
|
|
42
|
+
https://app.run402.com/_blob/avatar.png)
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--sha <hex> Expected hex SHA-256. Required.
|
|
46
|
+
--timeout <secs> Max wait in seconds. Default 60.
|
|
47
|
+
--project <id> Project ID (defaults to active project)
|
|
48
|
+
|
|
49
|
+
Output:
|
|
50
|
+
Prints a JSON result on stdout when polling ends:
|
|
51
|
+
{ "fresh": true|false, "observedSha256": "...", "attempts": N,
|
|
52
|
+
"elapsedMs": ..., "vantage": "gateway-us-east-1" }
|
|
53
|
+
|
|
54
|
+
Exit codes:
|
|
55
|
+
0 the URL served the expected SHA before the timeout
|
|
56
|
+
1 the URL did NOT match within the timeout (or the project resolution failed)
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
- For IMMUTABLE URLs (returned as 'immutableUrl' from 'run402 blob put
|
|
60
|
+
--immutable'), no waiting is needed. Use this command only for the
|
|
61
|
+
mutable 'url' field, after a re-upload to an existing public key.
|
|
62
|
+
- The probe is single-vantage (us-east-1). Other CloudFront PoPs may
|
|
63
|
+
serve different cached states until invalidation propagates.
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
run402 cdn wait-fresh https://app.run402.com/_blob/avatar.png --sha ba78...
|
|
67
|
+
run402 cdn wait-fresh https://app.run402.com/_blob/avatar.png --sha ba78... --timeout 120
|
|
68
|
+
`,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
function die(msg, code = 1) {
|
|
72
|
+
console.error(JSON.stringify({ status: "error", message: msg }));
|
|
73
|
+
process.exit(code);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseArgs(args) {
|
|
77
|
+
const opts = { positional: [] };
|
|
78
|
+
for (let i = 0; i < args.length; i++) {
|
|
79
|
+
const a = args[i];
|
|
80
|
+
if (a === "--sha") opts.sha = args[++i];
|
|
81
|
+
else if (a === "--timeout") opts.timeout = Number(args[++i]);
|
|
82
|
+
else if (a === "--project") opts.project = args[++i];
|
|
83
|
+
else if (a.startsWith("--")) die(`Unknown option: ${a}`);
|
|
84
|
+
else opts.positional.push(a);
|
|
85
|
+
}
|
|
86
|
+
return opts;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function waitFresh(projectId, argv) {
|
|
90
|
+
const opts = parseArgs(argv);
|
|
91
|
+
opts.project = opts.project || projectId;
|
|
92
|
+
const resolvedId = resolveProjectId(opts.project);
|
|
93
|
+
if (opts.positional.length === 0) die("URL required");
|
|
94
|
+
const url = opts.positional[0];
|
|
95
|
+
if (!opts.sha) die("--sha is required");
|
|
96
|
+
|
|
97
|
+
const timeoutMs = (opts.timeout ?? 60) * 1000;
|
|
98
|
+
try {
|
|
99
|
+
const result = await getSdk().blobs.waitFresh(resolvedId, {
|
|
100
|
+
url,
|
|
101
|
+
sha256: opts.sha.toLowerCase(),
|
|
102
|
+
timeoutMs,
|
|
103
|
+
});
|
|
104
|
+
console.log(JSON.stringify(result, null, 2));
|
|
105
|
+
process.exit(result.fresh ? 0 : 1);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
reportSdkError(err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export async function run(sub, args) {
|
|
112
|
+
if (!sub || sub === "--help" || sub === "-h") {
|
|
113
|
+
console.log(HELP);
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
|
|
117
|
+
console.log(SUB_HELP[sub] || HELP);
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
const defaultProject = process.env.RUN402_PROJECT ?? null;
|
|
121
|
+
switch (sub) {
|
|
122
|
+
case "wait-fresh":
|
|
123
|
+
await waitFresh(defaultProject, args);
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
console.error(`Unknown subcommand: ${sub}`);
|
|
127
|
+
console.log(HELP);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* configured fetch still flows through any wrappers (e.g. test mocks).
|
|
8
8
|
*/
|
|
9
9
|
import type { Client } from "../kernel.js";
|
|
10
|
-
import type { BlobLsOptions, BlobLsResult, BlobPutOptions, BlobPutResult, BlobPutSource, BlobSignOptions, BlobSignResult } from "./blobs.types.js";
|
|
10
|
+
import type { BlobDiagnoseEnvelope, BlobLsOptions, BlobLsResult, BlobPutOptions, BlobPutResult, BlobPutSource, BlobSignOptions, BlobSignResult, BlobWaitFreshOptions, BlobWaitFreshResult } from "./blobs.types.js";
|
|
11
11
|
export declare class Blobs {
|
|
12
12
|
private readonly client;
|
|
13
13
|
constructor(client: Client);
|
|
@@ -22,6 +22,46 @@ export declare class Blobs {
|
|
|
22
22
|
* @throws {ProjectNotFound} if `projectId` is not in the provider.
|
|
23
23
|
*/
|
|
24
24
|
put(projectId: string, key: string, source: BlobPutSource, opts?: BlobPutOptions): Promise<BlobPutResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Diagnose a public blob URL. Returns a JSON envelope describing the live
|
|
27
|
+
* CDN state (expected vs observed SHA, cache headers, recent invalidation
|
|
28
|
+
* status, vantage). The gateway probes the URL once from us-east-1 with
|
|
29
|
+
* `Range: bytes=0-0` and returns within 5 s even if the inner probe is
|
|
30
|
+
* slow.
|
|
31
|
+
*
|
|
32
|
+
* **Vantage caveat:** the result reflects ONE CloudFront PoP at the time
|
|
33
|
+
* of the call. Other PoPs may serve different cached states. The
|
|
34
|
+
* `probeMayHaveWarmedCache: true` field reminds the agent that the probe
|
|
35
|
+
* itself populates the cache, so a subsequent read may differ.
|
|
36
|
+
*
|
|
37
|
+
* The URL must belong to the requesting project — cross-project URLs are
|
|
38
|
+
* rejected by the gateway with `403`. SSRF is enforced gateway-side: only
|
|
39
|
+
* `*.run402.com` and the project's active custom domains are accepted.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const diag = await client.blobs.diagnoseUrl("prj_abc", "https://app.run402.com/_blob/avatar.png");
|
|
43
|
+
* if (diag.observedSha256 !== diag.expectedSha256) console.log(diag.hint);
|
|
44
|
+
*/
|
|
45
|
+
diagnoseUrl(projectId: string, url: string): Promise<BlobDiagnoseEnvelope>;
|
|
46
|
+
/**
|
|
47
|
+
* Poll the CDN until a mutable URL serves the expected SHA-256, or the
|
|
48
|
+
* timeout elapses. **For mutable URLs only** — for immutable URLs (the
|
|
49
|
+
* `immutableUrl` returned by `put`) no waiting is needed; they're bound
|
|
50
|
+
* at upload time and never previously cached.
|
|
51
|
+
*
|
|
52
|
+
* Default `timeoutMs` is 60_000 (60 s). The helper polls the gateway's
|
|
53
|
+
* diagnose endpoint with exponential backoff bounded by 1 s; each poll
|
|
54
|
+
* may itself warm the cache for the probed PoP, so subsequent reads from
|
|
55
|
+
* other PoPs may still be stale until invalidation propagation completes.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* await client.blobs.waitFresh("prj_abc", {
|
|
59
|
+
* url: result.url, // the mutable URL from blobs.put
|
|
60
|
+
* sha256: result.contentSha256,
|
|
61
|
+
* timeoutMs: 30_000,
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
64
|
+
waitFresh(projectId: string, opts: BlobWaitFreshOptions): Promise<BlobWaitFreshResult>;
|
|
25
65
|
/**
|
|
26
66
|
* Download a blob. Returns the raw `Response` so callers can stream to
|
|
27
67
|
* disk, pipe to another sink, or buffer with `.bytes()` / `.arrayBuffer()`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../../src/namespaces/blobs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../../src/namespaces/blobs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAGV,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAsO1B,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;;;;;;OASG;IACG,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,aAAa,CAAC;IA2FzB;;;;;;;;;;;;;;;;;;;OAmBG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAchF;;;;;;;;;;;;;;;;;OAiBG;IACG,SAAS,CACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC;IA2C/B;;;;;;;OAOG;IACG,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAuB5D,oDAAoD;IAC9C,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAoB5E,+DAA+D;IACzD,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcvD,6FAA6F;IACvF,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;CAoBhG"}
|
|
@@ -40,6 +40,152 @@ async function sha256Hex(bytes) {
|
|
|
40
40
|
.map((b) => b.toString(16).padStart(2, "0"))
|
|
41
41
|
.join("");
|
|
42
42
|
}
|
|
43
|
+
function escapeHtmlAttr(s) {
|
|
44
|
+
return s
|
|
45
|
+
.replace(/&/g, "&")
|
|
46
|
+
.replace(/"/g, """)
|
|
47
|
+
.replace(/</g, "<")
|
|
48
|
+
.replace(/>/g, ">");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert hex (e.g. `"abcd…"`) to base64 in environments that have either
|
|
52
|
+
* Buffer (Node) or `btoa` (browsers). The helper is here because Browser SDK
|
|
53
|
+
* builds may run without `Buffer`.
|
|
54
|
+
*/
|
|
55
|
+
function hexToBase64(hex) {
|
|
56
|
+
const len = hex.length;
|
|
57
|
+
const bytes = new Uint8Array(len / 2);
|
|
58
|
+
for (let i = 0; i < len; i += 2) {
|
|
59
|
+
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
60
|
+
}
|
|
61
|
+
// Prefer Buffer when available (faster on Node).
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
const g = globalThis;
|
|
64
|
+
if (g.Buffer)
|
|
65
|
+
return g.Buffer.from(bytes).toString("base64");
|
|
66
|
+
let s = "";
|
|
67
|
+
for (const b of bytes)
|
|
68
|
+
s += String.fromCharCode(b);
|
|
69
|
+
return g.btoa ? g.btoa(s) : "";
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Widen the gateway's snake_case completion response into the AssetRef
|
|
73
|
+
* shape (which adds camelCase aliases + locally-derived integrity fields
|
|
74
|
+
* for any URL the consumer is about to embed in code). For non-immutable
|
|
75
|
+
* uploads where the SHA is null, the integrity fields are null and the
|
|
76
|
+
* agent guidance steers them to use `--immutable` before linking.
|
|
77
|
+
*/
|
|
78
|
+
function buildAssetRef(resp, contentType) {
|
|
79
|
+
const sha = resp.sha256;
|
|
80
|
+
const immutable = !!resp.immutable_url;
|
|
81
|
+
const cacheKind = resp.visibility === "private"
|
|
82
|
+
? "private"
|
|
83
|
+
: immutable
|
|
84
|
+
? "immutable"
|
|
85
|
+
: "mutable";
|
|
86
|
+
const etag = sha ? `"sha256-${sha}"` : null;
|
|
87
|
+
const sri = sha ? `sha256-${hexToBase64(sha)}` : null;
|
|
88
|
+
const contentDigest = sha ? `sha-256=:${hexToBase64(sha)}:` : null;
|
|
89
|
+
// v1.45 agent-DX URLs — guaranteed CDN-reachable on the auto-subdomain.
|
|
90
|
+
// Older gateway versions don't emit them; null in that case (callers fall
|
|
91
|
+
// back to the preferred-host `url` / `immutableUrl`).
|
|
92
|
+
const cdnUrl = resp.cdn_immutable_url ?? null;
|
|
93
|
+
const cdnMutableUrl = resp.cdn_url ?? null;
|
|
94
|
+
// The cdn envelope: prefer what the gateway returns; fall back to
|
|
95
|
+
// best-effort defaults so older gateway versions don't break the SDK
|
|
96
|
+
// surface. immutable URLs are always-ready by definition.
|
|
97
|
+
const cdnFromGw = resp.cdn ?? {};
|
|
98
|
+
const cdn = {
|
|
99
|
+
version: cdnFromGw.version ?? "blob-gateway-v2",
|
|
100
|
+
invalidationId: cdnFromGw.invalidationId ?? null,
|
|
101
|
+
invalidationStatus: cdnFromGw.invalidationStatus ?? null,
|
|
102
|
+
ready: cdnFromGw.ready ?? immutable,
|
|
103
|
+
hint: cdnFromGw.hint ??
|
|
104
|
+
(immutable
|
|
105
|
+
? "Use cdnUrl + scriptTag()/linkTag()/imgTag() — paste-and-go."
|
|
106
|
+
: "For mutable URLs, propagation is asynchronous. Prefer cdnUrl (immutable, content-hashed) for generated HTML/CSS/JS, or call wait_for_cdn_freshness."),
|
|
107
|
+
};
|
|
108
|
+
// Emitter helpers. Throw with an actionable hint when the SHA is null
|
|
109
|
+
// (non-immutable upload) — the agent should re-upload with `immutable:
|
|
110
|
+
// true` to get content-hashed URLs that pair with SRI.
|
|
111
|
+
function requireImmutable(name) {
|
|
112
|
+
if (!cdnUrl || !sri) {
|
|
113
|
+
throw new Error(`${name}() requires an immutable upload (pass { immutable: true } to blobs.put). ` +
|
|
114
|
+
`Without immutable, there is no SHA to bind for SRI and the URL would change on re-upload.`);
|
|
115
|
+
}
|
|
116
|
+
return { url: cdnUrl, sri };
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
key: resp.key,
|
|
120
|
+
size_bytes: resp.size_bytes,
|
|
121
|
+
sha256: sha,
|
|
122
|
+
visibility: resp.visibility,
|
|
123
|
+
url: resp.url,
|
|
124
|
+
immutable_url: resp.immutable_url,
|
|
125
|
+
size: resp.size_bytes,
|
|
126
|
+
contentSha256: sha,
|
|
127
|
+
contentType,
|
|
128
|
+
immutableUrl: resp.immutable_url,
|
|
129
|
+
cdnUrl,
|
|
130
|
+
cdnMutableUrl,
|
|
131
|
+
etag,
|
|
132
|
+
sri,
|
|
133
|
+
contentDigest,
|
|
134
|
+
cacheKind,
|
|
135
|
+
cdn,
|
|
136
|
+
scriptTag(opts) {
|
|
137
|
+
// Default `defer: true` — modern best practice. Defer prevents
|
|
138
|
+
// render-blocking when placed in <head> and is a no-op when placed
|
|
139
|
+
// at the end of <body> (the script runs after DOMContentLoaded
|
|
140
|
+
// either way). Pass `{ defer: false }` to opt out for the rare
|
|
141
|
+
// case requiring synchronous execution. `async` and `defer` are
|
|
142
|
+
// mutually exclusive; passing async overrides defer.
|
|
143
|
+
const { url, sri } = requireImmutable("scriptTag");
|
|
144
|
+
const attrs = [`src="${escapeHtmlAttr(url)}"`];
|
|
145
|
+
if (opts?.type === "module")
|
|
146
|
+
attrs.push(`type="module"`);
|
|
147
|
+
const wantsAsync = opts?.async === true;
|
|
148
|
+
const wantsDefer = opts?.defer ?? !wantsAsync;
|
|
149
|
+
if (wantsAsync)
|
|
150
|
+
attrs.push("async");
|
|
151
|
+
else if (wantsDefer)
|
|
152
|
+
attrs.push("defer");
|
|
153
|
+
attrs.push(`integrity="${escapeHtmlAttr(sri)}"`);
|
|
154
|
+
attrs.push("crossorigin");
|
|
155
|
+
return `<script ${attrs.join(" ")}></script>`;
|
|
156
|
+
},
|
|
157
|
+
linkTag(opts) {
|
|
158
|
+
// Always emit crossorigin — required for SRI to actually be
|
|
159
|
+
// enforced. Without crossorigin the browser silently ignores the
|
|
160
|
+
// integrity attribute (HTML spec). This applies to rel="preload"
|
|
161
|
+
// too: matching crossorigin on the preload + the eventual fetch is
|
|
162
|
+
// what lets the browser dedupe instead of double-fetching.
|
|
163
|
+
const { url, sri } = requireImmutable("linkTag");
|
|
164
|
+
const rel = opts?.rel ?? "stylesheet";
|
|
165
|
+
const attrs = [`rel="${escapeHtmlAttr(rel)}"`];
|
|
166
|
+
attrs.push(`href="${escapeHtmlAttr(url)}"`);
|
|
167
|
+
if (opts?.as)
|
|
168
|
+
attrs.push(`as="${escapeHtmlAttr(opts.as)}"`);
|
|
169
|
+
attrs.push(`integrity="${escapeHtmlAttr(sri)}"`);
|
|
170
|
+
attrs.push("crossorigin");
|
|
171
|
+
return `<link ${attrs.join(" ")}>`;
|
|
172
|
+
},
|
|
173
|
+
imgTag(alt) {
|
|
174
|
+
// Defaults: loading="lazy" + decoding="async" — modern best
|
|
175
|
+
// practice. Lazy is harmless for above-fold images (browsers
|
|
176
|
+
// handle the heuristic) and a flat win for the much more common
|
|
177
|
+
// below-fold case. Async decoding moves the decode off the main
|
|
178
|
+
// thread. Both are baseline-supported in all major browsers.
|
|
179
|
+
// <img> doesn't accept SRI per HTML5; the URL is content-hashed
|
|
180
|
+
// so it's still stable across re-deploys. Agents who need
|
|
181
|
+
// byte-level integrity for images should verify Content-Digest
|
|
182
|
+
// server-side.
|
|
183
|
+
const { url } = requireImmutable("imgTag");
|
|
184
|
+
const a = alt ?? "";
|
|
185
|
+
return `<img src="${escapeHtmlAttr(url)}" alt="${escapeHtmlAttr(a)}" loading="lazy" decoding="async">`;
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
43
189
|
export class Blobs {
|
|
44
190
|
client;
|
|
45
191
|
constructor(client) {
|
|
@@ -71,7 +217,13 @@ export class Blobs {
|
|
|
71
217
|
throw new Error("`content` is limited to 1 MB. Use `bytes` for larger uploads.");
|
|
72
218
|
}
|
|
73
219
|
const contentType = opts.contentType ?? guessContentType(key);
|
|
74
|
-
|
|
220
|
+
// v1.45 default: `immutable: true`. The agent-DX surface (cdnUrl, sri,
|
|
221
|
+
// scriptTag/linkTag/imgTag) only works for content-addressed uploads,
|
|
222
|
+
// so the default reaches for the best path. Pass `{ immutable: false }`
|
|
223
|
+
// explicitly when you specifically want a non-content-hashed URL
|
|
224
|
+
// (e.g. very large file where you want to skip the SHA pass).
|
|
225
|
+
const immutable = opts.immutable ?? true;
|
|
226
|
+
const sha256 = immutable ? await sha256Hex(bytes) : undefined;
|
|
75
227
|
// 1. Init upload — gateway returns presigned S3 URLs for each part.
|
|
76
228
|
const init = await this.client.request("/storage/v1/uploads", {
|
|
77
229
|
method: "POST",
|
|
@@ -84,7 +236,7 @@ export class Blobs {
|
|
|
84
236
|
size_bytes: sizeBytes,
|
|
85
237
|
content_type: contentType,
|
|
86
238
|
visibility: opts.visibility ?? "public",
|
|
87
|
-
immutable
|
|
239
|
+
immutable,
|
|
88
240
|
sha256,
|
|
89
241
|
},
|
|
90
242
|
context: "initializing upload",
|
|
@@ -109,7 +261,7 @@ export class Blobs {
|
|
|
109
261
|
const completeBody = init.mode === "multipart"
|
|
110
262
|
? { parts: partEtags.map((e, i) => ({ part_number: i + 1, etag: `"${e.etag}"` })) }
|
|
111
263
|
: {};
|
|
112
|
-
|
|
264
|
+
const completion = await this.client.request(`/storage/v1/uploads/${init.upload_id}/complete`, {
|
|
113
265
|
method: "POST",
|
|
114
266
|
headers: {
|
|
115
267
|
apikey: project.anon_key,
|
|
@@ -118,6 +270,105 @@ export class Blobs {
|
|
|
118
270
|
body: completeBody,
|
|
119
271
|
context: "completing upload",
|
|
120
272
|
});
|
|
273
|
+
// Widen the gateway response into the v1.45 AssetRef return type. Older
|
|
274
|
+
// gateway versions don't emit the `cdn` envelope; `buildAssetRef` fills
|
|
275
|
+
// safe defaults derived from the SHA + visibility so the SDK surface is
|
|
276
|
+
// stable across gateway versions.
|
|
277
|
+
return buildAssetRef(completion, contentType);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Diagnose a public blob URL. Returns a JSON envelope describing the live
|
|
281
|
+
* CDN state (expected vs observed SHA, cache headers, recent invalidation
|
|
282
|
+
* status, vantage). The gateway probes the URL once from us-east-1 with
|
|
283
|
+
* `Range: bytes=0-0` and returns within 5 s even if the inner probe is
|
|
284
|
+
* slow.
|
|
285
|
+
*
|
|
286
|
+
* **Vantage caveat:** the result reflects ONE CloudFront PoP at the time
|
|
287
|
+
* of the call. Other PoPs may serve different cached states. The
|
|
288
|
+
* `probeMayHaveWarmedCache: true` field reminds the agent that the probe
|
|
289
|
+
* itself populates the cache, so a subsequent read may differ.
|
|
290
|
+
*
|
|
291
|
+
* The URL must belong to the requesting project — cross-project URLs are
|
|
292
|
+
* rejected by the gateway with `403`. SSRF is enforced gateway-side: only
|
|
293
|
+
* `*.run402.com` and the project's active custom domains are accepted.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* const diag = await client.blobs.diagnoseUrl("prj_abc", "https://app.run402.com/_blob/avatar.png");
|
|
297
|
+
* if (diag.observedSha256 !== diag.expectedSha256) console.log(diag.hint);
|
|
298
|
+
*/
|
|
299
|
+
async diagnoseUrl(projectId, url) {
|
|
300
|
+
const project = await this.client.getProject(projectId);
|
|
301
|
+
if (!project)
|
|
302
|
+
throw new ProjectNotFound(projectId, "diagnosing blob URL");
|
|
303
|
+
const path = `/storage/v1/blobs/diagnose?url=${encodeURIComponent(url)}`;
|
|
304
|
+
return this.client.request(path, {
|
|
305
|
+
headers: {
|
|
306
|
+
apikey: project.anon_key,
|
|
307
|
+
Authorization: `Bearer ${project.anon_key}`,
|
|
308
|
+
},
|
|
309
|
+
context: "diagnosing blob URL",
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Poll the CDN until a mutable URL serves the expected SHA-256, or the
|
|
314
|
+
* timeout elapses. **For mutable URLs only** — for immutable URLs (the
|
|
315
|
+
* `immutableUrl` returned by `put`) no waiting is needed; they're bound
|
|
316
|
+
* at upload time and never previously cached.
|
|
317
|
+
*
|
|
318
|
+
* Default `timeoutMs` is 60_000 (60 s). The helper polls the gateway's
|
|
319
|
+
* diagnose endpoint with exponential backoff bounded by 1 s; each poll
|
|
320
|
+
* may itself warm the cache for the probed PoP, so subsequent reads from
|
|
321
|
+
* other PoPs may still be stale until invalidation propagation completes.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* await client.blobs.waitFresh("prj_abc", {
|
|
325
|
+
* url: result.url, // the mutable URL from blobs.put
|
|
326
|
+
* sha256: result.contentSha256,
|
|
327
|
+
* timeoutMs: 30_000,
|
|
328
|
+
* });
|
|
329
|
+
*/
|
|
330
|
+
async waitFresh(projectId, opts) {
|
|
331
|
+
const project = await this.client.getProject(projectId);
|
|
332
|
+
if (!project)
|
|
333
|
+
throw new ProjectNotFound(projectId, "waiting for CDN freshness");
|
|
334
|
+
const expected = opts.sha256.toLowerCase();
|
|
335
|
+
const timeoutMs = opts.timeoutMs ?? 60_000;
|
|
336
|
+
const start = Date.now();
|
|
337
|
+
let attempts = 0;
|
|
338
|
+
let observed = null;
|
|
339
|
+
let delay = 100;
|
|
340
|
+
while (Date.now() - start < timeoutMs) {
|
|
341
|
+
attempts++;
|
|
342
|
+
try {
|
|
343
|
+
const envelope = await this.diagnoseUrl(projectId, opts.url);
|
|
344
|
+
observed = envelope.observedSha256;
|
|
345
|
+
if (observed && observed.toLowerCase() === expected) {
|
|
346
|
+
return {
|
|
347
|
+
fresh: true,
|
|
348
|
+
observedSha256: observed,
|
|
349
|
+
attempts,
|
|
350
|
+
elapsedMs: Date.now() - start,
|
|
351
|
+
vantage: "gateway-us-east-1",
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
// Swallow & retry — `diagnoseUrl` can fail on transient gateway
|
|
357
|
+
// hiccups (e.g. ALB cycling). The next poll re-attempts.
|
|
358
|
+
}
|
|
359
|
+
const remaining = timeoutMs - (Date.now() - start);
|
|
360
|
+
if (remaining <= 0)
|
|
361
|
+
break;
|
|
362
|
+
await new Promise((r) => setTimeout(r, Math.min(delay, remaining)));
|
|
363
|
+
delay = Math.min(delay * 2, 1000);
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
fresh: false,
|
|
367
|
+
observedSha256: observed,
|
|
368
|
+
attempts,
|
|
369
|
+
elapsedMs: Date.now() - start,
|
|
370
|
+
vantage: "gateway-us-east-1",
|
|
371
|
+
};
|
|
121
372
|
}
|
|
122
373
|
/**
|
|
123
374
|
* Download a blob. Returns the raw `Response` so callers can stream to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../../src/namespaces/blobs.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"blobs.js","sourceRoot":"","sources":["../../src/namespaces/blobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,16 +16,240 @@ export interface BlobPutOptions {
|
|
|
16
16
|
contentType?: string;
|
|
17
17
|
/** Default: `"public"`. Public blobs get a CDN URL; private requires auth. */
|
|
18
18
|
visibility?: BlobVisibility;
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Default (v1.45+): `true`. Returns an `AssetRef` with `cdnUrl` populated
|
|
21
|
+
* and the `scriptTag()` / `linkTag()` / `imgTag()` emitters working —
|
|
22
|
+
* this is the agent-DX flow (paste-and-go HTML with SRI baked in).
|
|
23
|
+
*
|
|
24
|
+
* Cost: one SHA-256 pass over the bytes on the client side. For small
|
|
25
|
+
* assets (the typical case — images, JS, CSS, fonts, JSON < 1 MB) it's
|
|
26
|
+
* a few ms dominated by network. Pass `false` to skip the SHA pass for
|
|
27
|
+
* very large uploads where you specifically don't need a content-hashed
|
|
28
|
+
* URL or SRI.
|
|
29
|
+
*
|
|
30
|
+
* When `false`, the returned `AssetRef` has `cdnUrl: null`, `sri: null`,
|
|
31
|
+
* and the tag emitters throw with an "immutable: true required" hint.
|
|
32
|
+
*/
|
|
20
33
|
immutable?: boolean;
|
|
21
34
|
}
|
|
22
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Cache-kind hint for a blob URL. Mirrors the gateway's
|
|
37
|
+
* `X-Run402-Blob-Cache-Kind` response header. Agents key on this when
|
|
38
|
+
* deciding whether they need to wait for CDN freshness after an upload.
|
|
39
|
+
*/
|
|
40
|
+
export type BlobCacheKind = "immutable" | "mutable" | "private";
|
|
41
|
+
/**
|
|
42
|
+
* CloudFront invalidation status for a mutable URL. Returned by the gateway's
|
|
43
|
+
* upload-completion response when an invalidation was triggered (e.g. a
|
|
44
|
+
* re-upload to an existing public mutable key). `ready: true` is the
|
|
45
|
+
* immutable-URL signal — no waiting needed.
|
|
46
|
+
*/
|
|
47
|
+
export interface BlobCdnEnvelope {
|
|
48
|
+
/** Blob CDN config version. Currently `"blob-gateway-v2"`. */
|
|
49
|
+
version: string;
|
|
50
|
+
/** CloudFront invalidation ID for the mutable URL, when one was triggered. */
|
|
51
|
+
invalidationId: string | null;
|
|
52
|
+
/** Status of the invalidation at the time of the upload response. */
|
|
53
|
+
invalidationStatus: "InProgress" | "Completed" | "Failed" | null;
|
|
54
|
+
/** `true` for immutable URLs (always ready); omitted/false for mutable. */
|
|
55
|
+
ready?: boolean;
|
|
56
|
+
/** Human-readable nudge ("Use immutableUrl or call wait_for_cdn_freshness."). */
|
|
57
|
+
hint: string | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Stable URL reference returned by `client.blobs.put`.
|
|
61
|
+
*
|
|
62
|
+
* **The recommended agent-DX fields are `cdnUrl` + the tag emitters
|
|
63
|
+
* (`scriptTag`, `linkTag`, `imgTag`).** These give you a paste-and-go HTML
|
|
64
|
+
* tag with content-addressed URL + SRI + `crossorigin` already wired. No
|
|
65
|
+
* decisions about mutable vs. immutable, no `wait_for_cdn_freshness` polls,
|
|
66
|
+
* no manual integrity attribute construction — the URL is bound to a SHA at
|
|
67
|
+
* upload time, served from `pr-<public_id>.run402.com` (the host that
|
|
68
|
+
* always works through the v1.33 CDN), and never invalidated.
|
|
69
|
+
*
|
|
70
|
+
* The other fields are present for compatibility / advanced use:
|
|
71
|
+
* - `url` / `immutable_url` (snake_case): legacy v1.0+ fields. May be on
|
|
72
|
+
* a claimed-subdomain or custom-domain host (which is "prettier" but
|
|
73
|
+
* currently can NOT serve `/_blob/*` through the CDN — those subdomains'
|
|
74
|
+
* KVS values lack a `project_id`. Fix tracked separately).
|
|
75
|
+
* - `immutableUrl`: same value as `immutable_url`, camelCase.
|
|
76
|
+
* - `cdnMutableUrl`: mutable form of the auto-subdomain URL — useful only
|
|
77
|
+
* when you need a stable URL that always reflects the latest content.
|
|
78
|
+
* Comes with eventual-consistency caveats (CloudFront invalidation is
|
|
79
|
+
* async); prefer `cdnUrl` for generated code.
|
|
80
|
+
* - `etag`, `sri`, `contentDigest`: integrity values derived from the
|
|
81
|
+
* SHA-256.
|
|
82
|
+
* - `cdn`: CloudFront invalidation envelope.
|
|
83
|
+
*
|
|
84
|
+
* Tag emitters require the SHA-256 (only computed when uploaded with
|
|
85
|
+
* `immutable: true`). On non-immutable uploads, calling them throws.
|
|
86
|
+
*/
|
|
87
|
+
export interface AssetRef {
|
|
23
88
|
key: string;
|
|
24
89
|
size_bytes: number;
|
|
25
90
|
sha256: string | null;
|
|
26
91
|
visibility: BlobVisibility;
|
|
27
92
|
url: string | null;
|
|
28
93
|
immutable_url: string | null;
|
|
94
|
+
/** Same value as `size_bytes`, camelCase form. */
|
|
95
|
+
size: number;
|
|
96
|
+
/** Hex SHA-256 of the bytes. Same as `sha256` (camelCase alias). */
|
|
97
|
+
contentSha256: string | null;
|
|
98
|
+
/** Effective Content-Type (auto-detected from the key extension when not
|
|
99
|
+
* set explicitly via `BlobPutOptions.contentType`). */
|
|
100
|
+
contentType: string;
|
|
101
|
+
/** Same value as `immutable_url` (preferred-host form), camelCase. */
|
|
102
|
+
immutableUrl: string | null;
|
|
103
|
+
/** **The recommended URL for generated HTML/CSS/JS.** Content-addressed
|
|
104
|
+
* (immutable), served from the auto-subdomain
|
|
105
|
+
* (`pr-<public_id>.run402.com/_blob/<key-with-suffix>.<ext>`) which is
|
|
106
|
+
* guaranteed to work through the v1.33 CDN path. Pair with `sri` for
|
|
107
|
+
* Subresource Integrity. Null on non-immutable uploads (the SHA isn't
|
|
108
|
+
* computed) and on private uploads. */
|
|
109
|
+
cdnUrl: string | null;
|
|
110
|
+
/** Mutable form of the auto-subdomain URL. Use only when a stable URL
|
|
111
|
+
* must always reflect the latest content (eventual consistency on
|
|
112
|
+
* re-upload). Prefer `cdnUrl` for generated code. */
|
|
113
|
+
cdnMutableUrl: string | null;
|
|
114
|
+
/** Strong ETag of the form `"sha256-<hex>"`. Null when `sha256` is null. */
|
|
115
|
+
etag: string | null;
|
|
116
|
+
/** Browser SRI form: `sha256-<base64>`. Use as the `integrity` attribute
|
|
117
|
+
* value in `<script>`/`<link>` tags. */
|
|
118
|
+
sri: string | null;
|
|
119
|
+
/** RFC 9530 `Content-Digest` value, `sha-256=:<base64>:`. */
|
|
120
|
+
contentDigest: string | null;
|
|
121
|
+
/** Semantic cache-kind hint matching the gateway's response header. */
|
|
122
|
+
cacheKind: BlobCacheKind;
|
|
123
|
+
/** CloudFront invalidation envelope. For immutable uploads `cdn.ready ===
|
|
124
|
+
* true` and no further action is needed. */
|
|
125
|
+
cdn: BlobCdnEnvelope;
|
|
126
|
+
/**
|
|
127
|
+
* Returns a ready-to-paste `<script>` tag with the content-addressed
|
|
128
|
+
* URL + Subresource Integrity + `crossorigin`. The browser will refuse
|
|
129
|
+
* to execute the script if the bytes don't match the SHA.
|
|
130
|
+
*
|
|
131
|
+
* **Defaults:** `defer: true`. Modern best practice — non-render-
|
|
132
|
+
* blocking when placed in `<head>` and a no-op at end of `<body>`.
|
|
133
|
+
* Pass `{ defer: false }` for the rare case requiring sync execution.
|
|
134
|
+
* `async: true` overrides defer (the two are mutually exclusive).
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const asset = await client.blobs.put(p, "app.js", { content });
|
|
138
|
+
* html += asset.scriptTag();
|
|
139
|
+
* // → <script src="https://pr-abc.run402.com/_blob/app-3a7fc02e.js" defer integrity="sha256-…" crossorigin></script>
|
|
140
|
+
*
|
|
141
|
+
* asset.scriptTag({ type: "module" });
|
|
142
|
+
* // → <script src="…" type="module" defer integrity="…" crossorigin></script>
|
|
143
|
+
*/
|
|
144
|
+
scriptTag(opts?: {
|
|
145
|
+
type?: "module" | "text/javascript";
|
|
146
|
+
defer?: boolean;
|
|
147
|
+
async?: boolean;
|
|
148
|
+
}): string;
|
|
149
|
+
/**
|
|
150
|
+
* Returns a ready-to-paste `<link>` tag (default `rel="stylesheet"`)
|
|
151
|
+
* with content-addressed URL + SRI + `crossorigin`. `crossorigin` is
|
|
152
|
+
* always emitted — required for SRI to actually be enforced (also
|
|
153
|
+
* required for rel="preload" to dedupe with the matching fetch).
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* asset.linkTag(); // stylesheet
|
|
157
|
+
* asset.linkTag({ rel: "preload", as: "font" });
|
|
158
|
+
* asset.linkTag({ rel: "modulepreload" });
|
|
159
|
+
*/
|
|
160
|
+
linkTag(opts?: {
|
|
161
|
+
rel?: string;
|
|
162
|
+
as?: string;
|
|
163
|
+
}): string;
|
|
164
|
+
/**
|
|
165
|
+
* Returns a ready-to-paste `<img>` tag with the content-addressed URL.
|
|
166
|
+
*
|
|
167
|
+
* **Defaults:** `loading="lazy"` + `decoding="async"`. Modern best
|
|
168
|
+
* practice — lazy loads below-fold images on demand, async decoding
|
|
169
|
+
* moves the decode off the main thread. Both are baseline-supported
|
|
170
|
+
* in all major browsers. Agents who specifically need an above-fold
|
|
171
|
+
* eager image can wrap the result and override.
|
|
172
|
+
*
|
|
173
|
+
* Browsers don't support SRI on `<img>`, so no `integrity` attribute
|
|
174
|
+
* is emitted. The URL is content-hashed so it's still stable across
|
|
175
|
+
* re-deploys; for byte-level verification, read `Content-Digest`
|
|
176
|
+
* server-side.
|
|
177
|
+
*
|
|
178
|
+
* `alt` is the image's accessibility text (default `""` for decorative
|
|
179
|
+
* images). Pass a description when the image conveys information.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* asset.imgTag("Company logo")
|
|
183
|
+
* // → <img src="https://pr-abc.run402.com/_blob/logo-a1b2c3d4.png" alt="Company logo" loading="lazy" decoding="async">
|
|
184
|
+
*/
|
|
185
|
+
imgTag(alt?: string): string;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Return type of `client.blobs.put`. v1.45 widens this to AssetRef; the
|
|
189
|
+
* legacy fields stay for back-compat.
|
|
190
|
+
*/
|
|
191
|
+
export type BlobPutResult = AssetRef;
|
|
192
|
+
/** Response envelope from `client.blobs.diagnoseUrl(...)`. */
|
|
193
|
+
export interface BlobDiagnoseEnvelope {
|
|
194
|
+
projectId: string;
|
|
195
|
+
key: string;
|
|
196
|
+
/** SHA the gateway DB believes is current for `(projectId, key)`. */
|
|
197
|
+
expectedSha256: string | null;
|
|
198
|
+
/** SHA actually returned by the probe (`X-Run402-Content-Sha256` header). */
|
|
199
|
+
observedSha256: string | null;
|
|
200
|
+
/** Probe vantage. The agent is told the probe is single-region. */
|
|
201
|
+
vantage: "gateway-us-east-1";
|
|
202
|
+
/** Probe method — `"GET_RANGE_0_0"` (NOT HEAD; HEAD can hit a different
|
|
203
|
+
* cached variant). */
|
|
204
|
+
probeMethod: "GET_RANGE_0_0";
|
|
205
|
+
/** Accept-Encoding used by the probe. */
|
|
206
|
+
acceptEncoding: string;
|
|
207
|
+
/** ISO timestamp of the probe. */
|
|
208
|
+
observedAt: string;
|
|
209
|
+
/** Always `true` — the probe itself populates the cache, so subsequent
|
|
210
|
+
* reads may differ. Agents are told this explicitly. */
|
|
211
|
+
probeMayHaveWarmedCache: true;
|
|
212
|
+
/** The URL the probe actually fetched (after URL normalization). */
|
|
213
|
+
canonicalUrl: string;
|
|
214
|
+
/** Which URL kind we resolved against (`'blob-immutable'` or
|
|
215
|
+
* `'blob-mutable'`). `/_cas/<sha>` is deferred from this change. */
|
|
216
|
+
pathKind: "blob-mutable" | "blob-immutable";
|
|
217
|
+
cache: {
|
|
218
|
+
xCache: string | null;
|
|
219
|
+
ageSeconds: number | null;
|
|
220
|
+
cacheKind: BlobCacheKind | null;
|
|
221
|
+
};
|
|
222
|
+
invalidation: {
|
|
223
|
+
id: string | null;
|
|
224
|
+
status: "InProgress" | "Completed" | "Failed" | null;
|
|
225
|
+
};
|
|
226
|
+
/** Human-readable hint with actionable next-steps for the agent. */
|
|
227
|
+
hint: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Options for `client.blobs.waitFresh(projectId, opts)`. The URL is the
|
|
231
|
+
* mutable public URL you want to wait on (typically `result.url` from a
|
|
232
|
+
* preceding `blobs.put` call).
|
|
233
|
+
*
|
|
234
|
+
* **Mutable URLs only.** For immutable URLs (`immutableUrl`) no waiting is
|
|
235
|
+
* needed — they are bound to a SHA at upload time and were never previously
|
|
236
|
+
* cached.
|
|
237
|
+
*/
|
|
238
|
+
export interface BlobWaitFreshOptions {
|
|
239
|
+
/** The mutable URL to poll (e.g. `https://app.run402.com/_blob/avatar.png`). */
|
|
240
|
+
url: string;
|
|
241
|
+
/** Expected hex SHA-256. Polling exits when `observedSha256 === sha256`. */
|
|
242
|
+
sha256: string;
|
|
243
|
+
/** Default 60_000 ms. */
|
|
244
|
+
timeoutMs?: number;
|
|
245
|
+
}
|
|
246
|
+
/** Result of `client.blobs.waitFresh(...)`. */
|
|
247
|
+
export interface BlobWaitFreshResult {
|
|
248
|
+
fresh: boolean;
|
|
249
|
+
observedSha256: string | null;
|
|
250
|
+
attempts: number;
|
|
251
|
+
elapsedMs: number;
|
|
252
|
+
vantage: "gateway-us-east-1";
|
|
29
253
|
}
|
|
30
254
|
export interface BlobLsOptions {
|
|
31
255
|
/** Filter: only return blobs whose key starts with this prefix. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobs.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/blobs.types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElD,qFAAqF;AACrF,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,
|
|
1
|
+
{"version":3,"file":"blobs.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/blobs.types.ts"],"names":[],"mappings":"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"}
|
package/lib/storage.mjs
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import { findProject, API } from "./config.mjs";
|
|
3
|
-
|
|
4
|
-
const HELP = `run402 storage — Manage project file storage
|
|
5
|
-
|
|
6
|
-
Usage:
|
|
7
|
-
run402 storage <subcommand> [args...]
|
|
8
|
-
|
|
9
|
-
Subcommands:
|
|
10
|
-
upload <id> <bucket> <path> [--file <local>] [--content-type <mime>]
|
|
11
|
-
Upload a file to storage
|
|
12
|
-
download <id> <bucket> <path> Download a file from storage
|
|
13
|
-
delete <id> <bucket> <path> Delete a file from storage
|
|
14
|
-
list <id> <bucket> List files in a bucket
|
|
15
|
-
|
|
16
|
-
Examples:
|
|
17
|
-
run402 storage upload abc123 assets logo.png --file ./logo.png --content-type image/png
|
|
18
|
-
echo "hello" | run402 storage upload abc123 data notes.txt
|
|
19
|
-
run402 storage download abc123 assets logo.png
|
|
20
|
-
run402 storage list abc123 assets
|
|
21
|
-
run402 storage delete abc123 assets logo.png
|
|
22
|
-
|
|
23
|
-
Notes:
|
|
24
|
-
- <id> is the project_id from 'run402 projects list'
|
|
25
|
-
- Upload reads from --file or stdin if no --file is given
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
const SUB_HELP = {
|
|
29
|
-
upload: `run402 storage upload — Upload a file to a project's storage bucket
|
|
30
|
-
|
|
31
|
-
Usage:
|
|
32
|
-
run402 storage upload <id> <bucket> <path> [--file <local>] [--content-type <mime>]
|
|
33
|
-
echo "..." | run402 storage upload <id> <bucket> <path> [--content-type <mime>]
|
|
34
|
-
|
|
35
|
-
Arguments:
|
|
36
|
-
<id> Project ID (from 'run402 projects list')
|
|
37
|
-
<bucket> Target bucket name
|
|
38
|
-
<path> Destination path within the bucket
|
|
39
|
-
|
|
40
|
-
Options:
|
|
41
|
-
--file <local> Local file to upload; if omitted, content is read from stdin
|
|
42
|
-
--content-type <mime> MIME type of the upload (default: text/plain)
|
|
43
|
-
|
|
44
|
-
Examples:
|
|
45
|
-
run402 storage upload abc123 assets logo.png --file ./logo.png \\
|
|
46
|
-
--content-type image/png
|
|
47
|
-
echo "hello" | run402 storage upload abc123 data notes.txt
|
|
48
|
-
`,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
async function readStdin() {
|
|
52
|
-
const chunks = [];
|
|
53
|
-
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
54
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function upload(projectId, bucket, path, args) {
|
|
58
|
-
const p = findProject(projectId);
|
|
59
|
-
const opts = { file: null, contentType: "text/plain" };
|
|
60
|
-
for (let i = 0; i < args.length; i++) {
|
|
61
|
-
if (args[i] === "--file" && args[i + 1]) opts.file = args[++i];
|
|
62
|
-
if (args[i] === "--content-type" && args[i + 1]) opts.contentType = args[++i];
|
|
63
|
-
}
|
|
64
|
-
const content = opts.file ? readFileSync(opts.file, "utf-8") : await readStdin();
|
|
65
|
-
const res = await fetch(`${API}/storage/v1/object/${bucket}/${path}`, {
|
|
66
|
-
method: "POST",
|
|
67
|
-
headers: { "Content-Type": opts.contentType, "apikey": p.anon_key, "Authorization": `Bearer ${p.anon_key}` },
|
|
68
|
-
body: content,
|
|
69
|
-
});
|
|
70
|
-
const data = await res.json();
|
|
71
|
-
if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
|
|
72
|
-
console.log(JSON.stringify(data, null, 2));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function download(projectId, bucket, path) {
|
|
76
|
-
const p = findProject(projectId);
|
|
77
|
-
const res = await fetch(`${API}/storage/v1/object/${bucket}/${path}`, {
|
|
78
|
-
headers: { "apikey": p.anon_key, "Authorization": `Bearer ${p.anon_key}` },
|
|
79
|
-
});
|
|
80
|
-
if (!res.ok) {
|
|
81
|
-
const data = await res.json().catch(() => ({}));
|
|
82
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
const text = await res.text();
|
|
85
|
-
process.stdout.write(text);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function deleteFile(projectId, bucket, path) {
|
|
89
|
-
const p = findProject(projectId);
|
|
90
|
-
const res = await fetch(`${API}/storage/v1/object/${bucket}/${path}`, {
|
|
91
|
-
method: "DELETE",
|
|
92
|
-
headers: { "apikey": p.anon_key, "Authorization": `Bearer ${p.anon_key}` },
|
|
93
|
-
});
|
|
94
|
-
if (res.status === 204 || res.ok) {
|
|
95
|
-
console.log(JSON.stringify({ status: "ok", message: `File '${bucket}/${path}' deleted.` }));
|
|
96
|
-
} else {
|
|
97
|
-
const data = await res.json().catch(() => ({}));
|
|
98
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function list(projectId, bucket) {
|
|
103
|
-
const p = findProject(projectId);
|
|
104
|
-
const res = await fetch(`${API}/storage/v1/object/list/${bucket}`, {
|
|
105
|
-
headers: { "apikey": p.anon_key, "Authorization": `Bearer ${p.anon_key}` },
|
|
106
|
-
});
|
|
107
|
-
const data = await res.json();
|
|
108
|
-
if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
|
|
109
|
-
console.log(JSON.stringify(data, null, 2));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export async function run(sub, args) {
|
|
113
|
-
if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
|
|
114
|
-
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
|
|
115
|
-
switch (sub) {
|
|
116
|
-
case "upload": await upload(args[0], args[1], args[2], args.slice(3)); break;
|
|
117
|
-
case "download": await download(args[0], args[1], args[2]); break;
|
|
118
|
-
case "delete": await deleteFile(args[0], args[1], args[2]); break;
|
|
119
|
-
case "list": await list(args[0], args[1]); break;
|
|
120
|
-
default:
|
|
121
|
-
console.error(`Unknown subcommand: ${sub}\n`);
|
|
122
|
-
console.log(HELP);
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
}
|