run402-mcp 4.121.0 → 4.122.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.
Files changed (48) hide show
  1. package/dist/docs/llms-sdk.txt +34 -6
  2. package/package.json +3 -3
  3. package/schemas/release-spec.v1.json +4 -2
  4. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  5. package/sdk/dist/namespaces/deploy.js +87 -31
  6. package/sdk/dist/namespaces/deploy.js.map +1 -1
  7. package/sdk/dist/namespaces/deploy.types.d.ts +4 -2
  8. package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
  9. package/sdk/dist/namespaces/deploy.types.js +4 -0
  10. package/sdk/dist/namespaces/deploy.types.js.map +1 -1
  11. package/sdk/dist/namespaces/pay.d.ts +7 -0
  12. package/sdk/dist/namespaces/pay.d.ts.map +1 -1
  13. package/sdk/dist/namespaces/pay.js +5 -0
  14. package/sdk/dist/namespaces/pay.js.map +1 -1
  15. package/sdk/dist/namespaces/projects.d.ts +6 -2
  16. package/sdk/dist/namespaces/projects.d.ts.map +1 -1
  17. package/sdk/dist/namespaces/projects.js +46 -31
  18. package/sdk/dist/namespaces/projects.js.map +1 -1
  19. package/sdk/dist/namespaces/projects.types.d.ts +14 -8
  20. package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
  21. package/sdk/dist/node/_paid-stack.d.ts +8 -3
  22. package/sdk/dist/node/_paid-stack.d.ts.map +1 -1
  23. package/sdk/dist/node/_paid-stack.js.map +1 -1
  24. package/sdk/dist/node/lightning-paid-fetch.d.ts.map +1 -1
  25. package/sdk/dist/node/lightning-paid-fetch.js +2 -0
  26. package/sdk/dist/node/lightning-paid-fetch.js.map +1 -1
  27. package/sdk/dist/node/mpp-pay-executor.d.ts +40 -0
  28. package/sdk/dist/node/mpp-pay-executor.d.ts.map +1 -0
  29. package/sdk/dist/node/mpp-pay-executor.js +352 -0
  30. package/sdk/dist/node/mpp-pay-executor.js.map +1 -0
  31. package/sdk/dist/node/paid-fetch.d.ts +2 -1
  32. package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
  33. package/sdk/dist/node/paid-fetch.js +44 -18
  34. package/sdk/dist/node/paid-fetch.js.map +1 -1
  35. package/sdk/dist/node/payment-attempts.d.ts +2 -2
  36. package/sdk/dist/node/payment-attempts.d.ts.map +1 -1
  37. package/sdk/dist/node/payment-attempts.js +2 -2
  38. package/sdk/dist/node/payment-attempts.js.map +1 -1
  39. package/sdk/dist/node/payment-offers.d.ts +35 -0
  40. package/sdk/dist/node/payment-offers.d.ts.map +1 -0
  41. package/sdk/dist/node/payment-offers.js +145 -0
  42. package/sdk/dist/node/payment-offers.js.map +1 -0
  43. package/sdk/dist/stale-project-key.d.ts +14 -0
  44. package/sdk/dist/stale-project-key.d.ts.map +1 -0
  45. package/sdk/dist/stale-project-key.js +88 -0
  46. package/sdk/dist/stale-project-key.js.map +1 -0
  47. package/sdk/dist/type-contract.d.ts.map +1 -1
  48. package/sdk/dist/type-contract.js.map +1 -1
@@ -227,7 +227,31 @@ or the rail's ceiling, and refuses an entry on another network with
227
227
  `nostr+walletconnect://` URI, a bearer secret the MCP sandbox refuses with
228
228
  `SECRET_REQUIRES_CLI`) pays with that pairing on its node's network instead.
229
229
  The receipt of a Lightning payment reports the `lnbtc:` network, the payment
