run402 1.43.0 → 1.44.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/lib/sites.mjs CHANGED
@@ -1,15 +1,16 @@
1
- import { readFileSync } from "fs";
2
- import { dirname, resolve } from "path";
1
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
2
+ import { tmpdir } from "os";
3
+ import { dirname, join, resolve } from "path";
3
4
  import { allowanceAuthHeaders, resolveProjectId, updateProject } from "./config.mjs";
4
5
  import { resolveFilePathsInManifest } from "./manifest.mjs";
5
6
  import { getSdk } from "./sdk.mjs";
6
7
  import { reportSdkError } from "./sdk-errors.mjs";
7
8
 
8
- const HELP = `run402 sites Deploy and manage static sites
9
+ const HELP = `run402 sites - Deploy and manage static sites
9
10
 
10
11
  Usage:
11
12
  run402 sites deploy --manifest <file> [--project <id>] [--target <target>]
12
- run402 sites deploy-dir <path> --project <id> [--target <target>] [--inherit]
13
+ run402 sites deploy-dir <path> --project <id> [--target <target>]
13
14
  run402 sites status <deployment_id>
14
15
  cat manifest.json | run402 sites deploy
15
16
 
@@ -22,14 +23,12 @@ Options (deploy):
22
23
  --manifest <file> Path to manifest JSON file (or read from stdin)
23
24
  --project <id> Project ID (defaults to active project)
24
25
  --target <target> Deployment target (e.g. 'production')
25
- --inherit Copy unchanged files from the previous deployment (only upload changed files)
26
26
  --help, -h Show this help message
27
27
 
28
28
  Options (deploy-dir):
29
29
  <path> Positional: local directory to deploy
30
30
  --project <id> Project ID (defaults to active project)
31
31
  --target <target> Deployment target (e.g. 'production')
32
- --inherit Copy unchanged files from the previous deployment server-side
33
32
 
34
33
  Manifest format (JSON):
35
34
  {
@@ -40,36 +39,37 @@ Manifest format (JSON):
40
39
  }
41
40
 
42
41
  Files can use either inline "data" or a local "path":
43
- { "file": "index.html", "data": "<html>...</html>" } inline content
44
- { "file": "style.css", "path": "./dist/style.css" } read from disk
42
+ { "file": "index.html", "data": "<html>...</html>" } <- inline content
43
+ { "file": "style.css", "path": "./dist/style.css" } <- read from disk
45
44
  Paths are resolved relative to the manifest file's directory.
46
45
  Binary files (images, fonts, etc.) are auto-detected and base64-encoded.
47
46
 
48
47
  Examples:
49
48
  run402 sites deploy --manifest site.json
50
- run402 sites deploy-dir ./my-site --project prj_abc --inherit
49
+ run402 sites deploy-dir ./my-site --project prj_abc
51
50
  run402 sites status dpl_abc123
52
51
  cat site.json | run402 sites deploy
53
52
 
54
53
  Notes:
54
+ - Both deploy and deploy-dir use the v1.32 plan/commit transport: only
55
+ bytes the gateway doesn't already have are uploaded. Re-deploys of an
56
+ unchanged tree make no S3 PUTs.
55
57
  - deploy-dir walks the directory, skips .git / node_modules / .DS_Store,
56
58
  and auto-detects binary files. Symlinks are rejected.
57
- - Free with active tier requires allowance auth
59
+ - Free with active tier - requires allowance auth
58
60
  `;
59
61
 
60
62
  const SUB_HELP = {
61
- deploy: `run402 sites deploy Deploy a static site from a manifest
63
+ deploy: `run402 sites deploy - Deploy a static site from a manifest
62
64
 
63
65
  Usage:
64
- run402 sites deploy --manifest <file> [--project <id>] [--target <target>] [--inherit]
66
+ run402 sites deploy --manifest <file> [--project <id>] [--target <target>]
65
67
  cat manifest.json | run402 sites deploy [--project <id>] [--target <target>]
66
68
 
67
69
  Options:
68
70
  --manifest <file> Path to manifest JSON file (or read from stdin)
69
71
  --project <id> Project ID (defaults to the active project)
70
72
  --target <target> Deployment target (e.g. 'production')
71
- --inherit Copy unchanged files from the previous deployment
72
- (only upload changed files)
73
73
 
74
74
  Manifest format (JSON):
75
75
  {
@@ -83,17 +83,17 @@ Manifest format (JSON):
83
83
 
84
84
  Notes:
85
85
  - Must include at least index.html in the files array
86
- - Free with active tier requires allowance auth
86
+ - Free with active tier - requires allowance auth
87
87
 
88
88
  Examples:
89
89
  run402 sites deploy --manifest site.json
90
- run402 sites deploy --manifest site.json --target production --inherit
90
+ run402 sites deploy --manifest site.json --target production
91
91
  cat site.json | run402 sites deploy
92
92
  `,
93
- "deploy-dir": `run402 sites deploy-dir Deploy a static site from a local directory
93
+ "deploy-dir": `run402 sites deploy-dir - Deploy a static site from a local directory
94
94
 
95
95
  Usage:
96
- run402 sites deploy-dir <path> [--project <id>] [--target <target>] [--inherit]
96
+ run402 sites deploy-dir <path> [--project <id>] [--target <target>]
97
97
 
98
98
  Arguments:
99
99
  <path> Local directory to deploy (positional, required)
@@ -101,23 +101,22 @@ Arguments:
101
101
  Options:
102
102
  --project <id> Project ID (defaults to the active project)
103
103
  --target <target> Deployment target (e.g. 'production')
104
- --inherit Copy unchanged files from the previous deployment
105
104
 
106
105
  Behavior:
107
106
  - Walks <path> recursively, skips .git / node_modules / .DS_Store
108
- - UTF-8 files are inlined as text; binary files are base64-encoded
107
+ - Computes per-file SHA-256 and uploads only bytes the gateway doesn't
108
+ already have (plan/commit transport, v1.32+)
109
109
  - Symlinks are rejected (no following)
110
110
  - Paths in the manifest are POSIX-style relative to <path>
111
111
 
112
112
  Notes:
