run402 4.105.5 → 4.105.6

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/up.mjs CHANGED
@@ -65,7 +65,8 @@ Options:
65
65
  commits directly, and a plan whose migrations are all
66
66
  already applied with an identical checksum is not
67
67
  rehearsed either (result.deploy.rehearsal says which:
68
- no_live_release / migrations_unchanged / no_migrations).
68
+ no_live_release / migrations_unchanged / no_migrations /
69
+ ci_session_unsupported).
69
70
  --repo-only Provision + scaffold the run402 remote + first push,
70
71
  and stop there — no deploy. The vault-only track
71
72
  (D8), composed through up instead of run402 repos
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "4.105.5",
3
+ "version": "4.105.6",
4
4
  "description": "CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"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"}
@@ -24,7 +24,7 @@ import { isGrantKeyCredentials } from "../grant-key-credentials.js";
24
24
  import { isKnownBinaryContent, isUtf8StringSource } from "../validation.js";
25
25
  import { assertCiDeployableSpec } from "./ci.js";
26
26
  import { ROUTE_PRICING_NETWORKS, ROUTE_HTTP_METHODS, isModernPlanMigrationDiff, normalizeDeployResolveRequest, } from "./deploy.types.js";
27
- import { ApiError, LocalError, NetworkError, PaymentRequired, Run402DeployError, Unauthorized, isTransferFreezeError, } from "../errors.js";
27
+ import { ApiError, LocalError, NetworkError, PaymentRequired, Run402DeployError, Unauthorized, isRun402Error, isTransferFreezeError, } from "../errors.js";
28
28
  import { assertAssetMetadata, assertExifPolicy, } from "./assets-validation.js";
29
29
  // ─── Constants ───────────────────────────────────────────────────────────────
30
30
  const PLAN_BODY_LIMIT_BYTES = 5 * 1024 * 1024;
@@ -36,6 +36,10 @@ const APPLY_RETRY_DEFAULT_MAX_RETRIES = 2;
36
36
  const APPLY_RETRY_BASE_DELAY_MS = 250;
37
37
  const APPLY_RETRY_MAX_DELAY_MS = 2_000;
38
38
  const APPLY_RETRY_JITTER_MS = 100;
39
+ const CONTENT_COMMIT_MAX_ATTEMPTS = 3;
40
+ const DEPLOY_COMMIT_MAX_ATTEMPTS = 3;
41
+ const DEPLOY_COMMIT_RETRY_BASE_DELAY_MS = 1_000;
42
+ const CONTENT_COMMIT_RETRY_BASE_DELAY_MS = 500;
39
43
  const URL_REFRESH_AT_MS = 50 * 60 * 1000;
40
44
  const SECRET_KEY_RE = /^[A-Z_][A-Z0-9_]{0,127}$/;
41
45
  const APPLY_SAFE_RETRY_CODES = new Set([
@@ -568,11 +572,9 @@ async function rehearseBeforeCommit(client, plan, planId, project, opts, emit) {
568
572
  const envelope = plan.rehearsal;
569
573
  if (!envelope || !envelope.available) {
570
574
  const reason = envelope?.reason ?? "no_migrations";
571
- return skip(reason === "no_live_release"
572
- ? "no_live_release"
573
- : reason === "migrations_unchanged"
574
- ? "migrations_unchanged"
575
- : "no_migrations");
575
+ return skip(reason === "no_live_release" || reason === "migrations_unchanged" || reason === "ci_session_unsupported"
576
+ ? reason
577
+ : "no_migrations");
576
578
  }
577
579
  // Named migrations that are all checksum-identical noops (already applied
578
580
  // to the live project) would run NOTHING on the branch, so a rehearsal
@@ -731,7 +733,7 @@ async function applyOnce(client, spec, opts, emit) {
731
733
  apply_plan_sha256: plan.vault?.apply_plan_sha256 ?? null,
732
734
  })
733
735
  : undefined;
734
- const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project_id, requiredPlan, vaultCommit), "applying deploy");
736
+ const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project_id, requiredPlan, vaultCommit, operationId), "applying deploy");
735
737
  const result = await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project_id, sliceKinds);