230
- hash as `transaction`, `amountMsat`, and no payer:
230
+ hash as `transaction`, `amountMsat`, and no payer.
231
+
232
+ On the `mpp` rail it pays a 402 that carries an MPP Tempo charge
233
+ (`WWW-Authenticate: Payment`, method `tempo`, intent `charge`) in pathUSD on
234
+ the first offered Tempo chain the wallet covers (price plus fee headroom),
235
+ applying `maxUsdMicros` to the selected challenge before anything is signed,
236
+ then retries the identical request with `Authorization: Payment`. Its receipt
237
+ reports `protocol: "mpp"`, `method: "tempo"`, the `eip155:4217` /
238
+ `eip155:42431` network, pathUSD as `asset`, the Tempo transaction hash as
239
+ `transaction`, and the seller's decoded `Payment-Receipt` as
240
+ `evidence.protocolReceipt`; `offer.status` and `merchantReceipt.status` are
241
+ `"unavailable"` (MPP carries no wallet-rooted merchant evidence, so
242
+ `requireReceipt` fails `MERCHANT_RECEIPT_REQUIRED` before signing). An x402
243
+ receipt reports `protocol: "x402"`, `method: "exact"`. Over MPP a payment's
244
+ identity is its credential, not the caller key: `idempotencyKey` is forwarded
245
+ for correlation only, and an ambiguous or pending outcome is resolved by
246
+ repeating the identical request on the same SDK instance, which re-presents
247
+ the same credential; the seller resolves it to the original payment
248
+ (`deduplicated: true`, `fundsMoved: false`) and never charges twice.
249
+
250
+ When the wallet's rail cannot pay anything the 402 offers, the buyer fails
251
+ `PAYMENT_NETWORK_UNSUPPORTED` before signing, with `details.offers[]` listing
252
+ every offer it saw (`{ protocol, method, intent?, network }`, x402 entries and
253
+ MPP challenges alike) and a `run402 init <rail> --switch-rail` next action
254
+ naming the rail that pays the first offer:
231
255
 