113
- - Practical size limit today is ~100 MB (inline JSON payload).
114
- For larger sites, use a pre-built manifest with the bundle_deploy API
115
- or wait for blob-backed deploys.
116
- - Free with active tier — requires allowance auth
113
+ - Re-deploying an unchanged tree makes no S3 PUTs (returns immediately
114
+ with bytes_uploaded: 0)
115
+ - Free with active tier - requires allowance auth
117
116
 
118
117
  Examples:
119
118
  run402 sites deploy-dir ./dist --project prj_abc
120
- run402 sites deploy-dir ./my-site --project prj_abc --target production --inherit
119
+ run402 sites deploy-dir ./my-site --project prj_abc --target production
121
120
  `,
122
121
  };
123
122
 
@@ -127,14 +126,41 @@ async function readStdin() {
127
126
  return Buffer.concat(chunks).toString("utf-8");
128
127
  }
129
128
 
129
+ /**
130
+ * Stage manifest files to a temp directory so the SDK's deployDir can walk
131
+ * them. The v1.32 SDK no longer accepts inline file bytes — every deploy
132
+ * goes through plan/commit and reads from a directory.
133
+ */
134
+ function stageFilesToTempDir(files) {
135
+ const stage = mkdtempSync(join(tmpdir(), "run402-deploy-stage-"));
136
+ for (const f of files) {
137
+ if (typeof f.file !== "string" || typeof f.data !== "string") {
138
+ throw new Error("manifest entry missing required 'file' or 'data' string");
139
+ }
140
+ const target = join(stage, f.file);
141
+ mkdirSync(dirname(target), { recursive: true });
142
+ const buf = (f.encoding ?? "utf-8") === "base64"
143
+ ? Buffer.from(f.data, "base64")
144
+ : Buffer.from(f.data, "utf-8");
145
+ writeFileSync(target, buf);
146
+ }
147
+ return stage;
148
+ }
149
+
130
150
  async function deploy(args) {
131
- const opts = { manifest: null, project: undefined, target: undefined, inherit: false };
151
+ const opts = { manifest: null, project: undefined, target: undefined };
132
152
  for (let i = 0; i < args.length; i++) {
133
153
  if (args[i] === "--help" || args[i] === "-h") { console.log(HELP); process.exit(0); }
134
154
  if (args[i] === "--manifest" && args[i + 1]) opts.manifest = args[++i];
135
155
  if (args[i] === "--project" && args[i + 1]) opts.project = args[++i];
136
156
  if (args[i] === "--target" && args[i + 1]) opts.target = args[++i];
137
- if (args[i] === "--inherit") opts.inherit = true;
157
+ if (args[i] === "--inherit") {
158
+ console.error(JSON.stringify({
159
+ status: "error",
160
+ message: "--inherit is removed in v1.32; the SDK now uploads only changed files automatically.",
161
+ }));
162
+ process.exit(1);
163
+ }
138
164
  }
139
165
  const projectId = resolveProjectId(opts.project);
140
166
  const raw = opts.manifest ? readFileSync(opts.manifest, "utf-8") : await readStdin();
@@ -142,13 +168,14 @@ async function deploy(args) {
142
168
  if (opts.manifest) resolveFilePathsInManifest(manifest, dirname(resolve(opts.manifest)));
143
169
 
144
170
  // Preserve the aggressive early exit when no allowance is configured.
145
- allowanceAuthHeaders("/deployments/v1");
171
+ allowanceAuthHeaders("/deploy/v1/plan");
146
172
 
173
+ const stage = stageFilesToTempDir(manifest.files || []);
147
174
  try {
148
- const data = await getSdk().sites.deploy(projectId, {
149
- files: manifest.files,
175
+ const data = await getSdk().sites.deployDir({
176
+ project: projectId,
177
+ dir: stage,
150
178
  target: opts.target,
151
- inherit: opts.inherit,
152
179
  });
153
180
  if (data.deployment_id) {
154
181
  updateProject(projectId, { last_deployment_id: data.deployment_id });
@@ -156,16 +183,24 @@ async function deploy(args) {
156
183
  console.log(JSON.stringify(data, null, 2));
157
184
  } catch (err) {
158
185
  reportSdkError(err);
186
+ } finally {
187
+ rmSync(stage, { recursive: true, force: true });
159
188
  }
160
189
  }
161
190
 
162
191
  async function deployDir(args) {
163
- const opts = { dir: null, project: undefined, target: undefined, inherit: false };
192
+ const opts = { dir: null, project: undefined, target: undefined };
164
193
  for (let i = 0; i < args.length; i++) {
165
194
  if (args[i] === "--help" || args[i] === "-h") { console.log(SUB_HELP["deploy-dir"]); process.exit(0); }
166
195
  if (args[i] === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
167
196
  if (args[i] === "--target" && args[i + 1]) { opts.target = args[++i]; continue; }
168
- if (args[i] === "--inherit") { opts.inherit = true; continue; }
197
+ if (args[i] === "--inherit") {
198
+ console.error(JSON.stringify({
199
+ status: "error",
200
+ message: "--inherit is removed in v1.32; the SDK now uploads only changed files automatically.",
201
+ }));
202
+ process.exit(1);
203
+ }
169
204
  if (!args[i].startsWith("-") && opts.dir === null) { opts.dir = args[i]; continue; }
170
205
  }
171
206
  if (!opts.dir) {
@@ -175,14 +210,13 @@ async function deployDir(args) {
175
210
  const projectId = resolveProjectId(opts.project);
176
211
 
177
212
  // Preserve the aggressive early exit when no allowance is configured.
178
- allowanceAuthHeaders("/deployments/v1");
213
+ allowanceAuthHeaders("/deploy/v1/plan");
179
214
 
180
215
  try {
181
216
  const data = await getSdk().sites.deployDir({
182
217
  project: projectId,
183
218
  dir: opts.dir,
184
219
  target: opts.target,
185
- inherit: opts.inherit,
186
220
  });
187
221
  if (data.deployment_id) {
188
222
  updateProject(projectId, { last_deployment_id: data.deployment_id });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.43.0",
3
+ "version": "1.44.0",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,9 +1,14 @@
1
1
  /**
2
- * `sites` namespace — static site deployments via `/deployments/v1`.
2
+ * `sites` namespace — static site deployments.
3
3
  *
4
- * `deploy` uses allowance-based SIWX auth (no project service key — the
5
- * project is referenced in the request body). Callers persisting
6
- * `last_deployment_id` locally should do so after a successful response.
4
+ * As of v1.32 the inline-bytes deploy path (`POST /deployments/v1` with
5
+ * base64 file blobs) is REMOVED at the gateway (returns 410 Gone). Callers
6
+ * migrate to `NodeSites.deployDir` from `@run402/sdk/node`, which uses the
7
+ * plan/commit transport over `/deploy/v1/plan` + `/deploy/v1/commit`.
8
+ *
9
+ * The isomorphic surface keeps only the public read-only `getDeployment`
10
+ * call. `SiteFile` is preserved for `apps.bundleDeploy` (separate `/deploy/v1`
11
+ * endpoint, unaffected by the v1.32 cutover).
7
12
  */
8
13
  import type { Client } from "../kernel.js";
9
14
  export interface SiteFile {
@@ -13,20 +18,13 @@ export interface SiteFile {
13
18
  data: string;
14
19
  encoding?: "utf-8" | "base64";
15
20
  }
16
- export interface SiteDeployOptions {
17
- /** Files to deploy. Paths are relative to the site root. */
18
- files: SiteFile[];
19
- /** Deployment target label, e.g. `"production"`. */
20
- target?: string;
21
- /**
22
- * When true, unchanged files are copied from the previous deployment —
23
- * only changed/new files need to appear in `files`.
24
- */
25
- inherit?: boolean;
26
- }
27
21
  export interface SiteDeployResult {
28
22
  deployment_id: string;
29
23
  url: string;
24
+ /** Total bytes across the manifest (present when reported by the gateway). */
25
+ bytes_total?: number;
26
+ /** Bytes uploaded in this deploy (0 on a no-op redeploy). */
27
+ bytes_uploaded?: number;
30
28
  }
31
29
  export interface DeploymentInfo {
32
30
  id: string;
@@ -40,12 +38,6 @@ export interface DeploymentInfo {
40
38
  export declare class Sites {
41
39
  private readonly client;
42
40
  constructor(client: Client);
43
- /**
44
- * Deploy a static site. Payment flows through the configured fetch wrapper
45
- * (x402 in Node when a tier purchase is required; typically free with an
46
- * active tier).
47
- */
48
- deploy(projectId: string, opts: SiteDeployOptions): Promise<SiteDeployResult>;
49
41
  /** Get deployment metadata by id. Public — no project auth. */
50
42
  getDeployment(deploymentId: string): Promise<DeploymentInfo>;
51
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/namespaces/sites.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYnF,+DAA+D;IACzD,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAMnE"}
1
+ {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/namespaces/sites.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,+DAA+D;IACzD,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAMnE"}
@@ -1,32 +1,20 @@
1
1
  /**
2
- * `sites` namespace — static site deployments via `/deployments/v1`.
2
+ * `sites` namespace — static site deployments.
3
3
  *
4
- * `deploy` uses allowance-based SIWX auth (no project service key — the
5
- * project is referenced in the request body). Callers persisting
6
- * `last_deployment_id` locally should do so after a successful response.
4
+ * As of v1.32 the inline-bytes deploy path (`POST /deployments/v1` with
5
+ * base64 file blobs) is REMOVED at the gateway (returns 410 Gone). Callers
6
+ * migrate to `NodeSites.deployDir` from `@run402/sdk/node`, which uses the
7
+ * plan/commit transport over `/deploy/v1/plan` + `/deploy/v1/commit`.
8
+ *
9
+ * The isomorphic surface keeps only the public read-only `getDeployment`
10
+ * call. `SiteFile` is preserved for `apps.bundleDeploy` (separate `/deploy/v1`
11
+ * endpoint, unaffected by the v1.32 cutover).
7
12
  */
8
13
  export class Sites {
9
14
  client;
10
15
  constructor(client) {
11
16
  this.client = client;
12
17
  }
13
- /**
14
- * Deploy a static site. Payment flows through the configured fetch wrapper
15
- * (x402 in Node when a tier purchase is required; typically free with an
16
- * active tier).
17
- */
18
- async deploy(projectId, opts) {
19
- const body = { project: projectId, files: opts.files };
20
- if (opts.target !== undefined)
21
- body.target = opts.target;
22
- if (opts.inherit)
23
- body.inherit = true;
24
- return this.client.request("/deployments/v1", {
25
- method: "POST",
26
- body,
27
- context: "deploying site",
28
- });
29
- }
30
18
  /** Get deployment metadata by id. Public — no project auth. */
31
19
  async getDeployment(deploymentId) {
32
20
  return this.client.request(`/deployments/v1/${deploymentId}`, {
@@ -1 +1 @@
1
- {"version":3,"file":"sites.js","sourceRoot":"","sources":["../../src/namespaces/sites.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuCH,MAAM,OAAO,KAAK;IACa;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,IAAuB;QACrD,MAAM,IAAI,GAA4B,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAChF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzD,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEtC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAmB,iBAAiB,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,+DAA+D;IAC/D,KAAK,CAAC,aAAa,CAAC,YAAoB;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAiB,mBAAmB,YAAY,EAAE,EAAE;YAC5E,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"sites.js","sourceRoot":"","sources":["../../src/namespaces/sites.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+BH,MAAM,OAAO,KAAK;IACa;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C,+DAA+D;IAC/D,KAAK,CAAC,aAAa,CAAC,YAAoB;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAiB,mBAAmB,YAAY,EAAE,EAAE;YAC5E,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * RFC 8785 (JCS) canonical JSON for the v1.32 deploy-plan manifest digest.
3
+ *
4
+ * MUST stay byte-for-byte identical to the gateway's
5
+ * `services/deploy-plans.ts:canonicalizeJson`. A digest mismatch breaks
6
+ * idempotency: the SDK's hash won't match the gateway's, so retrying a
7
+ * plan creates a NEW plan instead of finding the existing one.
8
+ *
9
+ * Spec for our value domain:
10
+ * - object keys sorted ASCII-ascending
11
+ * - arrays comma-separated, no whitespace
12
+ * - strings/numbers via JSON.stringify (matches RFC 8785 for ASCII paths,
13
+ * hex sha256, integer sizes, ASCII content_types)
14
+ */
15
+ export interface ManifestEntry {
16
+ path: string;
17
+ sha256: string;
18
+ size: number;
19
+ content_type: string;
20
+ }
21
+ export interface Manifest {
22
+ files: ManifestEntry[];
23
+ }
24
+ export declare function canonicalizeJson(value: unknown): string;
25
+ /**
26
+ * Build the canonical manifest object the gateway hashes: `{ files: [...] }`
27
+ * with entries sorted by path and only the four expected keys per entry.
28
+ * `content_type` defaults to `"application/octet-stream"` when absent.
29
+ */
30
+ export declare function buildCanonicalManifest(entries: Array<{
31
+ path: string;
32
+ sha256: string;
33
+ size: number;
34
+ content_type?: string;
35
+ }>): Manifest;
36
+ /**
37
+ * Compute the hex SHA-256 of the canonical JSON encoding of a manifest.
38
+ * Matches the gateway's `computeManifestDigest`.
39
+ */
40
+ export declare function computeManifestDigest(manifest: Manifest): Promise<string>;
41
+ //# sourceMappingURL=canonicalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalize.d.ts","sourceRoot":"","sources":["../../src/node/canonicalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAavD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACpF,QAAQ,CAUV;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/E"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * RFC 8785 (JCS) canonical JSON for the v1.32 deploy-plan manifest digest.
3
+ *
4
+ * MUST stay byte-for-byte identical to the gateway's
5
+ * `services/deploy-plans.ts:canonicalizeJson`. A digest mismatch breaks
6
+ * idempotency: the SDK's hash won't match the gateway's, so retrying a
7
+ * plan creates a NEW plan instead of finding the existing one.
8
+ *
9
+ * Spec for our value domain:
10
+ * - object keys sorted ASCII-ascending
11
+ * - arrays comma-separated, no whitespace
12
+ * - strings/numbers via JSON.stringify (matches RFC 8785 for ASCII paths,
13
+ * hex sha256, integer sizes, ASCII content_types)
14
+ */
15
+ export function canonicalizeJson(value) {
16
+ if (value === null)
17
+ return "null";
18
+ if (typeof value === "boolean")
19
+ return value ? "true" : "false";
20
+ if (typeof value === "number")
21
+ return JSON.stringify(value);
22
+ if (typeof value === "string")
23
+ return JSON.stringify(value);
24
+ if (Array.isArray(value))
25
+ return "[" + value.map(canonicalizeJson).join(",") + "]";
26
+ if (typeof value === "object") {
27
+ const obj = value;
28
+ const keys = Object.keys(obj).sort();
29
+ const pairs = keys.map((k) => JSON.stringify(k) + ":" + canonicalizeJson(obj[k]));
30
+ return "{" + pairs.join(",") + "}";
31
+ }
32
+ throw new Error("canonicalizeJson: unsupported value type");
33
+ }
34
+ /**
35
+ * Build the canonical manifest object the gateway hashes: `{ files: [...] }`
36
+ * with entries sorted by path and only the four expected keys per entry.
37
+ * `content_type` defaults to `"application/octet-stream"` when absent.
38
+ */
39
+ export function buildCanonicalManifest(entries) {
40
+ const files = entries
41
+ .map((e) => ({
42
+ path: e.path,
43
+ sha256: e.sha256,
44
+ size: e.size,
45
+ content_type: e.content_type ?? "application/octet-stream",
46
+ }))
47
+ .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
48
+ return { files };
49
+ }
50
+ /**
51
+ * Compute the hex SHA-256 of the canonical JSON encoding of a manifest.
52
+ * Matches the gateway's `computeManifestDigest`.
53
+ */
54
+ export async function computeManifestDigest(manifest) {
55
+ const canonical = canonicalizeJson(manifest);
56
+ const bytes = new TextEncoder().encode(canonical);
57
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
58
+ return Array.from(new Uint8Array(hash))
59
+ .map((b) => b.toString(16).padStart(2, "0"))
60
+ .join("");
61
+ }
62
+ //# sourceMappingURL=canonicalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalize.js","sourceRoot":"","sources":["../../src/node/canonicalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACnF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,OAAO,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACrC,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAqF;IAErF,MAAM,KAAK,GAAoB,OAAO;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,0BAA0B;KAC3D,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAkB;IAC5D,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAgC,CAAC,CAAC;IACrF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;SACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -14,6 +14,10 @@
14
14
  * const project = await r.projects.provision({ tier: "prototype" });
15
15
  * await r.sites.deployDir({ project: project.project_id, dir: "./my-site" });
16
16
  * ```
