run402 1.56.0 → 1.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,10 +57,13 @@ run402 projects schema <id> # introspect tables + R
57
57
  ```bash
58
58
  run402 sites deploy-dir ./dist # incremental upload (plan/commit transport)
59
59
  run402 deploy --manifest app.json # one-call full stack deploy
60
+ run402 deploy release active # inspect current-live release inventory
61
+ run402 deploy release diff --from empty --to active
60
62
  run402 subdomains claim my-app # → my-app.run402.com (auto-reassigns on next deploy)
61
63
  ```
62
64
 
63
65
  `deploy-dir` hashes each file client-side and only uploads bytes the gateway doesn't already have. Re-deploying an unchanged tree returns immediately with `bytes_uploaded: 0`. Progress events stream to stderr.
66
+ Release inspection commands print `{ status: "ok", release: ... }` or `{ status: "ok", diff: ... }`; use them after deploys to compare release inventory without starting another mutation.
64
67
 
65
68
  ### GitHub Actions OIDC deploys
66
69
 
package/lib/deploy-v2.mjs CHANGED
@@ -110,11 +110,70 @@ Output:
110
110
  stdout: { "status": "ok", "events": [...] }
111
111
  `;
112
112
 
113
+ const RELEASE_HELP = `run402 deploy release — Inspect deploy release inventory and diffs
114
+
115
+ Usage:
116
+ run402 deploy release get <release_id> [--project <id>] [--site-limit <n>]
117
+ run402 deploy release active [--project <id>] [--site-limit <n>]
118
+ run402 deploy release diff --from <empty|active|release_id> --to <active|release_id> [--project <id>] [--limit <n>]
119
+
120
+ Subcommands:
121
+ get Fetch the inventory for a specific release id
122
+ active Fetch the current-live release inventory for the project
123
+ diff Diff two release targets
124
+
125
+ Output:
126
+ get/active: { "status": "ok", "release": {...} }
127
+ diff: { "status": "ok", "diff": {...} }
128
+ `;
129
+
130
+ const RELEASE_GET_HELP = `run402 deploy release get — Fetch a release inventory by id
131
+
132
+ Usage:
133
+ run402 deploy release get <release_id> [--project <id>] [--site-limit <n>]
134
+
135
+ Options:
136
+ --project <id> Project ID that owns the release (default: active project)
137
+ --site-limit <n> Maximum site path entries to include (gateway default: 5000)
138
+
139
+ Output:
140
+ stdout: { "status": "ok", "release": {...} }
141
+ `;
142
+
143
+ const RELEASE_ACTIVE_HELP = `run402 deploy release active — Fetch the active release inventory
144
+
145
+ Usage:
146
+ run402 deploy release active [--project <id>] [--site-limit <n>]
147
+
148
+ Options:
149
+ --project <id> Project ID to inspect (default: active project)
150
+ --site-limit <n> Maximum site path entries to include (gateway default: 5000)
151
+
152
+ Output:
153
+ stdout: { "status": "ok", "release": {...} }
154
+ `;
155
+
156
+ const RELEASE_DIFF_HELP = `run402 deploy release diff — Diff two release targets
157
+
158
+ Usage:
159
+ run402 deploy release diff --from <empty|active|release_id> --to <active|release_id> [--project <id>] [--limit <n>]
160
+
161
+ Options:
162
+ --from <target> Diff source: empty, active, or rel_...
163
+ --to <target> Diff target: active or rel_...
164
+ --project <id> Project ID to inspect (default: active project)
165
+ --limit <n> Maximum entries per site diff bucket (gateway default: 1000)
166
+
167
+ Output:
168
+ stdout: { "status": "ok", "diff": {...} }
169
+ `;
170
+
113
171
  export async function runDeployV2(sub, args) {
114
172
  if (sub === "apply") return await applyCmd(args);
115
173
  if (sub === "resume") return await resumeCmd(args);
116
174
  if (sub === "list") return await listCmd(args);
117
175
  if (sub === "events") return await eventsCmd(args);
176
+ if (sub === "release") return await releaseCmd(args);
118
177
  fail({
119
178
  code: "BAD_USAGE",
120
179
  message: `Unknown deploy subcommand: ${sub}`,
@@ -498,6 +557,118 @@ async function eventsCmd(args) {
498
557
  }
499
558
  }
500
559
 
560
+ async function releaseCmd(args) {
561
+ const action = args[0];
562
+ if (!action || action === "--help" || action === "-h") {
563
+ console.log(RELEASE_HELP);
564
+ process.exit(0);
565
+ }
566
+ if (action === "get") return await releaseGetCmd(args.slice(1));
567
+ if (action === "active") return await releaseActiveCmd(args.slice(1));
568
+ if (action === "diff") return await releaseDiffCmd(args.slice(1));
569
+ fail({
570
+ code: "BAD_USAGE",
571
+ message: `Unknown deploy release subcommand: ${action}`,
572
+ details: { subcommand: action },
573
+ });
574
+ }
575
+
576
+ async function releaseGetCmd(args) {
577
+ const opts = { releaseId: null, project: null, siteLimit: null };
578
+ for (let i = 0; i < args.length; i++) {
579
+ if (args[i] === "--help" || args[i] === "-h") { console.log(RELEASE_GET_HELP); process.exit(0); }
580
+ if (args[i] === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
581
+ if (args[i] === "--site-limit" && args[i + 1]) { opts.siteLimit = parsePositiveInt(args[++i], "--site-limit"); continue; }
582
+ if (!args[i].startsWith("-") && !opts.releaseId) opts.releaseId = args[i];
583
+ }
584
+ if (!opts.releaseId) {
585
+ fail({
586
+ code: "BAD_USAGE",
587
+ message: "Missing <release_id>.",
588
+ hint: "run402 deploy release get <release_id>",
589
+ });
590
+ }
591
+
592
+ const project = resolveProjectId(opts.project);
593
+
594
+ try {
595
+ const sdkOpts = { project };
596
+ if (opts.siteLimit !== null) sdkOpts.siteLimit = opts.siteLimit;
597
+ const release = await getSdk().deploy.getRelease(opts.releaseId, sdkOpts);
598
+ console.log(JSON.stringify({ status: "ok", release }, null, 2));
599
+ } catch (err) {
600
+ reportSdkError(err);
601
+ }
602
+ }
603
+
604
+ async function releaseActiveCmd(args) {
605
+ const opts = { project: null, siteLimit: null };
606
+ for (let i = 0; i < args.length; i++) {
607
+ if (args[i] === "--help" || args[i] === "-h") { console.log(RELEASE_ACTIVE_HELP); process.exit(0); }
608
+ if (args[i] === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
609
+ if (args[i] === "--site-limit" && args[i + 1]) { opts.siteLimit = parsePositiveInt(args[++i], "--site-limit"); continue; }
610
+ }
611
+
612
+ const project = resolveProjectId(opts.project);
613
+
614
+ try {
615
+ const sdkOpts = { project };
616
+ if (opts.siteLimit !== null) sdkOpts.siteLimit = opts.siteLimit;
617
+ const release = await getSdk().deploy.getActiveRelease(sdkOpts);
618
+ console.log(JSON.stringify({ status: "ok", release }, null, 2));
619
+ } catch (err) {
620
+ reportSdkError(err);
621
+ }
622
+ }
623
+
624
+ async function releaseDiffCmd(args) {
625
+ const opts = { project: null, from: null, to: null, limit: null };
626
+ for (let i = 0; i < args.length; i++) {
627
+ if (args[i] === "--help" || args[i] === "-h") { console.log(RELEASE_DIFF_HELP); process.exit(0); }
628
+ if (args[i] === "--project" && args[i + 1]) { opts.project = args[++i]; continue; }
629
+ if (args[i] === "--from" && args[i + 1]) { opts.from = args[++i]; continue; }
630
+ if (args[i] === "--to" && args[i + 1]) { opts.to = args[++i]; continue; }
631
+ if (args[i] === "--limit" && args[i + 1]) { opts.limit = parsePositiveInt(args[++i], "--limit"); continue; }
632
+ }
633
+ if (!opts.from || !opts.to) {
634
+ fail({
635
+ code: "BAD_USAGE",
636
+ message: "Missing --from or --to release target.",
637
+ hint: "run402 deploy release diff --from empty --to active",
638
+ });
639
+ }
640
+ if (opts.to === "empty") {
641
+ fail({
642
+ code: "BAD_USAGE",
643
+ message: "--to cannot be empty. Use active or a release id.",
644
+ details: { flag: "--to", value: opts.to },
645
+ });
646
+ }
647
+
648
+ const project = resolveProjectId(opts.project);
649
+
650
+ try {
651
+ const sdkOpts = { project, from: opts.from, to: opts.to };
652
+ if (opts.limit !== null) sdkOpts.limit = opts.limit;
653
+ const diff = await getSdk().deploy.diff(sdkOpts);
654
+ console.log(JSON.stringify({ status: "ok", diff }, null, 2));
655
+ } catch (err) {
656
+ reportSdkError(err);
657
+ }
658
+ }
659
+
660
+ function parsePositiveInt(value, flag) {
661
+ const parsed = Number(value);
662
+ if (!Number.isInteger(parsed) || parsed < 1) {
663
+ fail({
664
+ code: "BAD_USAGE",
665
+ message: `${flag} must be a positive integer.`,
666
+ details: { flag, value },
667
+ });
668
+ }
669
+ return parsed;
670
+ }
671
+
501
672
  // ─── Manifest → ReleaseSpec ──────────────────────────────────────────────────
502
673
 
503
674
  function mapManifestToReleaseSpec(spec) {
package/lib/deploy.mjs CHANGED
@@ -21,6 +21,7 @@ Subcommands (recommended for new manifests):
21
21
  run402 deploy resume <operation_id> resume a stuck operation
22
22
  run402 deploy list [--project <id>] list recent deploy operations
23
23
  run402 deploy events <operation_id> fetch event stream for an operation
24
+ run402 deploy release ... inspect release inventory and diffs
24
25
 
25
26
  Manifest format (JSON, v2 ReleaseSpec — recommended):
26
27
  {
@@ -303,13 +304,15 @@ export async function run(args) {
303
304
  // run402 deploy resume <op> → resume an activation_pending operation
304
305
  // run402 deploy list → list recent deploy operations
305
306
  // run402 deploy events <op> → fetch recorded event stream for an operation
307
+ // run402 deploy release ... → release inventory/diff observability
306
308
  // run402 deploy --manifest … → legacy bundle deploy (routes through v2)
307
309
  const sub = args[0];
308
310
  switch (sub) {
309
311
  case "apply":
310
312
  case "resume":
311
313
  case "list":
312
- case "events": {
314
+ case "events":
315
+ case "release": {
313
316
  const { runDeployV2 } = await import("./deploy-v2.mjs");
314
317
  await runDeployV2(sub, args.slice(1));
315
318
  return;
package/lib/sites.mjs CHANGED
@@ -299,7 +299,7 @@ async function deployDir(args) {
299
299
  const { plan } = await getSdk().deploy.plan({
300
300
  project: projectId,
301
301
  site: { replace: fileSet },
302
- });
302
+ }, { dryRun: true });
303
303
  console.log(JSON.stringify({
304
304
  status: "ok",
305
305
  dry_run: true,
@@ -308,6 +308,8 @@ async function deployDir(args) {
308
308
  operation_id: plan.operation_id,
309
309
  manifest_digest: plan.manifest_digest,
310
310
  diff: plan.diff,
311
+ warnings: plan.warnings,
312
+ expected_events: plan.expected_events ?? [],
311
313
  missing_content_count: plan.missing_content.filter((p) => !p.present).length,
312
314
  }, null, 2));
313
315
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.56.0",
3
+ "version": "1.57.1",
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": {
@@ -130,5 +130,5 @@ export { Deploy } from "./namespaces/deploy.js";
130
130
  export { Ci, CI_AUDIENCE, CI_GITHUB_ACTIONS_ISSUER, CI_GITHUB_ACTIONS_PROVIDER, DEFAULT_CI_DELEGATION_CHAIN_ID, V1_CI_ALLOWED_ACTIONS, V1_CI_ALLOWED_EVENTS_DEFAULT, assertCiDeployableSpec, buildCiDelegationResourceUri, buildCiDelegationStatement, normalizeCiDelegationValues, validateCiNonce, validateCiSubjectMatch, } from "./namespaces/ci.js";
131
131
  export { ScopedRun402 } from "./scoped.js";
132
132
  export type { CiAllowedAction, CiAllowedEvent, CiBindingErrorCode, CiBindingRow, CiCreateBindingInput, CiDelegationValues, CiDeployErrorCode, CiErrorCode, CiListBindingsInput, CiListBindingsResult, CiProvider, CiTokenExchangeErrorCode, CiTokenExchangeInput, CiTokenExchangeRequestBody, CiTokenExchangeResponse, NormalizedCiDelegationValues, ParsedDelegation, } from "./namespaces/ci.types.js";
133
- export type { ApplyOptions, CommitResponse, CommitStatus, ContentRef, ContentSource, DatabaseSpec, DeployDiff, DeployEvent, DeployOperation, DeployResult, ExposeManifest, FileSet, FsFileSource, FunctionSpec, FunctionsSpec, MigrationSpec, MissingContent, OperationSnapshot, OperationStatus, PaymentRequiredHint, PlanRequest, PlanResponse, ReleaseSpec, RouteSpec, SecretsSpec, SiteSpec, SmokeCheck, StartOptions, SubdomainsSpec, WarningEntry, } from "./namespaces/deploy.types.js";
133
+ export type { ApplyOptions, ActiveReleaseInventory, CommitResponse, CommitStatus, ContentRef, ContentSource, DatabaseSpec, DeployObservabilityWarningEntry, DeployDiff, DeployEvent, DeployOperation, DeployResult, ExposeManifest, FileSet, FsFileSource, FunctionSpec, FunctionsDiff, FunctionsSpec, LegacyWarningEntry, MigrationAppliedEntry, MigrationSpec, MissingContent, OperationSnapshot, OperationStatus, PaymentRequiredHint, PlanDiffEnvelope, PlanMigrationDiff, PlanRequest, PlanResponse, ReleaseDiffOptions, ReleaseDiffTarget, ReleaseDiffToTarget, ReleaseFunctionEntry, ReleaseInventory, ReleaseInventoryBase, ReleaseInventoryByIdOptions, ReleaseInventoryOptions, ReleaseInventoryStateKind, ReleaseInventoryStatus, ReleaseSnapshotInventory, ReleaseSpec, ReleaseToReleaseDiff, RouteSpec, SecretsSpec, SecretsDiff, SiteDiff, SitePathEntry, SiteSpec, SmokeCheck, StartOptions, SubdomainsSpec, SubdomainsDiff, WarningEntry, } from "./namespaces/deploy.types.js";
134
134
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@
19
19
  * behavior; this file is the implementation.
20
20
  */
21
21
  import type { Client } from "../kernel.js";
22
- import type { ApplyOptions, DeployEvent, DeployEventsResponse, DeployListResponse, DeployOperation, DeployResult, OperationSnapshot, PlanResponse, ReleaseSpec, StartOptions } from "./deploy.types.js";
22
+ import type { ApplyOptions, ActiveReleaseInventory, DeployEvent, DeployEventsResponse, DeployListResponse, DeployOperation, DeployResult, OperationSnapshot, PlanResponse, ReleaseDiffOptions, ReleaseInventory, ReleaseInventoryByIdOptions, ReleaseInventoryOptions, ReleaseSpec, ReleaseToReleaseDiff, StartOptions } from "./deploy.types.js";
23
23
  export declare class Deploy {
24
24
  private readonly client;
25
25
  constructor(client: Client);
@@ -41,6 +41,7 @@ export declare class Deploy {
41
41
  */
42
42
  plan(spec: ReleaseSpec, opts?: {
43
43
  idempotencyKey?: string;
44
+ dryRun?: boolean;
44
45
  }): Promise<{
45
46
  plan: PlanResponse;
46
47
  byteReaders: Map<string, ByteReader>;
@@ -113,17 +114,39 @@ export declare class Deploy {
113
114
  project: string;
114
115
  }): Promise<DeployEventsResponse>;
115
116
  /**
116
- * Fetch a release by id. (Endpoint may not be live in early v2 builds —
117
- * falls through to the gateway's standard 404 handling in that case.)
117
+ * Fetch a release inventory by id. The endpoint requires `apikey` auth, so
118
+ * pass the owning project id. `siteLimit` controls how many site paths the
119
+ * gateway includes before reporting `site.totals.paths`.
118
120
  */
119
- getRelease(releaseId: string): Promise<unknown>;
121
+ getRelease(opts: ReleaseInventoryByIdOptions): Promise<ReleaseInventory>;
122
+ getRelease(releaseId: string, opts: ReleaseInventoryOptions): Promise<ReleaseInventory>;
120
123
  /**
121
- * Diff two releases. (Endpoint may not be live in early v2 builds.)
124
+ * @deprecated Pass `{ project, releaseId }` or
125
+ * `getRelease(releaseId, { project })`. This legacy shape throws a
126
+ * `LocalError` before any request because the gateway now requires apikey
127
+ * auth scoped to a project.
122
128
  */
123
- diff(opts: {
124
- from: string;
125
- to: string;
126
- }): Promise<unknown>;
129
+ getRelease(releaseId: string, opts?: Partial<ReleaseInventoryOptions>): Promise<ReleaseInventory>;
130
+ /**
131
+ * Fetch the currently active release inventory for a project. If the project
132
+ * has not activated a release yet, the gateway returns an empty current-live
133
+ * inventory with `release_id: null`.
134
+ */
135
+ getActiveRelease(opts: ReleaseInventoryOptions): Promise<ActiveReleaseInventory>;
136
+ /**
137
+ * Diff two materialized release targets for a project. `from` may be
138
+ * `"empty"`, `"active"`, or a release id. `to` may be `"active"` or a
139
+ * release id; the gateway treats `"active"` as the current-live target.
140
+ */
141
+ diff(opts: ReleaseDiffOptions): Promise<ReleaseToReleaseDiff>;
142
+ /**
143
+ * @deprecated Pass `project` with the diff selectors. This legacy shape
144
+ * throws a `LocalError` before any request because the gateway now requires
145
+ * apikey auth scoped to a project.
146
+ */
147
+ diff(opts: Omit<ReleaseDiffOptions, "project"> & {
148
+ project?: string;
149
+ }): Promise<ReleaseToReleaseDiff>;
127
150
  }
128
151
  /**
129
152
  * A deferred byte reader: returns the bytes when called. The `label` is a
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAa3C,OAAO,KAAK,EACV,YAAY,EAKZ,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,YAAY,EAWZ,iBAAiB,EAGjB,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,mBAAmB,CAAC;AAyB3B,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;OAIG;IACG,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IA8B9E;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IAI3E;;;;OAIG;IACG,IAAI,CACR,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO,GACrC,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;KAAE,CAAC;IAIxE;;;;;OAKG;IACG,MAAM,CACV,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;KACxC,GACA,OAAO,CAAC,IAAI,CAAC;IAWhB;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;QACvC,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KACb,GACL,OAAO,CAAC,YAAY,CAAC;IAMxB;;;;;;;;;OASG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACtE,OAAO,CAAC,YAAY,CAAC;IAqBxB;;;;OAIG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAC9B,OAAO,CAAC,iBAAiB,CAAC;IAQ7B;;;;;;OAMG;IACG,IAAI,CACR,IAAI,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACjD,OAAO,CAAC,kBAAkB,CAAC;IAsB9B;;;;;;;;OAQG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,oBAAoB,CAAC;IAmBhC;;;OAGG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMrD;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;CAMjE;AA2nBD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"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"}
@@ -70,7 +70,8 @@ export class Deploy {
70
70
  }
71
71
  await uploadMissing(this.client, spec.project, plan.missing_content, byteReaders, emit);
72
72
  emit({ type: "commit.phase", phase: "validate", status: "started" });
73
- const commit = await commitInternal(this.client, plan.plan_id, opts.idempotencyKey);
73
+ const { planId } = requirePersistedPlan(plan, "applying deploy");
74
+ const commit = await commitInternal(this.client, planId, opts.idempotencyKey);
74
75
  return await pollUntilReady(this.client, commit, plan.diff, plan.warnings, emit, spec.project);
75
76
  }
76
77
  /**
@@ -86,7 +87,7 @@ export class Deploy {
86
87
  * response and a byte-reader map keyed by sha256 (used by `upload`).
87
88
  */
88
89
  async plan(spec, opts = {}) {
89
- return planInternal(this.client, spec, opts.idempotencyKey);
90
+ return planInternal(this.client, spec, opts.idempotencyKey, opts.dryRun);
90
91
  }
91
92
  /**
92
93
  * Low-level upload: ensure every ref the gateway reported as missing for
@@ -196,27 +197,57 @@ export class Deploy {
196
197
  throw translateDeployError(err, "events", null, operationId);
197
198
  }
198
199
  }
199
- /**
200
- * Fetch a release by id. (Endpoint may not be live in early v2 builds —
201
- * falls through to the gateway's standard 404 handling in that case.)
202
- */
203
- async getRelease(releaseId) {
204
- return this.client.request(`/deploy/v2/releases/${releaseId}`, {
205
- context: "fetching release",
206
- });
200
+ async getRelease(releaseIdOrOpts, maybeOpts = {}) {
201
+ const opts = typeof releaseIdOrOpts === "string"
202
+ ? { ...maybeOpts, releaseId: releaseIdOrOpts }
203
+ : releaseIdOrOpts;
204
+ if (!opts.project) {
205
+ throw new LocalError("r.deploy.getRelease requires a project id ({ project: 'prj_...', releaseId: 'rel_...' })", "fetching release inventory");
206
+ }
207
+ if (!opts.releaseId) {
208
+ throw new LocalError("r.deploy.getRelease requires a release id", "fetching release inventory");
209
+ }
210
+ const headers = await apikeyHeaders(this.client, opts.project);
211
+ return this.client.request(appendQuery(`/deploy/v2/releases/${encodeURIComponent(opts.releaseId)}`, {
212
+ site_limit: opts.siteLimit,
213
+ }), { headers, context: "fetching release inventory" });
207
214
  }
208
215
  /**
209
- * Diff two releases. (Endpoint may not be live in early v2 builds.)
216
+ * Fetch the currently active release inventory for a project. If the project
217
+ * has not activated a release yet, the gateway returns an empty current-live
218
+ * inventory with `release_id: null`.
210
219
  */
220
+ async getActiveRelease(opts) {
221
+ if (!opts?.project) {
222
+ throw new LocalError("r.deploy.getActiveRelease requires a project id ({ project: 'prj_...' })", "fetching active release inventory");
223
+ }
224
+ const headers = await apikeyHeaders(this.client, opts.project);
225
+ return this.client.request(appendQuery("/deploy/v2/releases/active", {
226
+ site_limit: opts.siteLimit,
227
+ }), { headers, context: "fetching active release inventory" });
228
+ }
211
229
  async diff(opts) {
230
+ if (!opts?.project) {
231
+ throw new LocalError("r.deploy.diff requires a project id ({ project: 'prj_...', from, to })", "diffing releases");
232
+ }
233
+ const headers = await apikeyHeaders(this.client, opts.project);
212
234
  const qs = new URLSearchParams({ from: opts.from, to: opts.to });
213
- return this.client.request(`/deploy/v2/releases/diff?${qs}`, {
214
- context: "diffing releases",
215
- });
235
+ if (opts.limit !== undefined)
236
+ qs.set("limit", String(opts.limit));
237
+ return this.client.request(`/deploy/v2/releases/diff?${qs.toString()}`, { headers, context: "diffing releases" });
216
238
  }
217
239
  }
240
+ function appendQuery(path, params) {
241
+ const qs = new URLSearchParams();
242
+ for (const [key, value] of Object.entries(params)) {
243
+ if (value !== undefined)
244
+ qs.set(key, String(value));
245
+ }
246
+ const query = qs.toString();
247
+ return query.length > 0 ? `${path}?${query}` : path;
248
+ }
218
249
  // ─── Internal pipeline ───────────────────────────────────────────────────────
219
- async function planInternal(client, spec, idempotencyKey) {
250
+ async function planInternal(client, spec, idempotencyKey, dryRun = false) {
220
251
  const ciCredentials = isCiClient(client);
221
252
  validateSpec(spec);
222
253
  if (ciCredentials)
@@ -228,7 +259,7 @@ async function planInternal(client, spec, idempotencyKey) {
228
259
  // needs `spec` in the body (with at least the project), so we keep a
229
260
  // minimal stub there.
230
261
  const inlineBody = { spec: normalized };
231
- if (idempotencyKey)
262
+ if (idempotencyKey && !dryRun)
232
263
  inlineBody.idempotency_key = idempotencyKey;
233
264
  const inlineBytes = new TextEncoder().encode(JSON.stringify(inlineBody)).byteLength;
234
265
  let body;
@@ -236,6 +267,15 @@ async function planInternal(client, spec, idempotencyKey) {
236
267
  body = inlineBody;
237
268
  }
238
269
  else {
270
+ if (dryRun) {
271
+ throw new Run402DeployError("Dry-run deploy planning requires an inline spec under the gateway body cap; the normalized deploy plan would require manifest_ref.", {
272
+ code: "DRY_RUN_REQUIRES_INLINE_SPEC",
273
+ phase: "validate",
274
+ resource: "manifest_ref",
275
+ retryable: false,
276
+ context: "planning deploy",
277
+ });
278
+ }
239
279
  if (ciCredentials) {
240
280
  throw new Run402DeployError("CI deploys must use inline specs under the gateway body cap; the normalized deploy plan would require manifest_ref.", {
241
281
  code: "forbidden_spec_field",
@@ -256,7 +296,7 @@ async function planInternal(client, spec, idempotencyKey) {
256
296
  }
257
297
  let plan;
258
298
  try {
259
- plan = normalizePlanResponse(await client.request("/deploy/v2/plans", {
299
+ plan = normalizePlanResponse(await client.request(dryRun ? "/deploy/v2/plans?dry_run=true" : "/deploy/v2/plans", {
260
300
  method: "POST",
261
301
  body,
262
302
  context: "planning deploy",
@@ -626,22 +666,24 @@ async function startInternal(client, spec, opts) {
626
666
  const resultPromise = (async () => {
627
667
  await uploadMissing(client, spec.project, plan.missing_content, byteReaders, emit);
628
668
  emit({ type: "commit.phase", phase: "validate", status: "started" });
629
- const commit = await commitInternal(client, plan.plan_id, opts.idempotencyKey);
669
+ const { planId } = requirePersistedPlan(plan, "starting deploy");
670
+ const commit = await commitInternal(client, planId, opts.idempotencyKey);
630
671
  return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project);
631
672
  })();
632
673
  // Avoid an unhandled-rejection at construction time. Consumers must call
633
674
  // .result() to actually observe the error.
634
675
  resultPromise.catch(() => { });
635
676
  let snapshot = null;
677
+ const { operationId } = requirePersistedPlan(plan, "starting deploy");
636
678
  const startHeaders = await apikeyHeaders(client, spec.project);
637
679
  const fetchSnapshot = async () => {
638
680
  if (snapshot && TERMINAL_STATUSES.includes(snapshot.status))
639
681
  return snapshot;
640
- snapshot = await client.request(`/deploy/v2/operations/${encodeURIComponent(plan.operation_id)}`, { headers: startHeaders, context: "fetching deploy operation" });
682
+ snapshot = await client.request(`/deploy/v2/operations/${encodeURIComponent(operationId)}`, { headers: startHeaders, context: "fetching deploy operation" });
641
683
  return snapshot;
642
684
  };
643
685
  return {
644
- id: plan.operation_id,
686
+ id: operationId,
645
687
  async snapshot() {
646
688
  return fetchSnapshot();
647
689
  },
@@ -757,11 +799,42 @@ function validateSpec(spec) {
757
799
  }
758
800
  function normalizePlanResponse(plan) {
759
801
  const raw = plan;
802
+ const warnings = Array.isArray(raw.warnings) ? raw.warnings : [];
803
+ if (raw.kind === "plan_response") {
804
+ const diff = {
805
+ is_noop: raw.is_noop,
806
+ summary: raw.summary,
807
+ warnings,
808
+ migrations: raw.migrations,
809
+ site: raw.site,
810
+ functions: raw.functions,
811
+ secrets: raw.secrets,
812
+ subdomains: raw.subdomains,
813
+ };
814
+ return {
815
+ ...plan,
816
+ warnings,
817
+ diff,
818
+ payment_required: raw.payment_required ?? null,
819
+ };
820
+ }
760
821
  return {
761
822
  ...plan,
762
- warnings: Array.isArray(raw.warnings) ? raw.warnings : [],
823
+ warnings,
763
824
  };
764
825
  }
826
+ function requirePersistedPlan(plan, context) {
827
+ if (plan.plan_id && plan.operation_id) {
828
+ return { planId: plan.plan_id, operationId: plan.operation_id };
829
+ }
830
+ throw new Run402DeployError("Dry-run plan responses cannot be uploaded or committed because they do not create plan or operation rows.", {
831
+ code: "DRY_RUN_PLAN_NOT_COMMITTABLE",
832
+ phase: "plan",
833
+ resource: "plan_id",
834
+ retryable: false,
835
+ context,
836
+ });
837
+ }
765
838
  function emitPlanWarnings(plan, emit) {
766
839
  if (plan.warnings.length > 0) {
767
840
  emit({ type: "plan.warnings", warnings: plan.warnings });