232
256
  ```ts
233
257
  import { run402 } from "@run402/sdk/node";
@@ -259,7 +283,8 @@ validity, settlement, payer, transaction, and signer relationship. Branch on
259
283
  lifetime/key-reuse codes, or `PAYMENT_SETTLEMENT_FAILED`. The error preserves
260
284
  `fundsMoved`, `paymentId`, intent/delivery events, and canonical `nextActions`.
261
285
  Successful results preserve `paymentId`, `deduplicated`, `fundsMoved`,
262
- `delivery`, `settledAt`, and `intentState` when supplied.
286
+ `delivery`, `settledAt`, and `intentState` when supplied. Every receipt names
287
+ the `protocol` (`x402` | `mpp`) and `method` (`exact` | `tempo`) that paid.
263
288
  A seller may settle and then deliberately answer a non-2xx (for example a
264
289
  400 refusing the paid action). When that response carries a valid standard
265
290
  `PAYMENT-RESPONSE` receipt for the accepted challenge, `r.pay.fetch` returns a
@@ -706,9 +731,9 @@ const info = await r.projects.info(projectId);
706
731
 
707
732
  ## Rehearsals, snapshots, and branches
708
733
 
709
- Rehearsal is automatic inside `apply()` and `r.up()`: when the plan's `rehearsal.available` is true (migrations, and the project has a live release), the plan is rehearsed on a contained branch and committed only on a passing report, bound to the report's `required_plan`. The result carries `rehearsal: { status: "passed", report, operation_id, branch_project_id }`, or `{ status: "skipped", reason: "no_live_release" | "no_migrations" | "migrations_unchanged" | "ci_session_unsupported" | "disabled" | "reviewed_plan" | "unsupported" }` (`migrations_unchanged`: every migration is already applied with an identical checksum — `plan.migrations.new` is empty — so nothing is rehearsed and a page-only redeploy ships in seconds; `ci_session_unsupported`: the plan was made by a CI session, which the gateway does not rehearse, so it commits directly). A failed rehearsal throws `Run402DeployError` with `code: "REHEARSAL_FAILED"` (the report is in `body.rehearsal`); nothing is committed. Pass `{ noRehearse: true }` to skip it. `onEvent` sees `rehearsal.started`, `rehearsal.finished`, and `rehearsal.skipped`.
734
+ Rehearsal is automatic inside `apply()` and `r.up()`: when the plan's `rehearsal.available` is true (migrations, and the project has a live release), the plan is rehearsed on a contained branch and committed only on a passing report, bound to the report's `required_plan`. The result carries `rehearsal: { status: "passed", report, operation_id, branch_project_id }`, or `{ status: "skipped", reason: "no_live_release" | "no_migrations" | "migrations_unchanged" | "ci_session_unsupported" | "disabled" | "reviewed_plan" | "unsupported" }` (`migrations_unchanged`: every migration is already applied with an identical checksum — `plan.migrations.new` is empty — so nothing is rehearsed and a page-only redeploy ships in seconds; `ci_session_unsupported`: the plan was made by a CI session, which the gateway does not rehearse, so it commits directly). A failed rehearsal throws `Run402DeployError` with `code: "REHEARSAL_FAILED"` (the report is in `body.rehearsal`); nothing is committed. Pass `{ noRehearse: true }` to skip it. The rehearsal runs on the gateway as an operation, not inside one request: the SDK starts it with `Prefer: respond-async` and polls the operation until its report is there, so a slow snapshot never holds a request open; a rehearsal whose gateway task stopped before it finished throws `OPERATION_INTERRUPTED` (retryable, `operationId` set, the branch it left in `body.details.branch_project_id`). `onEvent` sees `rehearsal.started`, the recorded `rehearsal.phase` events, `rehearsal.finished`, and `rehearsal.skipped`.
710
735
 
711
- The primitive is still there for experts: `r.project(id).apply.rehearse(planId, { teardown })` rehearses an already-persisted plan without committing (a project with no live release rehearses on an EMPTY branch — never a refusal).
736
+ The primitive is still there for experts: `r.project(id).apply.rehearse(planId, { teardown })` rehearses an already-persisted plan without committing and polls its operation for the report (a project with no live release rehearses on an EMPTY branch — never a refusal).
712
737
 
713
738
  Manual restore points are exposed as `r.snapshots` and the scoped `r.project(id).snapshots`. `restorePlan()` is the no-mutation loss-statement step; `restore()` requires the confirm token from the plan and performs the atomic offline-materialize-then-flip restore. Auth users/passkeys are restored only with `{ includeAuth: true }`; sessions and tokens are never restored. Give a restore point a name with `create(projectId, { label: "before engine upgrade", metadata })`; labels live outside the project's database, so they survive restores. `{ release: "snapshot" }` on both `restorePlan` and `restore` also puts back the release that was live at capture (and re-deploys every function that differs to its capture-time code). A deployed function can do all of this for its own project with the `@run402/functions` `snapshots` namespace and its service key.
714
739
 
@@ -1335,7 +1360,10 @@ The `Run402` class exposes focused namespaces. Click into the SDK source for ful
1335
1360
  r.pay.fetch(url, init?, { maxUsdMicros?, idempotencyKey?, requireReceipt?, maxSats?, lightningPairing? }): Promise<PayFetchResult>
1336
1361
  ```
1337
1362
 
1338
- Node automatically supplies the configured wallet/signer. Isomorphic hosts
1363
+ Node automatically supplies the configured wallet/signer and pays on its rail:
1364
+ x402 `exact` on Base, Lightning on the `lightning` rail, and an MPP Tempo charge
1365
+ in pathUSD on the `mpp` rail. The receipt names `protocol` (`x402` | `mpp`) and
1366
+ `method` (`exact` | `tempo`). Isomorphic hosts
1339
1367
  may inject `payExecutor` in `Run402Options`; without one, unpriced URLs pass
1340
1368
  through and a 402 fails locally with `PAYMENT_WALLET_UNFUNDED`.
1341
1369
 
@@ -1406,7 +1434,7 @@ demoteUser(id, email): Promise<void>
1406
1434
 
1407
1435
  `r.projects.setRepoName(projectId, name)` sets or renames the project's per-org-unique, ADDRESS-form name (`POST /projects/v1/:id/repo-name`, repo-first-onramp design D6, task 4.2) — the `<name>` half of `run402::<org-slug>/<name>` — and returns `{ project_id, repo_name, previous_repo_name }`. Distinct from `rename` above (the free-text display name, unchanged): the address-form name is charset-restricted (`[a-z0-9-]`, ≤63 chars) and per-org-unique. No fee, unlike the org-slug claim. Same authority as `rename`. Scoped form: `r.project(id).setRepoName(name)`.
1408
1436
 