17
+ *
18
+ * `deployDir` uses the v1.32 plan/commit transport and only uploads the
19
+ * bytes the gateway doesn't already have. Re-deploying an unchanged tree
20
+ * issues no S3 PUTs.
17
21
  */
18
22
  import { Run402 } from "../index.js";
19
23
  import { NodeSites } from "./sites-node.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,MAAM,EAAsB,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAqB/D;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,MAAM,GACP,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,MAAM,EAAsB,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAqB/D;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,MAAM,GACP,MAAM,aAAa,CAAC"}
@@ -14,6 +14,10 @@
14
14
  * const project = await r.projects.provision({ tier: "prototype" });
15
15
  * await r.sites.deployDir({ project: project.project_id, dir: "./my-site" });
16
16
  * ```
17
+ *
18
+ * `deployDir` uses the v1.32 plan/commit transport and only uploads the
19
+ * bytes the gateway doesn't already have. Re-deploying an unchanged tree
20
+ * issues no S3 PUTs.
17
21
  */
18
22
  import { getApiBase } from "../../core-dist/config.js";
19
23
  import { Run402 } from "../index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAsB,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAqB5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,MAAM,CAAC,OAA0B,EAAE;IACjD,MAAM,OAAO,GAAkB;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,UAAU,EAAE;QACrC,WAAW,EAAE,IAAI,uBAAuB,CAAC;YACvC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC;QACF,KAAK,EACH,IAAI,CAAC,KAAK;YACV,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;KACtF,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjC,yEAAyE;IACzE,0EAA0E;IAC1E,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,MAAM,GAAI,IAAI,CAAC,KAAuC,CAAC,MAAM,CAAC;IACnE,IAAwC,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IAExE,OAAO,IAA6B,CAAC;AACvC,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtE,6EAA6E;AAC7E,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAsB,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAqB5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,MAAM,CAAC,OAA0B,EAAE;IACjD,MAAM,OAAO,GAAkB;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,UAAU,EAAE;QACrC,WAAW,EAAE,IAAI,uBAAuB,CAAC;YACvC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC;QACF,KAAK,EACH,IAAI,CAAC,KAAK;YACV,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;KACtF,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjC,yEAAyE;IACzE,0EAA0E;IAC1E,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,MAAM,GAAI,IAAI,CAAC,KAAuC,CAAC,MAAM,CAAC;IACnE,IAAwC,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IAExE,OAAO,IAA6B,CAAC;AACvC,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtE,6EAA6E;AAC7E,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC"}
@@ -1,47 +1,109 @@
1
1
  /**
2
2
  * Node-only augmentation of the `sites` namespace.
3
3
  *
4
- * Adds a `deployDir(dir)` helper that walks a directory on disk, reads
5
- * each file, detects text vs. binary, and assembles the inline
6
- * `SiteFile[]` manifest the isomorphic `Sites.deploy()` expects.
4
+ * `deployDir(dir)` walks a directory, computes per-file SHA-256 + size,
5
+ * builds a canonical manifest, and ships it via the v1.32 plan/commit
6
+ * transport:
7
7
  *
8
- * This file imports `node:fs/promises` and so cannot run in a V8 isolate.
9
- * It is only wired into the SDK via the `@run402/sdk/node` entry point.
8
+ * 1. POST /deploy/v1/plan { manifest_digest, manifest } returns per-file
9
+ * state (`present`, `satisfied_by_plan`, or `missing` + presigned URLs).
10
+ * 2. PUT each `missing` file's bytes to its presigned S3 URL(s),
11
+ * sending `x-amz-checksum-sha256` to satisfy the signed checksum
12
+ * algorithm. Single-PUT covers small files; multipart covers large
13
+ * files (the gateway picks per-part sizing).
14
+ * 3. POST /deploy/v1/commit { plan_id } — Stage 1 (DB) returns
15
+ * synchronously with `applied`, `noop`, `copying`, or `failed`.
16
+ * `copying` triggers a poll loop on `GET /deployments/v1/:id` until
17
+ * `ready` (or `failed`).
18
+ *
19
+ * The canonicalize used to compute `manifest_digest` MUST match the
20
+ * gateway's byte-for-byte (see `./canonicalize.ts`).
21
+ *
22
+ * Imports `node:fs/promises` and so cannot run in a V8 isolate. Wired into
23
+ * the SDK via the `@run402/sdk/node` entry point only.
10
24
  */
11
- import { Sites, type SiteFile, type SiteDeployResult } from "../namespaces/sites.js";
25
+ import { Sites, type SiteDeployResult } from "../namespaces/sites.js";
26
+ import { type ManifestEntry } from "./canonicalize.js";
12
27
  export interface DeployDirOptions {
13
28
  /** Project ID the deployment is linked to. */
14
29
  project: string;
15
30
  /** Local directory to walk. Paths in the manifest are relative to this root. */
16
31
  dir: string;
17
- /** When true, unchanged files are copied from the previous deployment server-side. */
18
- inherit?: boolean;
19
32
  /** Deployment target label, e.g. `"production"`. */
20
33
  target?: string;
21
34
  }
35
+ /** One walked file plus everything we need to hash, plan, and upload it. */
36
+ interface WalkedFile {
37
+ path: string;
38
+ size: number;
39
+ sha256: string;
40
+ content_type: string;
41
+ bytes: Buffer;
42
+ }
43
+ interface PlanFilePresent {
44
+ sha256: string;
45
+ present: true;
46
+ size: number;
47
+ content_type: string;
48
+ }
49
+ interface PlanFileSatisfied {
50
+ sha256: string;
51
+ satisfied_by_plan: true;
52
+ size: number;
53
+ content_type: string;
54
+ }
55
+ interface PlanFileMissing {
56
+ sha256: string;
57
+ missing: true;
58
+ upload_id: string;
59
+ mode: "single" | "multipart";
60
+ key: string;
61
+ staging_key: string;
62
+ part_size_bytes: number;
63
+ part_count: number;
64
+ parts: Array<{
65
+ part_number: number;
66
+ url: string;
67
+ byte_start: number;
68
+ byte_end: number;
69
+ }>;
70
+ expires_at: string;
71
+ }
72
+ type PlanFileResponse = PlanFilePresent | PlanFileSatisfied | PlanFileMissing;
73
+ interface PlanResponse {
74
+ plan_id: string;
75
+ files: PlanFileResponse[];
76
+ }
77
+ interface CommitResponse {
78
+ deployment_id: string;
79
+ url: string;
80
+ status: "applied" | "noop" | "copying" | "failed";
81
+ bytes_total?: number;
82
+ bytes_uploaded?: number;
83
+ }
22
84
  /**
23
85
  * Sites namespace enriched with the Node-only `deployDir` convenience.
24
86
  * All existing `Sites` methods are inherited unchanged.
25
87
  */
26
88
  export declare class NodeSites extends Sites {
27
89
  /**
28
- * Deploy every file under `dir` as a static site. Equivalent to calling
29
- * {@link Sites.deploy} with a manifest you assembled by hand, but the
30
- * walk, binary detection, and encoding are handled for you.
90
+ * Deploy every file under `dir` as a static site. Walks the tree, hashes
91
+ * each file, plans the deploy with the gateway (which dedupes against
92
+ * already-uploaded content), uploads only the missing bytes, then
93
+ * commits.
31
94
  *
32
95
  * Files named `.git`, `node_modules`, or `.DS_Store` are skipped at every
33
96
  * depth. Symlinks cause a {@link LocalError} — they are not followed.
34
97
  */
35
98
  deployDir(opts: DeployDirOptions): Promise<SiteDeployResult>;
36
99
  }
37
- /**
38
- * Walk `root` and return a `SiteFile[]` with POSIX-style relative paths.
39
- * Exported for tests; not part of the public SDK API.
40
- */
41
- export declare function collectSiteFiles(root: string): Promise<SiteFile[]>;
42
100
  /**
43
101
  * Normalize a relative path to POSIX forward slashes. Exposed for tests;
44
102
  * not part of the public SDK API.
45
103
  */
46
104
  export declare function normalizeRelPath(rel: string): string;
105
+ /** @internal — exposed for tests, not part of the public SDK API. */
106
+ export declare function _collectFilesForTest(root: string): Promise<WalkedFile[]>;
107
+ /** @internal — exposed for tests, not part of the public SDK API. */
108
+ export type { WalkedFile, PlanResponse, CommitResponse, ManifestEntry };
47
109
  //# sourceMappingURL=sites-node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sites-node.d.ts","sourceRoot":"","sources":["../../src/node/sites-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,KAAK,EAAE,KAAK,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAMrF,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC;;;;;;;OAOG;IACG,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAcnE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA2BxE;AA+CD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD"}
1
+ {"version":3,"file":"sites-node.d.ts","sourceRoot":"","sources":["../../src/node/sites-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,EAAE,KAAK,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAa3B,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,4EAA4E;AAC5E,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzF,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,KAAK,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,GAAG,eAAe,CAAC;AAE9E,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,UAAU,cAAc;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC;;;;;;;;OAQG;IACG,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAwFnE;AAoOD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AA2DD,qEAAqE;AACrE,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAE9E;AAED,qEAAqE;AACrE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC"}
@@ -1,49 +1,231 @@
1
1
  /**
2
2
  * Node-only augmentation of the `sites` namespace.
3
3
  *
4
- * Adds a `deployDir(dir)` helper that walks a directory on disk, reads
5
- * each file, detects text vs. binary, and assembles the inline
6
- * `SiteFile[]` manifest the isomorphic `Sites.deploy()` expects.
4
+ * `deployDir(dir)` walks a directory, computes per-file SHA-256 + size,
5
+ * builds a canonical manifest, and ships it via the v1.32 plan/commit
6
+ * transport:
7
7
  *
8
- * This file imports `node:fs/promises` and so cannot run in a V8 isolate.
9
- * It is only wired into the SDK via the `@run402/sdk/node` entry point.
8
+ * 1. POST /deploy/v1/plan { manifest_digest, manifest } returns per-file
9
+ * state (`present`, `satisfied_by_plan`, or `missing` + presigned URLs).
10
+ * 2. PUT each `missing` file's bytes to its presigned S3 URL(s),
11
+ * sending `x-amz-checksum-sha256` to satisfy the signed checksum
12
+ * algorithm. Single-PUT covers small files; multipart covers large
13
+ * files (the gateway picks per-part sizing).
14
+ * 3. POST /deploy/v1/commit { plan_id } — Stage 1 (DB) returns
15
+ * synchronously with `applied`, `noop`, `copying`, or `failed`.
16
+ * `copying` triggers a poll loop on `GET /deployments/v1/:id` until
17
+ * `ready` (or `failed`).
18
+ *
19
+ * The canonicalize used to compute `manifest_digest` MUST match the
20
+ * gateway's byte-for-byte (see `./canonicalize.ts`).
21
+ *
22
+ * Imports `node:fs/promises` and so cannot run in a V8 isolate. Wired into
23
+ * the SDK via the `@run402/sdk/node` entry point only.
10
24
  */
11
25
  import { readdir, readFile, lstat } from "node:fs/promises";
12
26
  import { join, relative, sep } from "node:path";
13
27
  import { Sites } from "../namespaces/sites.js";
14
- import { LocalError } from "../errors.js";
28
+ import { ApiError, LocalError, Run402Error } from "../errors.js";
29
+ import { buildCanonicalManifest, computeManifestDigest, } from "./canonicalize.js";
15
30
  const DEFAULT_IGNORE = new Set([".git", "node_modules", ".DS_Store"]);
16
31
  const CONTEXT = "deploying directory";
32
+ /** Cap on total time spent waiting for Stage 2 copy to drain. */
33
+ const COPY_POLL_TIMEOUT_MS = 10 * 60 * 1000;
34
+ /** Initial poll interval; we hold this for ~30 s, then back off. */
35
+ const COPY_POLL_INITIAL_MS = 1_000;
36
+ const COPY_POLL_MAX_MS = 30_000;
37
+ /** Time after which we re-call /deploy/v1/plan to refresh presigned URLs (1 h TTL). */
38
+ const URL_REFRESH_AT_MS = 50 * 60 * 1000;
17
39
  /**
18
40
  * Sites namespace enriched with the Node-only `deployDir` convenience.
19
41
  * All existing `Sites` methods are inherited unchanged.
20
42
  */
21
43
  export class NodeSites extends Sites {
22
44
  /**
23
- * Deploy every file under `dir` as a static site. Equivalent to calling
24
- * {@link Sites.deploy} with a manifest you assembled by hand, but the
25
- * walk, binary detection, and encoding are handled for you.
45
+ * Deploy every file under `dir` as a static site. Walks the tree, hashes
46
+ * each file, plans the deploy with the gateway (which dedupes against
47
+ * already-uploaded content), uploads only the missing bytes, then
48
+ * commits.
26
49
  *
27
50
  * Files named `.git`, `node_modules`, or `.DS_Store` are skipped at every
28
51
  * depth. Symlinks cause a {@link LocalError} — they are not followed.
29
52
  */
30
53
  async deployDir(opts) {
31
- const files = await collectSiteFiles(opts.dir);
54
+ const files = await collectFiles(opts.dir);
32
55
  if (files.length === 0) {
33
56
  throw new LocalError(`directory ${opts.dir} contains no deployable files`, CONTEXT);
34
57
  }
35
- return this.deploy(opts.project, {
36
- files,
37
- inherit: opts.inherit,
38
- target: opts.target,
58
+ const manifest = buildCanonicalManifest(files.map((f) => ({
59
+ path: f.path,
60
+ sha256: f.sha256,
61
+ size: f.size,
62
+ content_type: f.content_type,
63
+ })));
64
+ const manifestDigest = await computeManifestDigest(manifest);
65
+ // Map sha → bytes so we can satisfy the plan response without re-walking.
66
+ // Multiple paths may share the same sha (identical files); any copy works.
67
+ const bytesBySha = new Map();
68
+ for (const f of files)
69
+ bytesBySha.set(f.sha256, f.bytes);
70
+ // Reach through to the kernel client. `Sites.client` is `private` in TS
71
+ // but enumerable at runtime; the cast bypasses the visibility check.
72
+ const client = this.client;
73
+ const planClient = new ClientFromBase(client);
74
+ const plan = await planClient.requestPlan(opts.project, manifest, manifestDigest);
75
+ const planAt = Date.now();
76
+ let activePlan = plan;
77
+ let activePlanAt = planAt;
78
+ for (const entry of activePlan.files) {
79
+ if (!isMissing(entry))
80
+ continue;
81
+ // Refresh the plan if the URL TTL window is about to close.
82
+ if (Date.now() - activePlanAt > URL_REFRESH_AT_MS) {
83
+ activePlan = await planClient.requestPlan(opts.project, manifest, manifestDigest);
84
+ activePlanAt = Date.now();
85
+ }
86
+ const refreshed = activePlan.files.find((e) => e.sha256 === entry.sha256);
87
+ const target = refreshed && isMissing(refreshed) ? refreshed : entry;
88
+ const bytes = bytesBySha.get(target.sha256);
89
+ if (!bytes) {
90
+ throw new LocalError(`internal: no local bytes for sha ${target.sha256.slice(0, 12)}…`, CONTEXT);
91
+ }
92
+ try {
93
+ await uploadOne(client.fetch, target, bytes);
94
+ }
95
+ catch (err) {
96
+ // S3 returns 403 when the presigned URL has expired. Refresh once.
97
+ if (err instanceof ApiError && err.status === 403) {
98
+ activePlan = await planClient.requestPlan(opts.project, manifest, manifestDigest);
99
+ activePlanAt = Date.now();
100
+ const fresh = activePlan.files.find((e) => e.sha256 === target.sha256);
101
+ if (fresh && isMissing(fresh)) {
102
+ await uploadOne(client.fetch, fresh, bytes);
103
+ }
104
+ else {
105
+ throw err;
106
+ }
107
+ }
108
+ else {
109
+ throw err;
110
+ }
111
+ }
112
+ }
113
+ const commit = await planClient.commit(opts.project, activePlan.plan_id);
114
+ if (commit.status === "applied" || commit.status === "noop") {
115
+ return shapeResult(commit);
116
+ }
117
+ if (commit.status === "copying") {
118
+ const final = await pollUntilReady(this, commit.deployment_id);
119
+ return { deployment_id: commit.deployment_id, url: commit.url, ...final };
120
+ }
121
+ // status === "failed": stage 2 exhausted retries. Surface as ApiError so
122
+ // callers can decide whether to re-call deployDir (which re-commits).
123
+ throw new ApiError(`Deploy commit failed for plan ${activePlan.plan_id} after copy retries`, 500, commit, "committing deploy");
124
+ }
125
+ }
126
+ class ClientFromBase {
127
+ client;
128
+ constructor(client) {
129
+ this.client = client;
130
+ }
131
+ async requestPlan(projectId, manifest, manifestDigest) {
132
+ return this.client.request("/deploy/v1/plan", {
133
+ method: "POST",
134
+ body: { project: projectId, manifest_digest: manifestDigest, manifest },
135
+ context: "planning deploy",
136
+ });
137
+ }
138
+ async commit(projectId, planId) {
139
+ return this.client.request("/deploy/v1/commit", {
140
+ method: "POST",
141
+ body: { project: projectId, plan_id: planId },
142
+ context: "committing deploy",
39
143
  });
40
144
  }
41
145
  }
42
- /**
43
- * Walk `root` and return a `SiteFile[]` with POSIX-style relative paths.
44
- * Exported for tests; not part of the public SDK API.
45
- */
46
- export async function collectSiteFiles(root) {
146
+ function isMissing(entry) {
147
+ return entry.missing === true;
148
+ }
149
+ function shapeResult(commit) {
150
+ const out = { deployment_id: commit.deployment_id, url: commit.url };
151
+ if (commit.bytes_total !== undefined)
152
+ out.bytes_total = commit.bytes_total;
153
+ if (commit.bytes_uploaded !== undefined)
154
+ out.bytes_uploaded = commit.bytes_uploaded;
155
+ return out;
156
+ }
157
+ // ─── Upload ──────────────────────────────────────────────────────────────────
158
+ async function uploadOne(fetchFn, entry, bytes) {
159
+ if (entry.mode === "single") {
160
+ if (entry.parts.length !== 1) {
161
+ throw new LocalError(`internal: single-mode upload for ${entry.sha256.slice(0, 12)}… returned ${entry.parts.length} parts`, CONTEXT);
162
+ }
163
+ const part = entry.parts[0];
164
+ const slice = bytes.subarray(part.byte_start, part.byte_end + 1);
165
+ // For single-PUT, the URL pre-commits the whole-object SHA — we send
166
+ // the same value (in base64, not hex) on the PUT.
167
+ const checksum = base64FromHex(entry.sha256);
168
+ await putToS3(fetchFn, part.url, slice, checksum, part.part_number);
169
+ return;
170
+ }
171
+ // multipart: each part PUT carries its own per-part SHA-256 base64.
172
+ for (const part of entry.parts) {
173
+ const slice = bytes.subarray(part.byte_start, part.byte_end + 1);
174
+ const checksum = await sha256Base64(slice);
175
+ await putToS3(fetchFn, part.url, slice, checksum, part.part_number);
176
+ }
177
+ }
178
+ async function putToS3(fetchFn, url, body, checksumBase64, partNumber) {
179
+ let res;
180
+ try {
181
+ res = await fetchFn(url, {
182
+ method: "PUT",
183
+ headers: { "x-amz-checksum-sha256": checksumBase64 },
184
+ body: body,
185
+ });
186
+ }
187
+ catch (err) {
188
+ throw new ApiError(`S3 PUT failed for part ${partNumber}: ${err.message}`, 0, null, "uploading deploy bytes");
189
+ }
190
+ if (!res.ok) {
191
+ const text = await res.text().catch(() => "");
192
+ throw new ApiError(`S3 PUT failed for part ${partNumber} (HTTP ${res.status})${text ? ": " + text.slice(0, 200) : ""}`, res.status, text, "uploading deploy bytes");
193
+ }
194
+ }
195
+ async function pollUntilReady(sites, deploymentId) {
196
+ const start = Date.now();
197
+ let interval = COPY_POLL_INITIAL_MS;
198
+ while (Date.now() - start < COPY_POLL_TIMEOUT_MS) {
199
+ await sleep(interval);
200
+ let info;
201
+ try {
202
+ info = await sites.getDeployment(deploymentId);
203
+ }
204
+ catch (err) {
205
+ // Transient lookup failure: keep polling unless we're a hard error.
206
+ if (err instanceof Run402Error && err.status !== null && err.status >= 500) {
207
+ continue;
208
+ }
209
+ throw err;
210
+ }
211
+ if (info.status === "ready" || info.status === "applied") {
212
+ return { status: info.status, url: info.url };
213
+ }
214
+ if (info.status === "failed") {
215
+ throw new ApiError(`Deployment ${deploymentId} entered failed state during copy`, 500, info, "polling deploy");
216
+ }
217
+ // Hold the initial cadence for the first 30 s, then back off to a max.
218
+ if (Date.now() - start > 30_000) {
219
+ interval = Math.min(Math.floor(interval * 1.5), COPY_POLL_MAX_MS);
220
+ }
221
+ }
222
+ throw new ApiError(`Timed out waiting for deployment ${deploymentId} to reach ready (${COPY_POLL_TIMEOUT_MS / 60_000} min)`, 504, null, "polling deploy");
223
+ }
224
+ function sleep(ms) {
225
+ return new Promise((resolve) => setTimeout(resolve, ms));
226
+ }
227
+ // ─── Filesystem walk + hashing ───────────────────────────────────────────────
228
+ async function collectFiles(root) {
47
229
  let rootStat;
48
230
  try {
49
231
  rootStat = await lstat(root);
@@ -89,7 +271,13 @@ async function walkInto(root, current, out) {
89
271
  throw new LocalError(`cannot read file ${fullPath}: ${err.message}`, CONTEXT, err);
90
272
  }
91
273
  const rel = normalizeRelPath(relative(root, fullPath));
92
- out.push(encodeSiteFile(rel, bytes));
274
+ out.push({
275
+ path: rel,
276
+ size: bytes.byteLength,
277
+ sha256: await sha256Hex(bytes),
278
+ content_type: guessContentType(rel),
279
+ bytes,
280
+ });
93
281
  }
94
282
  }
95
283
  }
@@ -100,13 +288,60 @@ async function walkInto(root, current, out) {
100
288
  export function normalizeRelPath(rel) {
101
289
  return sep === "/" ? rel : rel.split(sep).join("/");
102
290
  }
103
- function encodeSiteFile(path, bytes) {
104
- try {
105
- const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
106
- return { file: path, data: text, encoding: "utf-8" };
107
- }
108
- catch {
109
- return { file: path, data: bytes.toString("base64"), encoding: "base64" };
291
+ async function sha256Hex(bytes) {
292
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
293
+ return Array.from(new Uint8Array(hash))
294
+ .map((b) => b.toString(16).padStart(2, "0"))
295
+ .join("");
296
+ }
297
+ async function sha256Base64(bytes) {
298
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
299
+ return Buffer.from(hash).toString("base64");
300
+ }
301
+ function base64FromHex(hex) {
302
+ if (!/^[0-9a-f]*$/i.test(hex) || hex.length % 2 !== 0) {
303
+ throw new LocalError(`invalid hex sha256: ${hex}`, CONTEXT);
110
304
  }
305
+ return Buffer.from(hex, "hex").toString("base64");
306
+ }
307
+ const CONTENT_TYPES = {
308
+ html: "text/html; charset=utf-8",
309
+ htm: "text/html; charset=utf-8",
310
+ css: "text/css; charset=utf-8",
311
+ js: "application/javascript; charset=utf-8",
312
+ mjs: "application/javascript; charset=utf-8",
313
+ json: "application/json; charset=utf-8",
314
+ svg: "image/svg+xml",
315
+ png: "image/png",
316
+ jpg: "image/jpeg",
317
+ jpeg: "image/jpeg",
318
+ gif: "image/gif",
319
+ webp: "image/webp",
320
+ ico: "image/x-icon",
321
+ woff: "font/woff",
322
+ woff2: "font/woff2",
323
+ ttf: "font/ttf",
324
+ eot: "application/vnd.ms-fontobject",
325
+ otf: "font/otf",
326
+ txt: "text/plain; charset=utf-8",
327
+ md: "text/markdown; charset=utf-8",
328
+ xml: "application/xml",
329
+ pdf: "application/pdf",
330
+ wasm: "application/wasm",
331
+ map: "application/json; charset=utf-8",
332
+ };
333
+ function guessContentType(path) {
334
+ const dot = path.lastIndexOf(".");
335
+ if (dot === -1)
336
+ return "application/octet-stream";
337
+ const ext = path.slice(dot + 1).toLowerCase();
338
+ return CONTENT_TYPES[ext] ?? "application/octet-stream";
339
+ }
340
+ // ─── Test-only exports ───────────────────────────────────────────────────────
341
+ // Kept exported so the unit tests can drive the walk + hash logic without
342
+ // having to spin up an HTTP mock for every concern.
343
+ /** @internal — exposed for tests, not part of the public SDK API. */
344
+ export async function _collectFilesForTest(root) {
345
+ return collectFiles(root);
111
346
  }
112
347
  //# sourceMappingURL=sites-node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sites-node.js","sourceRoot":"","sources":["../../src/node/sites-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sites-node.js","sourceRoot":"","sources":["../../src/node/sites-node.ts"],"names":[],"mappings":"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"}