736
738
  result.rehearsal = rehearsal.block;
737
739
  // v1.48 unified-apply: thread the plan response's `asset_entries[]` back
@@ -1591,7 +1593,7 @@ function expandCronNumberPart(part, min, max) {
1591
1593
  }
1592
1594
  return values;
1593
1595
  }
1594
- async function commitInternal(client, planId, idempotencyKey, project, requiredPlan, vault) {
1596
+ async function commitInternal(client, planId, idempotencyKey, project, requiredPlan, vault, operationId) {
1595
1597
  try {
1596
1598
  const body = {};
1597
1599
  if (idempotencyKey)
@@ -1600,7 +1602,7 @@ async function commitInternal(client, planId, idempotencyKey, project, requiredP
1600
1602
  body.required_plan = requiredPlanToWire(requiredPlan);
1601
1603
  if (vault)
1602
1604
  body.vault = vault;
1603
- return await client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/commit`, {
1605
+ const send = () => client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/commit`, {
1604
1606
  method: "POST",
1605
1607
  body,
1606
1608
  // Write-approval scope: committing a deploy is `project.deploy` on this project.
@@ -1615,11 +1617,43 @@ async function commitInternal(client, planId, idempotencyKey, project, requiredP
1615
1617
  : {}),
1616
1618
  context: "committing deploy",
1617
1619
  });
1620
+ return await sendCommitRecoveringLostResponse(client, send, operationId, project);
1618
1621
  }
1619
1622
  catch (err) {
1620
1623
  throw translateDeployError(err, "commit", planId, null);
1621
1624
  }
1622
1625
  }
1626
+ /**
1627
+ * Send a deploy commit, recovering when a 502/503/504 or a dropped connection
1628
+ * loses the response. The commit may still have reached the gateway (a long
1629
+ * commit can outlive the connection that carried it), and a second commit
1630
+ * while the first is running would drive the state machine twice. So read the
1631
+ * operation first: once it has left `planning`/`uploading` the commit landed,
1632
+ * and the caller follows the operation; otherwise the commit never arrived and
1633
+ * is sent again. Without an operation id to read, the failure surfaces as is.
1634
+ */
1635
+ async function sendCommitRecoveringLostResponse(client, send, operationId, projectId) {
1636
+ for (let attempt = 1;; attempt++) {
1637
+ try {
1638
+ return await send();
1639
+ }
1640
+ catch (err) {
1641
+ if (!operationId || !projectId || !isTransientGatewayFailure(err) || attempt >= DEPLOY_COMMIT_MAX_ATTEMPTS)
1642
+ throw err;
1643
+ await sleep(DEPLOY_COMMIT_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
1644
+ let snapshot;
1645
+ try {
1646
+ snapshot = await client.request(`/apply/v1/operations/${encodeURIComponent(operationId)}`, { headers: await apikeyHeaders(client, projectId), context: "fetching deploy operation" });
1647
+ }
1648
+ catch {
1649
+ throw err;
1650
+ }
1651
+ if (snapshot.status !== "planning" && snapshot.status !== "uploading") {
1652
+ return { operation_id: operationId, status: "running" };
1653
+ }
1654
+ }
1655
+ }
1656
+ }
1623
1657
  async function uploadMissing(client, projectId, presence, byteReaders, emit) {
1624
1658
  // Surface CAS dedup hits so agents can distinguish "N files were already
1625
1659
  // present" from "nothing happened". The gateway reports both present and
@@ -1692,7 +1726,7 @@ async function uploadMissing(client, projectId, presence, byteReaders, emit) {
1692
1726
  // Plan-level finalize — marks the plan committed in the deploy_plans
1693
1727
  // table. Per-session promotion to CAS already happened in the loop
1694
1728
  // above; this call is the plan-level idempotency anchor.
1695
- await client.request(`/content/v1/plans/${encodeURIComponent(planRes.plan_id)}/commit`, { method: "POST", headers, body: {}, context: "committing content upload" });
1729
+ await commitContentPlanWithRetry(client, planRes.plan_id, headers);
1696
1730
  }
1697
1731
  async function uploadCoreContent(client, projectId, byteReaders, emit) {
1698
1732
  const entries = [...byteReaders.entries()].sort(([a], [b]) => a.localeCompare(b));
@@ -1721,6 +1755,35 @@ async function uploadCoreContent(client, projectId, byteReaders, emit) {
1721
1755
  });
1722
1756
  }
1723
1757
  }
1758
+ /**
1759
+ * Finalize a content plan, riding out a transient gateway failure. A 502/503/504
1760
+ * or a dropped connection means the load balancer or the network lost the
1761
+ * request, not that the gateway refused it, and the commit is safe to repeat: the
1762
+ * gateway re-promotes the same staged sessions. If a lost attempt had in fact
1763
+ * committed, the repeat answers 409 PLAN_ALREADY_COMMITTED, which is success.
1764
+ */
1765
+ async function commitContentPlanWithRetry(client, planId, headers) {
1766
+ for (let attempt = 1;; attempt++) {
1767
+ try {
1768
+ await client.request(`/content/v1/plans/${encodeURIComponent(planId)}/commit`, { method: "POST", headers, body: {}, context: "committing content upload" });
1769
+ return;
1770
+ }
1771
+ catch (err) {
1772
+ if (attempt > 1 && isRun402Error(err) && err.status === 409 && err.code === "PLAN_ALREADY_COMMITTED")
1773
+ return;
1774
+ if (!isTransientGatewayFailure(err) || attempt >= CONTENT_COMMIT_MAX_ATTEMPTS)
1775
+ throw err;
1776
+ await sleep(CONTENT_COMMIT_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
1777
+ }
1778
+ }
1779
+ }
1780
+ function isTransientGatewayFailure(err) {
1781
+ if (!isRun402Error(err))
1782
+ return false;
1783
+ if (err.kind === "network_error")
1784
+ return true;
1785
+ return err.status === 502 || err.status === 503 || err.status === 504;
1786
+ }
1724
1787
  async function uploadOneWithRetry(fetchFn, session, bytes) {
1725
1788
  const MAX_ATTEMPTS = 3;
1726
1789
  for (let attempt = 1;; attempt++) {
@@ -2100,8 +2163,8 @@ async function startInternal(client, spec, opts) {
2100
2163
  status: "started",
2101
2164
  ...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
2102
2165
  });
2103
- const { planId } = requirePersistedPlan(plan, "starting deploy");
2104
- const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project_id, opts.requiredPlan), "starting deploy");
2166
+ const { planId, operationId } = requirePersistedPlan(plan, "starting deploy");
2167
+ const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project_id, opts.requiredPlan, undefined, operationId), "starting deploy");
2105
2168
  return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project_id, sliceKinds);
2106
2169
  })();
2107
2170
  // Avoid an unhandled-rejection at construction time. Consumers must call
@@ -4034,7 +4097,7 @@ async function uploadInlineCas(client, projectId, bytes, contentType) {
4034
4097
  await uploadOne(client.fetch, session, bytes);
4035
4098
  // v1.48 unified-apply: per-session /storage/v1/uploads/:id/complete is
4036
4099
  // gone (404). The plan-level commit below promotes the session to CAS.
4037
- await client.request(`/content/v1/plans/${encodeURIComponent(planRes.plan_id)}/commit`, { method: "POST", headers, body: {}, context: "committing content upload" });
4100
+ await commitContentPlanWithRetry(client, planRes.plan_id, headers);
4038
4101
  }
4039
4102
  return { sha256, size: bytes.byteLength, contentType };
4040
4103
  }