1409
- `r.projects.getUsage(id)` still surfaces `effective_status` and `organization_lifecycle_state` because that endpoint scopes to a single project and the derivation collapses per-project `archived_at` / `deleted_at` together with the organization's lifecycle.
1437
+ `r.projects.getUsage(id)` (`GET /projects/v1/admin/:project_id/usage`, service key) returns a `UsageReport`: `project_id`, `tier`, `org_id` (`| null`), `api_calls`, `api_calls_limit`, `storage_bytes`, `storage_limit_bytes`, `storage_limit` (human string, e.g. `"250 MB"`), `status` (the derived effective status), `lease_expires_at`, and `lease_perpetual`. `lease_expires_at` is the owning organization's ISO-8601 lease expiry, and `null` when the lease is perpetual (`lease_perpetual: true`) or the project has no organization; `lease_perpetual` is `false` otherwise. The lease fields match `r.tier.status()`.
1410
1438
 
1411
1439
  ### `r.project(id).apply`
1412
1440
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402-mcp",
3
- "version": "4.121.0",
3
+ "version": "4.122.1",
4
4
  "packageManager": "npm@11.19.0",
5
5
  "mcpName": "com.run402/mcp",
6
6
  "description": "MCP server 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.",
@@ -32,10 +32,10 @@
32
32
  "test:skill": "node scripts/build-agent-skills-index.mjs --check && node --test --import tsx SKILL.test.ts buzz/setup.test.mjs buzz/helper.test.mjs buzz/package.test.mjs scripts/build-agent-skills-index.test.mjs",
33
33
  "test:vault-surface": "node scripts/build-vault-surface.mjs --check && node --test scripts/build-vault-surface.test.mjs",
34
34
  "test:buzz-installer": "node buzz/install-smoke.mjs",
35
- "test:sync": "node --test --import tsx sync.test.ts examples/tenant-x402-wallet-stats/example.test.mjs examples/static-config-js/example.test.mjs",
35
+ "test:sync": "node --test --import tsx sync.test.ts scripts/types-node-engines.test.mjs examples/tenant-x402-wallet-stats/example.test.mjs examples/static-config-js/example.test.mjs",
36
36
  "test:run402-app-schema-drift": "node scripts/check-run402-app-schema-drift.mjs",
37
37
  "test:docs": "node scripts/check-typed-config-docs.mjs && npm run check:docs --workspace=@run402/sdk -- --skip-build && npm run test:docs:quality",
38
- "test": "npm run build && node scripts/build-agent-skills-index.mjs --check && node scripts/build-vault-surface.mjs --check && node --experimental-test-module-mocks --test --import tsx SKILL.test.ts sync.test.ts buzz/setup.test.mjs buzz/helper.test.mjs buzz/package.test.mjs scripts/build-agent-skills-index.test.mjs scripts/build-agent-flat-docs.test.mjs scripts/build-vault-surface.test.mjs examples/tenant-x402-wallet-stats/example.test.mjs examples/static-config-js/example.test.mjs 'core/src/**/*.test.ts' 'sdk/src/**/*.test.ts' 'src/**/*.test.ts' && node --test cli-core-target.test.mjs mcp-vendored-sdk-imports.test.mjs scripts/publish-idempotent.test.mjs && node --experimental-test-module-mocks --test cli-up-argv.test.mjs cli-up-repo-compose.test.mjs cli-repos-surface.test.mjs cli-repos-naming.test.mjs cli-projects-vault-scaffold.test.mjs cli-identity-link.test.mjs cli-identity-link-matrix.test.mjs cli-redeem.test.mjs cli-rooms-context-session-key.test.mjs cli-messages-wait.test.mjs cli-rooms-invite-key-leak.test.mjs cli-rooms-join-arrival.test.mjs cli/lib/buzz.test.mjs && node --test cli-help-listing.test.mjs cli-module-references.test.mjs cli-output-contract.test.mjs cli-json-noop-contract.test.mjs cli-e2e.test.mjs cli-help.test.mjs cli-subscriptions-help.test.mjs cli-provision-active.test.mjs cli-typed-config-modes.test.mjs cli-argv.test.mjs cli-repos-naming.test.mjs cli-conventions-gate.test.mjs cli-doctor.test.mjs cli-rest-diagnostics.test.mjs cli-credentials.test.mjs paid-stack-deps.test.mjs settlement-disclosure.test.mjs cli-suggestions-gate.test.mjs cli-env.test.mjs cli-wallets.test.mjs cli-org.test.mjs cli-org-context.test.mjs cli-image-org.test.mjs cli-harness-context.test.mjs cli-ci.test.mjs cli-snapshots.test.mjs cli-deploy-ci.test.mjs cli-login-loopback.test.mjs cli-vault-remote-helper.test.mjs cli-vault-daemon.test.mjs cli-deploy-vault-lane.test.mjs cli/lib/buzz-doctor.test.mjs cli/lib/diagnostic-telemetry.test.mjs cli/lib/doctor-source-scan.test.mjs cli/lib/errors.test.mjs cli/lib/argparse.test.mjs cli/lib/path-lookup.test.mjs cli/lib/pay.test.mjs cli/lib/up.test.mjs cli/lib/deploy-rehearse-discovery.test.mjs cli/lib/update-check.test.mjs cli-bootstrap-next-actions.test.mjs cli-sdk-errors-room-invite-hint.test.mjs && npm run test:docs",
38
+ "test": "npm run build && node scripts/build-agent-skills-index.mjs --check && node scripts/build-vault-surface.mjs --check && node --experimental-test-module-mocks --test --import tsx SKILL.test.ts sync.test.ts buzz/setup.test.mjs buzz/helper.test.mjs buzz/package.test.mjs scripts/build-agent-skills-index.test.mjs scripts/build-agent-flat-docs.test.mjs scripts/build-vault-surface.test.mjs scripts/types-node-engines.test.mjs examples/tenant-x402-wallet-stats/example.test.mjs examples/static-config-js/example.test.mjs 'core/src/**/*.test.ts' 'sdk/src/**/*.test.ts' 'src/**/*.test.ts' && node --test cli-core-target.test.mjs mcp-vendored-sdk-imports.test.mjs scripts/publish-idempotent.test.mjs && node --experimental-test-module-mocks --test cli-up-argv.test.mjs cli-up-repo-compose.test.mjs cli-repos-surface.test.mjs cli-repos-naming.test.mjs cli-projects-vault-scaffold.test.mjs cli-identity-link.test.mjs cli-identity-link-matrix.test.mjs cli-redeem.test.mjs cli-rooms-context-session-key.test.mjs cli-messages-wait.test.mjs cli-rooms-invite-key-leak.test.mjs cli-rooms-join-arrival.test.mjs cli/lib/buzz.test.mjs && node --test cli-help-listing.test.mjs cli-module-references.test.mjs cli-output-contract.test.mjs cli-json-noop-contract.test.mjs cli-e2e.test.mjs cli-help.test.mjs cli-subscriptions-help.test.mjs cli-provision-active.test.mjs cli-typed-config-modes.test.mjs cli-argv.test.mjs cli-repos-naming.test.mjs cli-conventions-gate.test.mjs cli-doctor.test.mjs cli-rest-diagnostics.test.mjs cli-credentials.test.mjs paid-stack-deps.test.mjs settlement-disclosure.test.mjs cli-suggestions-gate.test.mjs cli-env.test.mjs cli-wallets.test.mjs cli-org.test.mjs cli-org-context.test.mjs cli-image-org.test.mjs cli-harness-context.test.mjs cli-ci.test.mjs cli-snapshots.test.mjs cli-deploy-ci.test.mjs cli-login-loopback.test.mjs cli-vault-remote-helper.test.mjs cli-vault-daemon.test.mjs cli-deploy-vault-lane.test.mjs cli/lib/buzz-doctor.test.mjs cli/lib/diagnostic-telemetry.test.mjs cli/lib/doctor-source-scan.test.mjs cli/lib/errors.test.mjs cli/lib/argparse.test.mjs cli/lib/path-lookup.test.mjs cli/lib/pay.test.mjs cli/lib/up.test.mjs cli/lib/deploy-rehearse-discovery.test.mjs cli/lib/update-check.test.mjs cli-bootstrap-next-actions.test.mjs cli-sdk-errors-room-invite-hint.test.mjs && npm run test:docs",
39
39
  "test:e2e": "npm run build && node --test cli-core-target.test.mjs && node --experimental-test-module-mocks --test cli-repos-surface.test.mjs cli-repos-naming.test.mjs cli-up-repo-compose.test.mjs cli-projects-vault-scaffold.test.mjs cli-identity-link.test.mjs cli-identity-link-matrix.test.mjs cli-redeem.test.mjs cli-rooms-context-session-key.test.mjs cli-messages-wait.test.mjs cli-rooms-invite-key-leak.test.mjs cli-rooms-join-arrival.test.mjs && node --test cli-help-listing.test.mjs cli-module-references.test.mjs cli-output-contract.test.mjs cli-json-noop-contract.test.mjs cli-e2e.test.mjs cli-help.test.mjs cli-subscriptions-help.test.mjs cli-provision-active.test.mjs cli-typed-config-modes.test.mjs cli-argv.test.mjs cli-repos-naming.test.mjs cli-conventions-gate.test.mjs cli-doctor.test.mjs cli-rest-diagnostics.test.mjs cli-credentials.test.mjs paid-stack-deps.test.mjs settlement-disclosure.test.mjs cli-suggestions-gate.test.mjs cli-env.test.mjs cli-wallets.test.mjs cli-org.test.mjs cli-org-context.test.mjs cli-image-org.test.mjs cli-harness-context.test.mjs cli-ci.test.mjs cli-snapshots.test.mjs cli-deploy-ci.test.mjs cli-login-loopback.test.mjs cli-vault-remote-helper.test.mjs cli-vault-daemon.test.mjs cli-deploy-vault-lane.test.mjs cli/lib/buzz-doctor.test.mjs cli/lib/diagnostic-telemetry.test.mjs cli/lib/doctor-source-scan.test.mjs cli/lib/errors.test.mjs cli/lib/path-lookup.test.mjs cli/lib/up.test.mjs cli/lib/update-check.test.mjs cli-bootstrap-next-actions.test.mjs cli-sdk-errors-room-invite-hint.test.mjs",
40
40
  "test:help": "npm run build && node --test cli-help.test.mjs",
41
41
  "test:integration": "node --test --import tsx core/src/siwx-integration.integ.ts",
@@ -751,10 +751,12 @@
751
751
  "mainnet",
752
752
  "testnet",
753
753
  "lightning",
754
- "lightning-testnet"
754
+ "lightning-testnet",
755
+ "tempo",
756
+ "tempo-testnet"
755
757
  ]
756
758
  },
757
- "description": "Omit to accept production mainnet only. Include testnet explicitly for testnet payments. `lightning` / `lightning-testnet` sell for sats over x402 `exact` on `lnbtc`, settled to the org's Lightning receiver (`run402 orgs lightning-receiver set`); `receipt` cannot be combined with them."
759
+ "description": "Omit to accept production mainnet only. Include testnet explicitly for testnet payments. `lightning` / `lightning-testnet` sell for sats over x402 `exact` on `lnbtc`, settled to the org's Lightning receiver (`run402 orgs lightning-receiver set`). `tempo` / `tempo-testnet` also take an MPP Tempo charge in pathUSD on Tempo mainnet (chain 4217) / Moderato (42431), paid to the org's payout address. `receipt` cannot be combined with Lightning or Tempo networks."
758
760
  }
759
761
  }
760
762
  },
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAwB3C,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EAQtB,WAAW,EACX,oBAAoB,EAEpB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EAIvB,sBAAsB,EACtB,oBAAoB,EAUpB,iBAAiB,EAGjB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,2BAA2B,EAC3B,uBAAuB,EACvB,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAGlB,YAAY,EAEb,MAAM,mBAAmB,CAAC;AA4G3B,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;IAmD9E;;;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;QACJ,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC;QACvC,YAAY,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,eAAe,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5D,sEAAsE;QACtE,KAAK,CAAC,EAAE,oBAAoB,CAAC;KACzB,GACL,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;KAAE,CAAC;IASxE;;;;;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;QACjB,YAAY,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,eAAe,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5D;;;;WAIG;QACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;KAC3B,GACL,OAAO,CAAC,YAAY,CAAC;IASlB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAc3F;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,aAAa,CAAC;IA2CzB;;;;OAIG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAC9B,OAAO,CAAC,iBAAiB,CAAC;IAmB7B;;;;;;OAMG;IACG,IAAI,CACR,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAC/B,OAAO,CAAC,kBAAkB,CAAC;IA6B9B;;;;;;;;OAQG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,oBAAoB,CAAC;IAmBhC;;;;OAIG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,mBAAmB,CAAC;IAyB/B;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,uBAAuB,CAAC;IAoCnC;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6B9E;;;;OAIG;IACG,gBAAgB,CACpB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IAqBlC;;;;OAIG;IACG,IAAI,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA+BnE;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAW1E;AA+vED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;iEAG6D;IAC7D,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;CACvC;AAi+ED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrD"}
@@ -33,6 +33,9 @@ const COMMIT_POLL_INITIAL_MS = 1_000;
33
33
  const COMMIT_POLL_MAX_MS = 30_000;
34
34
  const COMMIT_POLL_BACKOFF_AFTER_MS = 30_000;
35
35
  const COMMIT_POLL_TIMEOUT_MS = 10 * 60 * 1000;
36
+ const REHEARSAL_POLL_INITIAL_MS = 1_000;
37
+ const REHEARSAL_POLL_MAX_MS = 10_000;
38
+ const REHEARSAL_POLL_TIMEOUT_MS = 30 * 60 * 1000;
36
39
  const APPLY_RETRY_DEFAULT_MAX_RETRIES = 2;
37
40
  const APPLY_RETRY_BASE_DELAY_MS = 250;
38
41
  const APPLY_RETRY_MAX_DELAY_MS = 2_000;
@@ -221,25 +224,7 @@ export class Deploy {
221
224
  const body = {};
222
225
  if (opts.teardown !== undefined)
223
226
  body.teardown = opts.teardown;
224
- try {
225
- return await this.client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/rehearse`, {
226
- method: "POST",
227
- body,
228
- ...(opts.project
229
- ? {
230
- authMeta: {
231
- method: "deploy.rehearse",
232
- capability: "project.deploy",
233
- target: { project_id: opts.project },
234
- },
235
- }
236
- : {}),
237
- context: "rehearsing deploy plan",
238
- });
239
- }
240
- catch (err) {
241
- throw translateDeployError(err, "rehearsal", planId, null);
242
- }
227
+ return await requestRehearsal(this.client, planId, body, opts.project);
243
228
  }
244
229
  /**
245
230
  * Resume an operation in `schema_settling` or `activation_pending`. The
@@ -610,18 +595,7 @@ async function rehearseBeforeCommit(client, plan, planId, project, opts, emit) {
610
595
  if (unchanged)
611
596
  return skip(unchanged);
612
597
  emit({ type: "rehearsal.started", planId });
613
- let rehearsed;
614
- try {
615
- rehearsed = await client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/rehearse`, {
616
- method: "POST",
617
- body: {},
618
- authMeta: { method: "deploy.rehearse", capability: "project.deploy", target: { project_id: project } },
619
- context: "rehearsing deploy plan",
620
- });
621
- }
622
- catch (err) {
623
- throw translateDeployError(err, "rehearsal", planId, null);
624
- }
598
+ const rehearsed = await requestRehearsal(client, planId, {}, project, emit);
625
599
  const report = rehearsed.report;
626
600
  emit({
627
601
  type: "rehearsal.finished",
@@ -653,6 +627,85 @@ async function rehearseBeforeCommit(client, plan, planId, project, opts, emit) {
653
627
  ...(bound ? { requiredPlan: { planId: bound.plan_id, planFingerprint: bound.plan_fingerprint } } : {}),
654
628
  };
655
629
  }
630
+ /**
631
+ * Start a rehearsal and return its report. The gateway runs a rehearsal as an
632
+ * operation, detached from the request (a snapshot can take minutes). With a
633
+ * project to poll as, the request asks for the asynchronous shape
634
+ * (`Prefer: respond-async`), gets the operation at once, and polls it until
635
+ * the report is there, relaying its recorded `rehearsal.phase` events; every
636
+ * failure from then on carries the rehearsal's operation id. A gateway that
637
+ * answers with the report inline is used as is, and without a project the
638
+ * response waits for the report.
639
+ */
640
+ async function requestRehearsal(client, planId, body, project, emit) {
641
+ let started;
642
+ try {
643
+ started = await client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/rehearse`, {
644
+ method: "POST",
645
+ body,
646
+ ...(project
647
+ ? {
648
+ headers: { Prefer: "respond-async" },
649
+ authMeta: {
650
+ method: "deploy.rehearse",
651
+ capability: "project.deploy",
652
+ target: { project_id: project },
653
+ },
654
+ }
655
+ : {}),
656
+ context: "rehearsing deploy plan",
657
+ });
658
+ }
659
+ catch (err) {
660
+ throw translateDeployError(err, "rehearsal", planId, null);
661
+ }
662
+ if (started.report || !project)
663
+ return started;
664
+ return await pollRehearsal(client, planId, started.operation_id, project, emit);
665
+ }
666
+ async function pollRehearsal(client, planId, operationId, project, emit) {
667
+ const pollUrl = `/apply/v1/operations/${encodeURIComponent(operationId)}`;
668
+ const headers = await apikeyHeaders(client, project);
669
+ const start = Date.now();
670
+ let interval = REHEARSAL_POLL_INITIAL_MS;
671
+ let eventCursor = null;
672
+ let eventsSupported = Boolean(emit);
673
+ for (;;) {
674
+ await sleep(interval);
675
+ let snapshot;
676
+ try {
677
+ // A poll lost to a 502/503/504 (a gateway rollout) says nothing about
678
+ // the rehearsal, which keeps running on the gateway; read it again.
679
+ snapshot = await requestWithTransientRetry(() => client.request(pollUrl, { headers, context: "polling rehearsal operation" }));
680
+ }
681
+ catch (err) {
682
+ throw translateDeployError(err, "rehearsal", planId, operationId);
683
+ }
684
+ if (emit && eventsSupported) {
685
+ const recorded = await emitRecordedOperationEvents(client, operationId, headers, eventCursor, emit);
686
+ eventsSupported = recorded.supported;
687
+ eventCursor = recorded.cursor;
688
+ }
689
+ if (TERMINAL_STATUSES.includes(snapshot.status)) {
690
+ if (snapshot.rehearsal_report) {
691
+ return { operation_id: operationId, status: snapshot.status, poll_url: pollUrl, report: snapshot.rehearsal_report };
692
+ }
693
+ throw translateGatewayError(snapshot.error, "rehearsal", planId, operationId);
694
+ }
695
+ if (Date.now() - start > REHEARSAL_POLL_TIMEOUT_MS) {
696
+ throw new Run402DeployError(`Timed out waiting for rehearsal operation ${operationId} to finish`, {
697
+ code: "INTERNAL_ERROR",
698
+ phase: "rehearsal",
699
+ retryable: true,
700
+ operationId,
701
+ planId,
702
+ status: 504,
703
+ context: "polling rehearsal",
704
+ });
705
+ }
706
+ interval = Math.min(Math.floor(interval * 1.5), REHEARSAL_POLL_MAX_MS);
707
+ }
708
+ }
656
709
  /**
657
710
  * `"migrations_unchanged"` when the plan carries modern migration buckets and
658
711
  * none are new (all noop); `"no_migrations"` when the buckets are both empty;
@@ -2904,6 +2957,9 @@ function validateRoutePricing(pricing, resource, targetType) {
2904
2957
  if (obj.receipt === "on_fulfillment" && hasLightning) {
2905
2958
  throw invalidRouteSpec(`ReleaseSpec.${resource}.pricing.receipt covers EVM entries only; merchant evidence is not issued for Lightning networks`, `${resource}.pricing.receipt`);
2906
2959
  }
2960
+ if (obj.receipt === "on_fulfillment" && networks.some((network) => network === "tempo" || network === "tempo-testnet")) {
2961
+ throw invalidRouteSpec(`ReleaseSpec.${resource}.pricing.receipt covers x402 EVM entries only; merchant evidence is not issued for Tempo`, `${resource}.pricing.receipt`);
2962
+ }
2907
2963
  }
2908
2964
  /** The declared pricing networks, validated; `["mainnet"]` when omitted. */
2909
2965
  function validateRoutePricingNetworks(networks, resource) {