@manifest-network/manifest-agent-core 0.14.0 → 0.15.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/dist/close-lease.d.ts.map +1 -1
- package/dist/close-lease.js +15 -3
- package/dist/close-lease.js.map +1 -1
- package/dist/deploy-app.d.ts +2 -2
- package/dist/deploy-app.d.ts.map +1 -1
- package/dist/deploy-app.js +82 -35
- package/dist/deploy-app.js.map +1 -1
- package/dist/deploy-app.test-d.d.ts +1 -0
- package/dist/deploy-app.test-d.js +11 -0
- package/dist/deploy-app.test-d.js.map +1 -0
- package/dist/guarded-fetch.d.ts +2 -0
- package/dist/guarded-fetch.js +2 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/dist/internals/cancellation.d.ts +57 -0
- package/dist/internals/cancellation.d.ts.map +1 -0
- package/dist/internals/cancellation.js +79 -0
- package/dist/internals/cancellation.js.map +1 -0
- package/dist/internals/inspect-image.js +1 -1
- package/dist/internals/inspect-image.js.map +1 -1
- package/dist/internals/render-intent-recap.d.ts +13 -11
- package/dist/internals/render-intent-recap.d.ts.map +1 -1
- package/dist/internals/render-intent-recap.js +5 -4
- package/dist/internals/render-intent-recap.js.map +1 -1
- package/dist/internals/spec-normalize.d.ts +34 -28
- package/dist/internals/spec-normalize.d.ts.map +1 -1
- package/dist/internals/spec-normalize.js +28 -22
- package/dist/internals/spec-normalize.js.map +1 -1
- package/dist/manage-domain.d.ts.map +1 -1
- package/dist/manage-domain.js +34 -8
- package/dist/manage-domain.js.map +1 -1
- package/dist/node_modules/@vitest/pretty-format/dist/index.js +888 -0
- package/dist/node_modules/@vitest/pretty-format/dist/index.js.map +1 -0
- package/dist/node_modules/@vitest/runner/dist/chunk-artifact.js +1500 -0
- package/dist/node_modules/@vitest/runner/dist/chunk-artifact.js.map +1 -0
- package/dist/node_modules/@vitest/runner/dist/index.js +1 -0
- package/dist/node_modules/@vitest/runner/dist/utils.js +1 -0
- package/dist/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +82 -0
- package/dist/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js.map +1 -0
- package/dist/node_modules/@vitest/utils/dist/display.js +558 -0
- package/dist/node_modules/@vitest/utils/dist/display.js.map +1 -0
- package/dist/node_modules/@vitest/utils/dist/helpers.js +68 -0
- package/dist/node_modules/@vitest/utils/dist/helpers.js.map +1 -0
- package/dist/node_modules/@vitest/utils/dist/source-map.js +95 -0
- package/dist/node_modules/@vitest/utils/dist/source-map.js.map +1 -0
- package/dist/node_modules/@vitest/utils/dist/timers.js +20 -0
- package/dist/node_modules/@vitest/utils/dist/timers.js.map +1 -0
- package/dist/node_modules/tinyrainbow/dist/index.js +86 -0
- package/dist/node_modules/tinyrainbow/dist/index.js.map +1 -0
- package/dist/node_modules/vite/dist/node/module-runner.js +22 -0
- package/dist/node_modules/vite/dist/node/module-runner.js.map +1 -0
- package/dist/node_modules/vitest/dist/index.js +6 -0
- package/dist/troubleshoot.d.ts.map +1 -1
- package/dist/troubleshoot.js +11 -1
- package/dist/troubleshoot.js.map +1 -1
- package/dist/types.d.ts +30 -51
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -6
- package/dist/internals/build-fred-input.d.ts +0 -46
- package/dist/internals/build-fred-input.d.ts.map +0 -1
- package/dist/internals/build-fred-input.js +0 -160
- package/dist/internals/build-fred-input.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close-lease.d.ts","names":[],"sources":["../src/close-lease.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"close-lease.d.ts","names":[],"sources":["../src/close-lease.ts"],"mappings":";;;;AAuF2B;;;;;;;;;;;;;;;;;;;;;;;;;;iBAJL,UAAA,CACpB,IAAA,EAAM,cAAA,EACN,SAAA,EAAW,mBAAA,EACX,IAAA,EAAM,iBAAA,GACL,OAAA,CAAQ,gBAAA"}
|
package/dist/close-lease.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { makeCancellationScope } from "./internals/cancellation.js";
|
|
1
2
|
import { decode, isTerminal } from "./internals/lease-state.js";
|
|
2
3
|
import { verifyAndRecover } from "./internals/verify-recover.js";
|
|
3
|
-
import { ManifestMCPError, ManifestMCPErrorCode, stopApp } from "@manifest-network/manifest-mcp-core";
|
|
4
|
+
import { ManifestMCPError, ManifestMCPErrorCode, noopLogger, parseLeaseUuid, stopApp } from "@manifest-network/manifest-mcp-core";
|
|
4
5
|
//#region src/close-lease.ts
|
|
5
6
|
/**
|
|
6
7
|
* Public entry point: orchestrate closing an existing lease via the
|
|
@@ -52,12 +53,23 @@ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
|
|
52
53
|
*/
|
|
53
54
|
async function closeLease(args, callbacks, opts) {
|
|
54
55
|
validateArgs(args);
|
|
56
|
+
const cx = makeCancellationScope({
|
|
57
|
+
opts,
|
|
58
|
+
onProgress: callbacks.onProgress,
|
|
59
|
+
opLabel: "Lease close",
|
|
60
|
+
broadcasts: true
|
|
61
|
+
});
|
|
62
|
+
cx.throwIfCancelled();
|
|
55
63
|
const block = renderConfirmationBlock(args);
|
|
56
64
|
if (callbacks.onConfirm) {
|
|
57
|
-
if (await callbacks.onConfirm(block) !== "yes") throw new ManifestMCPError(ManifestMCPErrorCode.OPERATION_CANCELLED, "User declined to proceed with close-lease.");
|
|
65
|
+
if (await cx.race(callbacks.onConfirm(block)) !== "yes") throw new ManifestMCPError(ManifestMCPErrorCode.OPERATION_CANCELLED, "User declined to proceed with close-lease.");
|
|
58
66
|
}
|
|
59
67
|
callbacks.onProgress?.({ kind: "user_confirmed" });
|
|
60
|
-
|
|
68
|
+
cx.throwIfCancelled();
|
|
69
|
+
await stopApp({
|
|
70
|
+
chain: opts.clientManager,
|
|
71
|
+
logger: noopLogger
|
|
72
|
+
}, { leaseUuid: parseLeaseUuid(args.leaseUuid) });
|
|
61
73
|
const verifyResult = await verifyAndRecover({
|
|
62
74
|
verifier: async () => {
|
|
63
75
|
let result;
|
package/dist/close-lease.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close-lease.js","names":["decodeLeaseState"],"sources":["../src/close-lease.ts"],"sourcesContent":["/**\n * Public entry point: orchestrate closing an existing lease via the\n * `close-lease` billing tx.\n *\n * Composition (mirrors `deploy-app.ts` / `manage-domain.ts`):\n *\n * 1. Validate args.\n * 2. Render a confirmation block + optionally consult `onConfirm`.\n * 3. Broadcast `stopApp` (which submits `MsgCloseLease`).\n * 4. Verify the post-broadcast on-chain state via `verifyAndRecover`\n * driving a direct `billing.v1.lease({ leaseUuid })` query +\n * `lease-state.decode` + `isTerminal`. Terminal states (CLOSED /\n * REJECTED / EXPIRED / INSUFFICIENT_FUNDS) count as success;\n * PENDING / ACTIVE map to the `pending_drift` branch; a chain\n * response with no lease (`{ lease: null }`) maps to the catch-all\n * `unclassified` branch.\n * 5. On verify-failure, invoke the simple-form `onFailure({ reason })`\n * then throw `ManifestMCPError(TX_FAILED)`. On success, emit\n * `onComplete` with the typed `CloseLeaseResult`.\n */\n\nimport {\n ManifestMCPError,\n ManifestMCPErrorCode,\n stopApp,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n decode as decodeLeaseState,\n isTerminal,\n} from './internals/lease-state.js';\nimport {\n type VerificationSpec,\n verifyAndRecover,\n} from './internals/verify-recover.js';\nimport type {\n CloseLeaseArgs,\n CloseLeaseCallbacks,\n CloseLeaseOptions,\n CloseLeaseResult,\n DeploymentPlanBlock,\n LeaseStateName,\n} from './types.js';\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\ntype CloseOutcome = 'terminal' | 'pending' | 'not_found';\n\ninterface CloseDiag {\n stateName?: LeaseStateName;\n reason?: string;\n}\n\n/**\n * Close a lease and verify it reached a terminal on-chain state.\n *\n * @throws `ManifestMCPError(INVALID_CONFIG)` for args validation.\n * @throws `ManifestMCPError(OPERATION_CANCELLED)` when `onConfirm` returns\n * `'no'` (deliberate user cancellation — ENG-272).\n * @throws `ManifestMCPError` (typically `TX_FAILED`) propagated as-is\n * from the `stopApp()` broadcast step. Broadcast errors do NOT invoke\n * `onFailure` — that callback is reserved for post-broadcast\n * verification failures. `stopApp` already raises a structured\n * `ManifestMCPError` from the core package; wrapping it again at this\n * layer would be redundant. Callers wanting to react to broadcast\n * errors should catch them at the call site.\n * @throws `ManifestMCPError(TX_FAILED)` when post-broadcast verification\n * reaches one of two failure modes (both with `onFailure({ reason })`\n * invoked first):\n * - the lease is still non-terminal (`pending_drift` branch — state\n * decoded as PENDING / ACTIVE / similar non-terminal); or\n * - the chain returns `{ lease: null }` post-close, so the lease is\n * not visible on-chain (`unclassified` branch).\n * @throws `ManifestMCPError(QUERY_FAILED)` when the post-broadcast verify\n * chain query (`billing.v1.lease`) raises a non-NotFound error\n * (RPC / transport / decoding failure). Wrapped inside the verifier\n * closure so the failure flows through `onFailure({ reason })` before\n * the throw. Structured `ManifestMCPError`s raised by the chain client\n * are re-thrown as-is (with `onFailure` invoked first).\n */\nexport async function closeLease(\n args: CloseLeaseArgs,\n callbacks: CloseLeaseCallbacks,\n opts: CloseLeaseOptions,\n): Promise<CloseLeaseResult> {\n validateArgs(args);\n\n const block = renderConfirmationBlock(args);\n if (callbacks.onConfirm) {\n const yesNo = await callbacks.onConfirm(block);\n if (yesNo !== 'yes') {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.OPERATION_CANCELLED,\n 'User declined to proceed with close-lease.',\n );\n }\n }\n callbacks.onProgress?.({ kind: 'user_confirmed' });\n\n await stopApp(opts.clientManager, args.leaseUuid);\n\n // Direct single-lease query (Copilot review PR #60, comment 3275999624):\n // the previous `leasesByTenant` + page-1-only pagination would\n // false-`not_found` for tenants with >100 leases. `billing.v1.lease`\n // is the same query shape `troubleshoot.ts` already uses; it's\n // tenant-agnostic and bounded to a single lease.\n const spec: VerificationSpec<unknown, CloseOutcome, CloseDiag> = {\n verifier: async () => {\n // Wrap the chain call in try/catch (Copilot review PR #60,\n // comment 3276419264): if `billing.v1.lease` rejects (RPC down,\n // transport, structured `ManifestMCPError`), the error would\n // otherwise propagate OUT of `verifyAndRecover` and bypass the\n // post-verify `onFailure({ reason })` callback below. Mirror\n // the disambiguation pattern from `lookupDomain` (commit aaa5cc5)\n // and `troubleshootDeployment` (commit f1a4737): invoke\n // `onFailure` first, then re-throw `ManifestMCPError` as-is or\n // wrap plain errors as `QUERY_FAILED`.\n let result: unknown;\n try {\n const queryClient = await opts.clientManager.getQueryClient();\n result = await queryClient.liftedinit.billing.v1.lease({\n leaseUuid: args.leaseUuid,\n });\n } catch (err) {\n const reason = `Failed to query lease ${args.leaseUuid} during close-verify: ${\n err instanceof Error ? err.message : String(err)\n }`;\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n if (err instanceof ManifestMCPError) {\n throw err;\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.QUERY_FAILED, reason);\n }\n const lease = (result as { lease?: unknown })?.lease;\n if (lease === null || lease === undefined) {\n return {\n outcome: 'not_found' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} not visible on chain after close`,\n },\n };\n }\n const rawState = (lease as { state?: unknown }).state;\n const stateName = decodeLeaseState(\n typeof rawState === 'number' || typeof rawState === 'string'\n ? rawState\n : undefined,\n );\n if (stateName === undefined) {\n return {\n outcome: 'pending' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} state could not be decoded (raw=${String(rawState)})`,\n },\n };\n }\n return {\n outcome: (isTerminal(stateName) ? 'terminal' : 'pending') as\n | 'terminal'\n | 'pending',\n diagnostic: { stateName },\n };\n },\n successValues: ['terminal'],\n branches: {\n pending: {\n branchId: 'pending_drift',\n journalActionTags: ['close-lease-verify-pending'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `close_lease tx accepted but state is still ${d.stateName ?? 'unknown'}.`,\n }),\n buildRecoveryOptions: () => [],\n },\n not_found: {\n branchId: 'unclassified',\n journalActionTags: ['close-lease-verify-not-found'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `Lease ${args.leaseUuid} not visible on chain after close.`,\n }),\n buildRecoveryOptions: () => [],\n },\n },\n };\n\n const verifyResult = await verifyAndRecover(spec, undefined);\n\n if (verifyResult.result !== 'success') {\n const reason =\n verifyResult.failure?.reason ?? 'close-lease verification failed.';\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, reason);\n }\n\n // Invariant: when `verifyAndRecover` returns success, the matched\n // outcome was `'terminal'`, and the verifier's `terminal` branch\n // ALWAYS sets `diagnostic.stateName` (see the spec above). A missing\n // `stateName` on the success path means the verifier invariant is\n // broken — likely a future refactor regression. The previous\n // implementation fell back to `'LEASE_STATE_CLOSED'` silently, which\n // would lie to the caller (Copilot review PR #60, comment 3276719603).\n // Fail loudly with a typed error instead. `TX_FAILED` is the closest\n // available code in `ManifestMCPErrorCode` (no `INTERNAL_ERROR`\n // variant); the message names the invariant explicitly.\n if (!verifyResult.diagnostic.stateName) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n `close-lease verifier invariant violated: success outcome reached without diagnostic.stateName for lease ${args.leaseUuid}`,\n );\n }\n const finalState: LeaseStateName = verifyResult.diagnostic.stateName;\n const result: CloseLeaseResult = {\n leaseUuid: args.leaseUuid,\n finalState,\n };\n callbacks.onComplete?.(result);\n return result;\n}\n\n// --- Helpers --------------------------------------------------------\n\nfunction validateArgs(args: CloseLeaseArgs): void {\n if (typeof args.leaseUuid !== 'string' || !args.leaseUuid.match(UUID_RE)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `closeLease: leaseUuid must be a UUID; got \"${args.leaseUuid}\".`,\n );\n }\n}\n\nfunction renderConfirmationBlock(args: CloseLeaseArgs): DeploymentPlanBlock {\n // Image is not tracked in `CloseLeaseArgs` and `stopApp` doesn't return it;\n // surface the gap explicitly so reviewers/users see the missing context\n // rather than silently omitting an image field they'd expect.\n const text = [\n `Close lease ${args.leaseUuid}.`,\n ' Image: (image not recorded)',\n ' This is permanent — the lease cannot be reopened.',\n '',\n 'Proceed?',\n ].join('\\n');\n return { text };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,UACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCF,eAAsB,WACpB,MACA,WACA,MAC2B;CAC3B,aAAa,IAAI;CAEjB,MAAM,QAAQ,wBAAwB,IAAI;CAC1C,IAAI,UAAU;MAER,MADgB,UAAU,UAAU,KAAK,MAC/B,OACZ,MAAM,IAAI,iBACR,qBAAqB,qBACrB,4CACF;CAAA;CAGJ,UAAU,aAAa,EAAE,MAAM,iBAAiB,CAAC;CAEjD,MAAM,QAAQ,KAAK,eAAe,KAAK,SAAS;CA6FhD,MAAM,eAAe,MAAM,iBAAiB;EArF1C,UAAU,YAAY;GAUpB,IAAI;GACJ,IAAI;IAEF,SAAS,OAAM,MADW,KAAK,cAAc,eAAe,GACjC,WAAW,QAAQ,GAAG,MAAM,EACrD,WAAW,KAAK,UAClB,CAAC;GACH,SAAS,KAAK;IACZ,MAAM,SAAS,yBAAyB,KAAK,UAAU,wBACrD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IAEjD,IAAI,UAAU,WACZ,MAAM,UAAU,UAAU,EAAE,OAAO,CAAC;IAEtC,IAAI,eAAe,kBACjB,MAAM;IAER,MAAM,IAAI,iBAAiB,qBAAqB,cAAc,MAAM;GACtE;GACA,MAAM,QAAS,QAAgC;GAC/C,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;IACL,SAAS;IACT,YAAY,EACV,QAAQ,SAAS,KAAK,UAAU,mCAClC;GACF;GAEF,MAAM,WAAY,MAA8B;GAChD,MAAM,YAAYA,OAChB,OAAO,aAAa,YAAY,OAAO,aAAa,WAChD,WACA,KAAA,CACN;GACA,IAAI,cAAc,KAAA,GAChB,OAAO;IACL,SAAS;IACT,YAAY,EACV,QAAQ,SAAS,KAAK,UAAU,mCAAmC,OAAO,QAAQ,EAAE,GACtF;GACF;GAEF,OAAO;IACL,SAAU,WAAW,SAAS,IAAI,aAAa;IAG/C,YAAY,EAAE,UAAU;GAC1B;EACF;EACA,eAAe,CAAC,UAAU;EAC1B,UAAU;GACR,SAAS;IACP,UAAU;IACV,mBAAmB,CAAC,4BAA4B;IAChD,uBAAuB,OAAO;KAC5B,SAAS;KACT,QACE,EAAE,UACF,8CAA8C,EAAE,aAAa,UAAU;IAC3E;IACA,4BAA4B,CAAC;GAC/B;GACA,WAAW;IACT,UAAU;IACV,mBAAmB,CAAC,8BAA8B;IAClD,uBAAuB,OAAO;KAC5B,SAAS;KACT,QACE,EAAE,UACF,SAAS,KAAK,UAAU;IAC5B;IACA,4BAA4B,CAAC;GAC/B;EACF;CAG6C,GAAG,KAAA,CAAS;CAE3D,IAAI,aAAa,WAAW,WAAW;EACrC,MAAM,SACJ,aAAa,SAAS,UAAU;EAClC,IAAI,UAAU,WACZ,MAAM,UAAU,UAAU,EAAE,OAAO,CAAC;EAEtC,MAAM,IAAI,iBAAiB,qBAAqB,WAAW,MAAM;CACnE;CAYA,IAAI,CAAC,aAAa,WAAW,WAC3B,MAAM,IAAI,iBACR,qBAAqB,WACrB,2GAA2G,KAAK,WAClH;CAEF,MAAM,aAA6B,aAAa,WAAW;CAC3D,MAAM,SAA2B;EAC/B,WAAW,KAAK;EAChB;CACF;CACA,UAAU,aAAa,MAAM;CAC7B,OAAO;AACT;AAIA,SAAS,aAAa,MAA4B;CAChD,IAAI,OAAO,KAAK,cAAc,YAAY,CAAC,KAAK,UAAU,MAAM,OAAO,GACrE,MAAM,IAAI,iBACR,qBAAqB,gBACrB,8CAA8C,KAAK,UAAU,GAC/D;AAEJ;AAEA,SAAS,wBAAwB,MAA2C;CAW1E,OAAO,EAAE,MAPI;EACX,eAAe,KAAK,UAAU;EAC9B;EACA;EACA;EACA;CACF,EAAE,KAAK,IACK,EAAE;AAChB"}
|
|
1
|
+
{"version":3,"file":"close-lease.js","names":["decodeLeaseState"],"sources":["../src/close-lease.ts"],"sourcesContent":["/**\n * Public entry point: orchestrate closing an existing lease via the\n * `close-lease` billing tx.\n *\n * Composition (mirrors `deploy-app.ts` / `manage-domain.ts`):\n *\n * 1. Validate args.\n * 2. Render a confirmation block + optionally consult `onConfirm`.\n * 3. Broadcast `stopApp` (which submits `MsgCloseLease`).\n * 4. Verify the post-broadcast on-chain state via `verifyAndRecover`\n * driving a direct `billing.v1.lease({ leaseUuid })` query +\n * `lease-state.decode` + `isTerminal`. Terminal states (CLOSED /\n * REJECTED / EXPIRED / INSUFFICIENT_FUNDS) count as success;\n * PENDING / ACTIVE map to the `pending_drift` branch; a chain\n * response with no lease (`{ lease: null }`) maps to the catch-all\n * `unclassified` branch.\n * 5. On verify-failure, invoke the simple-form `onFailure({ reason })`\n * then throw `ManifestMCPError(TX_FAILED)`. On success, emit\n * `onComplete` with the typed `CloseLeaseResult`.\n */\n\nimport {\n ManifestMCPError,\n ManifestMCPErrorCode,\n noopLogger,\n parseLeaseUuid,\n stopApp,\n} from '@manifest-network/manifest-mcp-core';\nimport { makeCancellationScope } from './internals/cancellation.js';\nimport {\n decode as decodeLeaseState,\n isTerminal,\n} from './internals/lease-state.js';\nimport {\n type VerificationSpec,\n verifyAndRecover,\n} from './internals/verify-recover.js';\nimport type {\n CloseLeaseArgs,\n CloseLeaseCallbacks,\n CloseLeaseOptions,\n CloseLeaseResult,\n DeploymentPlanBlock,\n LeaseStateName,\n} from './types.js';\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\ntype CloseOutcome = 'terminal' | 'pending' | 'not_found';\n\ninterface CloseDiag {\n stateName?: LeaseStateName;\n reason?: string;\n}\n\n/**\n * Close a lease and verify it reached a terminal on-chain state.\n *\n * @throws `ManifestMCPError(INVALID_CONFIG)` for args validation.\n * @throws `ManifestMCPError(OPERATION_CANCELLED)` when `onConfirm` returns\n * `'no'` (deliberate user cancellation — ENG-272).\n * @throws `ManifestMCPError` (typically `TX_FAILED`) propagated as-is\n * from the `stopApp()` broadcast step. Broadcast errors do NOT invoke\n * `onFailure` — that callback is reserved for post-broadcast\n * verification failures. `stopApp` already raises a structured\n * `ManifestMCPError` from the core package; wrapping it again at this\n * layer would be redundant. Callers wanting to react to broadcast\n * errors should catch them at the call site.\n * @throws `ManifestMCPError(TX_FAILED)` when post-broadcast verification\n * reaches one of two failure modes (both with `onFailure({ reason })`\n * invoked first):\n * - the lease is still non-terminal (`pending_drift` branch — state\n * decoded as PENDING / ACTIVE / similar non-terminal); or\n * - the chain returns `{ lease: null }` post-close, so the lease is\n * not visible on-chain (`unclassified` branch).\n * @throws `ManifestMCPError(QUERY_FAILED)` when the post-broadcast verify\n * chain query (`billing.v1.lease`) raises a non-NotFound error\n * (RPC / transport / decoding failure). Wrapped inside the verifier\n * closure so the failure flows through `onFailure({ reason })` before\n * the throw. Structured `ManifestMCPError`s raised by the chain client\n * are re-thrown as-is (with `onFailure` invoked first).\n */\nexport async function closeLease(\n args: CloseLeaseArgs,\n callbacks: CloseLeaseCallbacks,\n opts: CloseLeaseOptions,\n): Promise<CloseLeaseResult> {\n validateArgs(args);\n\n const cx = makeCancellationScope({\n opts,\n onProgress: callbacks.onProgress,\n opLabel: 'Lease close',\n broadcasts: true,\n });\n cx.throwIfCancelled();\n\n const block = renderConfirmationBlock(args);\n if (callbacks.onConfirm) {\n const yesNo = await cx.race(callbacks.onConfirm(block));\n if (yesNo !== 'yes') {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.OPERATION_CANCELLED,\n 'User declined to proceed with close-lease.',\n );\n }\n }\n callbacks.onProgress?.({ kind: 'user_confirmed' });\n\n cx.throwIfCancelled();\n\n // txCtx has no signer (ManageDomain/CloseLease flows carry no walletProvider);\n // the sender resolves from ctx.chain (the CosmosClientManager wallet). See OI-SENDER.\n await stopApp(\n { chain: opts.clientManager, logger: noopLogger },\n { leaseUuid: parseLeaseUuid(args.leaseUuid) },\n );\n\n // Direct single-lease query (Copilot review PR #60, comment 3275999624):\n // the previous `leasesByTenant` + page-1-only pagination would\n // false-`not_found` for tenants with >100 leases. `billing.v1.lease`\n // is the same query shape `troubleshoot.ts` already uses; it's\n // tenant-agnostic and bounded to a single lease.\n const spec: VerificationSpec<unknown, CloseOutcome, CloseDiag> = {\n verifier: async () => {\n // Wrap the chain call in try/catch (Copilot review PR #60,\n // comment 3276419264): if `billing.v1.lease` rejects (RPC down,\n // transport, structured `ManifestMCPError`), the error would\n // otherwise propagate OUT of `verifyAndRecover` and bypass the\n // post-verify `onFailure({ reason })` callback below. Mirror\n // the disambiguation pattern from `lookupDomain` (commit aaa5cc5)\n // and `troubleshootDeployment` (commit f1a4737): invoke\n // `onFailure` first, then re-throw `ManifestMCPError` as-is or\n // wrap plain errors as `QUERY_FAILED`.\n let result: unknown;\n try {\n const queryClient = await opts.clientManager.getQueryClient();\n result = await queryClient.liftedinit.billing.v1.lease({\n leaseUuid: args.leaseUuid,\n });\n } catch (err) {\n const reason = `Failed to query lease ${args.leaseUuid} during close-verify: ${\n err instanceof Error ? err.message : String(err)\n }`;\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n if (err instanceof ManifestMCPError) {\n throw err;\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.QUERY_FAILED, reason);\n }\n const lease = (result as { lease?: unknown })?.lease;\n if (lease === null || lease === undefined) {\n return {\n outcome: 'not_found' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} not visible on chain after close`,\n },\n };\n }\n const rawState = (lease as { state?: unknown }).state;\n const stateName = decodeLeaseState(\n typeof rawState === 'number' || typeof rawState === 'string'\n ? rawState\n : undefined,\n );\n if (stateName === undefined) {\n return {\n outcome: 'pending' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} state could not be decoded (raw=${String(rawState)})`,\n },\n };\n }\n return {\n outcome: (isTerminal(stateName) ? 'terminal' : 'pending') as\n | 'terminal'\n | 'pending',\n diagnostic: { stateName },\n };\n },\n successValues: ['terminal'],\n branches: {\n pending: {\n branchId: 'pending_drift',\n journalActionTags: ['close-lease-verify-pending'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `close_lease tx accepted but state is still ${d.stateName ?? 'unknown'}.`,\n }),\n buildRecoveryOptions: () => [],\n },\n not_found: {\n branchId: 'unclassified',\n journalActionTags: ['close-lease-verify-not-found'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `Lease ${args.leaseUuid} not visible on chain after close.`,\n }),\n buildRecoveryOptions: () => [],\n },\n },\n };\n\n const verifyResult = await verifyAndRecover(spec, undefined);\n\n if (verifyResult.result !== 'success') {\n const reason =\n verifyResult.failure?.reason ?? 'close-lease verification failed.';\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, reason);\n }\n\n // Invariant: when `verifyAndRecover` returns success, the matched\n // outcome was `'terminal'`, and the verifier's `terminal` branch\n // ALWAYS sets `diagnostic.stateName` (see the spec above). A missing\n // `stateName` on the success path means the verifier invariant is\n // broken — likely a future refactor regression. The previous\n // implementation fell back to `'LEASE_STATE_CLOSED'` silently, which\n // would lie to the caller (Copilot review PR #60, comment 3276719603).\n // Fail loudly with a typed error instead. `TX_FAILED` is the closest\n // available code in `ManifestMCPErrorCode` (no `INTERNAL_ERROR`\n // variant); the message names the invariant explicitly.\n if (!verifyResult.diagnostic.stateName) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n `close-lease verifier invariant violated: success outcome reached without diagnostic.stateName for lease ${args.leaseUuid}`,\n );\n }\n const finalState: LeaseStateName = verifyResult.diagnostic.stateName;\n const result: CloseLeaseResult = {\n leaseUuid: args.leaseUuid,\n finalState,\n };\n callbacks.onComplete?.(result);\n return result;\n}\n\n// --- Helpers --------------------------------------------------------\n\nfunction validateArgs(args: CloseLeaseArgs): void {\n if (typeof args.leaseUuid !== 'string' || !args.leaseUuid.match(UUID_RE)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `closeLease: leaseUuid must be a UUID; got \"${args.leaseUuid}\".`,\n );\n }\n}\n\nfunction renderConfirmationBlock(args: CloseLeaseArgs): DeploymentPlanBlock {\n // Image is not tracked in `CloseLeaseArgs` and `stopApp` doesn't return it;\n // surface the gap explicitly so reviewers/users see the missing context\n // rather than silently omitting an image field they'd expect.\n const text = [\n `Close lease ${args.leaseUuid}.`,\n ' Image: (image not recorded)',\n ' This is permanent — the lease cannot be reopened.',\n '',\n 'Proceed?',\n ].join('\\n');\n return { text };\n}\n"],"mappings":"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"}
|
package/dist/deploy-app.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeployAppCallbacks, DeployAppOptions, DeployResult
|
|
1
|
+
import { AppDeploySpec, DeployAppCallbacks, DeployAppOptions, DeployResult } from "./types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/deploy-app.d.ts
|
|
4
4
|
/**
|
|
@@ -19,7 +19,7 @@ import { DeployAppCallbacks, DeployAppOptions, DeployResult, DeploySpec } from "
|
|
|
19
19
|
* branch) throw directly as `ManifestMCPError(TX_FAILED)` without
|
|
20
20
|
* invoking `onFailure`.
|
|
21
21
|
*/
|
|
22
|
-
declare function deployApp(spec:
|
|
22
|
+
declare function deployApp(spec: AppDeploySpec, callbacks: DeployAppCallbacks, opts: DeployAppOptions): Promise<DeployResult>;
|
|
23
23
|
//#endregion
|
|
24
24
|
export { deployApp };
|
|
25
25
|
//# sourceMappingURL=deploy-app.d.ts.map
|
package/dist/deploy-app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy-app.d.ts","names":[],"sources":["../src/deploy-app.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"deploy-app.d.ts","names":[],"sources":["../src/deploy-app.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;iBAqIsB,SAAA,CACpB,IAAA,EAAM,aAAA,EACN,SAAA,EAAW,kBAAA,EACX,IAAA,EAAM,gBAAA,GACL,OAAA,CAAQ,YAAA"}
|
package/dist/deploy-app.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import { makeCancellationScope } from "./internals/cancellation.js";
|
|
1
2
|
import { decode } from "./internals/lease-state.js";
|
|
2
|
-
import { isStackSpec, summarizeSpec, validateSpec } from "./internals/spec-normalize.js";
|
|
3
|
-
import { buildFredDeployInput, buildManifestPreviewInput } from "./internals/build-fred-input.js";
|
|
4
3
|
import { classifyDeployError } from "./internals/classify-deploy-error.js";
|
|
5
4
|
import { extractRunningEndpoints, formatEndpointAsUrl, normalizeFredUrl } from "./internals/connection.js";
|
|
6
5
|
import { classifyDeployResponse } from "./internals/classify-deploy-response.js";
|
|
7
6
|
import { EMPTY_DENOM_MAP, loadChainDenomMap } from "./internals/humanize-denom.js";
|
|
8
7
|
import { evaluateReadinessFromFredResponse } from "./internals/evaluate-readiness-from-fred.js";
|
|
9
8
|
import { renderDeploymentPlan } from "./internals/render-deployment-plan.js";
|
|
9
|
+
import { isStackSpec, summarizeSpec, validateSpec } from "./internals/spec-normalize.js";
|
|
10
10
|
import { renderIntentRecap } from "./internals/render-intent-recap.js";
|
|
11
11
|
import { renderPartialSuccessPrompt } from "./internals/render-partial-success-prompt.js";
|
|
12
|
-
import { ManifestMCPError, ManifestMCPErrorCode, cosmosEstimateFee, resolveSku, setItemCustomDomain, stopApp } from "@manifest-network/manifest-mcp-core";
|
|
12
|
+
import { ManifestMCPError, ManifestMCPErrorCode, asLeaseUuid, asProviderUuid, cosmosEstimateFee, noopLogger, parseFqdn, parseLeaseUuid, resolveSku, setItemCustomDomain, stopApp } from "@manifest-network/manifest-mcp-core";
|
|
13
13
|
import { AuthTimestampTracker, buildManifestPreview, checkDeploymentReadiness, createAuthToken, createLeaseDataSignMessage, createSignMessage, deployApp as deployApp$1, fetchActiveLease, pollLeaseUntilReady, resolveProviderUrl, uploadLeaseData, waitForAppReady } from "@manifest-network/manifest-mcp-fred";
|
|
14
14
|
//#region src/deploy-app.ts
|
|
15
15
|
/**
|
|
16
16
|
* Public entry point: orchestrate a Manifest-Network app deployment from
|
|
17
|
-
* a typed `
|
|
17
|
+
* a typed `AppDeploySpec` through the plan/confirm/broadcast/save flow.
|
|
18
18
|
*
|
|
19
19
|
* Architect's α-locked composition (post-PR-3 sub-plan Q1):
|
|
20
20
|
*
|
|
@@ -75,6 +75,13 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
75
75
|
throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, err instanceof Error ? err.message : `Invalid spec: ${String(err)}`);
|
|
76
76
|
}
|
|
77
77
|
if (typeof opts.walletProvider.signArbitrary !== "function") throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "opts.walletProvider must implement signArbitrary for ADR-036 auth tokens.");
|
|
78
|
+
const { signal, throwIfCancelled, race } = makeCancellationScope({
|
|
79
|
+
opts,
|
|
80
|
+
onProgress: callbacks.onProgress,
|
|
81
|
+
opLabel: "Deployment",
|
|
82
|
+
broadcasts: true
|
|
83
|
+
});
|
|
84
|
+
throwIfCancelled();
|
|
78
85
|
const walletAddress = await opts.walletProvider.getAddress();
|
|
79
86
|
const clientAddress = await opts.clientManager.getAddress();
|
|
80
87
|
if (walletAddress !== clientAddress) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, `opts.walletProvider and opts.clientManager are bound to different addresses (walletProvider=${walletAddress}, clientManager=${clientAddress}); they must reference the same wallet to avoid creating an orphaned lease on the clientManager wallet when ADR-036 auth (signed by walletProvider) fails.`);
|
|
@@ -83,12 +90,17 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
83
90
|
const chainId = opts.clientManager.getConfig().chainId;
|
|
84
91
|
const activeChain = /mainnet|main/i.test(chainId) ? "mainnet" : "testnet";
|
|
85
92
|
const queryClient = await opts.clientManager.getQueryClient();
|
|
93
|
+
const readCtx = {
|
|
94
|
+
query: queryClient,
|
|
95
|
+
chain: opts.clientManager,
|
|
96
|
+
logger: noopLogger
|
|
97
|
+
};
|
|
86
98
|
const resolvePin = async (s) => {
|
|
87
99
|
const providerUuid = requestedProviderUuid(s);
|
|
88
100
|
const skuUuid = requestedSkuUuid(s);
|
|
89
101
|
try {
|
|
90
102
|
return {
|
|
91
|
-
pin: await resolveSku(
|
|
103
|
+
pin: await resolveSku(readCtx, {
|
|
92
104
|
size: requestedSize(s),
|
|
93
105
|
...providerUuid !== void 0 ? { providerUuid } : {},
|
|
94
106
|
...skuUuid !== void 0 ? { skuUuid } : {}
|
|
@@ -102,9 +114,9 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
102
114
|
kind: "sku_ambiguous",
|
|
103
115
|
candidates
|
|
104
116
|
});
|
|
105
|
-
const pick = await callbacks.onResolveSku(candidates);
|
|
117
|
+
const pick = await race(callbacks.onResolveSku(candidates));
|
|
106
118
|
return {
|
|
107
|
-
pin: await resolveSku(
|
|
119
|
+
pin: await resolveSku(readCtx, {
|
|
108
120
|
size: requestedSize(s),
|
|
109
121
|
skuUuid: pick.skuUuid,
|
|
110
122
|
providerUuid: pick.providerUuid
|
|
@@ -116,7 +128,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
116
128
|
}
|
|
117
129
|
};
|
|
118
130
|
let { pin: pinned, elicited: pinElicited } = await resolvePin(spec);
|
|
119
|
-
let readiness = evaluateReadinessFromFredResponse(await checkDeploymentReadiness(
|
|
131
|
+
let readiness = evaluateReadinessFromFredResponse(await checkDeploymentReadiness(readCtx, tenantAddress, {
|
|
120
132
|
image: primaryImage(spec),
|
|
121
133
|
size: pinned.name,
|
|
122
134
|
providerUuid: pinned.providerUuid,
|
|
@@ -130,7 +142,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
130
142
|
`${readiness.reasons.join("; ")}`;
|
|
131
143
|
throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, `Readiness check failed: ${readiness.reasons.join("; ")}`);
|
|
132
144
|
}
|
|
133
|
-
let preview = await buildManifestPreview(
|
|
145
|
+
let preview = await buildManifestPreview(spec);
|
|
134
146
|
let summary = summarizeSpec(spec);
|
|
135
147
|
let fees = await estimateFees(opts, spec, preview.meta_hash_hex, pinned.skuUuid);
|
|
136
148
|
let plan = {
|
|
@@ -158,7 +170,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
158
170
|
block
|
|
159
171
|
});
|
|
160
172
|
if (callbacks.onPlan) {
|
|
161
|
-
const verdict = await callbacks.onPlan(plan);
|
|
173
|
+
const verdict = await race(callbacks.onPlan(plan));
|
|
162
174
|
if (verdict === "cancel") throw new ManifestMCPError(ManifestMCPErrorCode.OPERATION_CANCELLED, "User cancelled deployment at plan step.");
|
|
163
175
|
if (verdict !== "confirm") {
|
|
164
176
|
confirmedSpec = applyPlanEdit(confirmedSpec, verdict);
|
|
@@ -173,7 +185,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
173
185
|
skuUuid: pinned.skuUuid,
|
|
174
186
|
providerUuid: pinned.providerUuid
|
|
175
187
|
};
|
|
176
|
-
readiness = evaluateReadinessFromFredResponse(await checkDeploymentReadiness(
|
|
188
|
+
readiness = evaluateReadinessFromFredResponse(await checkDeploymentReadiness(readCtx, tenantAddress, {
|
|
177
189
|
image: primaryImage(confirmedSpec),
|
|
178
190
|
size: pinned.name,
|
|
179
191
|
providerUuid: pinned.providerUuid,
|
|
@@ -184,7 +196,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
184
196
|
readiness
|
|
185
197
|
});
|
|
186
198
|
if (readiness.status === "block") throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, `Post-edit readiness check failed: ${readiness.reasons.join("; ")}`);
|
|
187
|
-
preview = await buildManifestPreview(
|
|
199
|
+
preview = await buildManifestPreview(confirmedSpec);
|
|
188
200
|
summary = summarizeSpec(confirmedSpec);
|
|
189
201
|
fees = await estimateFees(opts, confirmedSpec, preview.meta_hash_hex, pinned.skuUuid);
|
|
190
202
|
plan = {
|
|
@@ -213,7 +225,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
213
225
|
activeChain
|
|
214
226
|
}) };
|
|
215
227
|
if (callbacks.onConfirm) {
|
|
216
|
-
if (await callbacks.onConfirm(recapBlock) !== "yes") throw new ManifestMCPError(ManifestMCPErrorCode.OPERATION_CANCELLED, "User declined to proceed at intent-recap step.");
|
|
228
|
+
if (await race(callbacks.onConfirm(recapBlock)) !== "yes") throw new ManifestMCPError(ManifestMCPErrorCode.OPERATION_CANCELLED, "User declined to proceed at intent-recap step.");
|
|
217
229
|
}
|
|
218
230
|
callbacks.onProgress?.({ kind: "user_confirmed" });
|
|
219
231
|
const signArbitrary = opts.walletProvider.signArbitrary.bind(opts.walletProvider);
|
|
@@ -228,14 +240,26 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
228
240
|
const { pub_key, signature } = await signArbitrary(address, createLeaseDataSignMessage(leaseUuid, metaHashHex, ts));
|
|
229
241
|
return createAuthToken(address, leaseUuid, ts, pub_key.value, signature, metaHashHex);
|
|
230
242
|
};
|
|
243
|
+
throwIfCancelled();
|
|
231
244
|
callbacks.onProgress?.({ kind: "deploy_app_broadcast" });
|
|
232
|
-
const fredInput =
|
|
245
|
+
const fredInput = {
|
|
246
|
+
...confirmedSpec,
|
|
247
|
+
size: pinned.name,
|
|
233
248
|
skuUuid: pinned.skuUuid,
|
|
234
249
|
providerUuid: pinned.providerUuid
|
|
235
|
-
}
|
|
250
|
+
};
|
|
236
251
|
let fredResult;
|
|
237
252
|
try {
|
|
238
|
-
fredResult = await deployApp$1(
|
|
253
|
+
fredResult = await deployApp$1({
|
|
254
|
+
query: queryClient,
|
|
255
|
+
chain: opts.clientManager,
|
|
256
|
+
fetch: opts.fetchFn ?? globalThis.fetch,
|
|
257
|
+
logger: noopLogger,
|
|
258
|
+
providerAuth: {
|
|
259
|
+
providerToken: (i) => getAuthToken(i.address, i.leaseUuid),
|
|
260
|
+
leaseDataToken: (i) => getLeaseDataAuthToken(i.address, i.leaseUuid, i.metaHashHex)
|
|
261
|
+
}
|
|
262
|
+
}, fredInput, signal ? { abortSignal: signal } : {});
|
|
239
263
|
} catch (err) {
|
|
240
264
|
const recoveryCtx = {
|
|
241
265
|
manifestJson: preview.manifest_json,
|
|
@@ -267,7 +291,19 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
267
291
|
let attempt = 0;
|
|
268
292
|
let pollResult;
|
|
269
293
|
try {
|
|
270
|
-
pollResult = await waitForAppReady(
|
|
294
|
+
pollResult = await waitForAppReady({
|
|
295
|
+
query: queryClient,
|
|
296
|
+
chain: opts.clientManager,
|
|
297
|
+
fetch: opts.fetchFn ?? globalThis.fetch,
|
|
298
|
+
logger: noopLogger,
|
|
299
|
+
providerAuth: {
|
|
300
|
+
providerToken: (i) => getAuthToken(i.address, i.leaseUuid),
|
|
301
|
+
leaseDataToken: (i) => getLeaseDataAuthToken(i.address, i.leaseUuid, i.metaHashHex)
|
|
302
|
+
}
|
|
303
|
+
}, {
|
|
304
|
+
address: tenantAddress,
|
|
305
|
+
leaseUuid
|
|
306
|
+
}, {
|
|
271
307
|
timeoutMs: opts.waitForReadyTimeoutMs ?? 48e4,
|
|
272
308
|
onProgress: (status) => {
|
|
273
309
|
attempt += 1;
|
|
@@ -280,7 +316,7 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
280
316
|
...stateName !== void 0 ? { state: stateName } : {}
|
|
281
317
|
});
|
|
282
318
|
}
|
|
283
|
-
}
|
|
319
|
+
});
|
|
284
320
|
} catch (err) {
|
|
285
321
|
const reason = err instanceof Error ? `wait_for_app_ready failed for lease ${leaseUuid}: ${err.message}` : `wait_for_app_ready failed for lease ${leaseUuid}: ${String(err)}`;
|
|
286
322
|
throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, reason);
|
|
@@ -298,8 +334,8 @@ async function deployApp(spec, callbacks, opts) {
|
|
|
298
334
|
}
|
|
299
335
|
fredResult = {
|
|
300
336
|
...fredResult,
|
|
301
|
-
lease_uuid: pollResult.lease_uuid,
|
|
302
|
-
provider_uuid: pollResult.provider_uuid,
|
|
337
|
+
lease_uuid: asLeaseUuid(pollResult.lease_uuid),
|
|
338
|
+
provider_uuid: asProviderUuid(pollResult.provider_uuid),
|
|
303
339
|
provider_url: pollResult.provider_url
|
|
304
340
|
};
|
|
305
341
|
liveState = pollResult.status.state;
|
|
@@ -353,15 +389,13 @@ function primaryImage(spec) {
|
|
|
353
389
|
return spec.image ?? "";
|
|
354
390
|
}
|
|
355
391
|
function requestedSize(spec) {
|
|
356
|
-
|
|
357
|
-
return typeof recorded === "string" && recorded.length > 0 ? recorded : "small";
|
|
392
|
+
return spec.size;
|
|
358
393
|
}
|
|
359
394
|
/**
|
|
360
395
|
* SKU disambiguator intent helpers. `providerUuid` / `skuUuid` are
|
|
361
|
-
* first-class optional fields on
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* supplied.
|
|
396
|
+
* first-class optional fields on `AppDeploySpec` (ENG-296, mirroring
|
|
397
|
+
* ENG-275's typed `size`). Returns `undefined` for absent / empty values
|
|
398
|
+
* so `resolveSku` only narrows when a real disambiguator is supplied.
|
|
365
399
|
*/
|
|
366
400
|
function requestedProviderUuid(spec) {
|
|
367
401
|
const v = spec.providerUuid;
|
|
@@ -426,11 +460,10 @@ function applyPlanEdit(spec, edit) {
|
|
|
426
460
|
}
|
|
427
461
|
};
|
|
428
462
|
}
|
|
429
|
-
const single = spec;
|
|
430
463
|
return {
|
|
431
|
-
...
|
|
464
|
+
...spec,
|
|
432
465
|
env: {
|
|
433
|
-
...
|
|
466
|
+
...spec.env ?? {},
|
|
434
467
|
...edit.env
|
|
435
468
|
}
|
|
436
469
|
};
|
|
@@ -478,7 +511,10 @@ async function dispatchRecovery(choice, envelope, spec, opts, callbacks, ctx) {
|
|
|
478
511
|
case "salvage_without_domain": throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, `salvage_without_domain: lease ${leaseUuid} retained without domain; caller should re-run troubleshootDeployment.`);
|
|
479
512
|
case "cancel_lease":
|
|
480
513
|
case "close_lease":
|
|
481
|
-
await stopApp(
|
|
514
|
+
await stopApp({
|
|
515
|
+
chain: opts.clientManager,
|
|
516
|
+
logger: noopLogger
|
|
517
|
+
}, { leaseUuid: parseLeaseUuid(leaseUuid) });
|
|
482
518
|
throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, `${choice.id}: lease ${leaseUuid} closed.`);
|
|
483
519
|
}
|
|
484
520
|
throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, `Unknown recovery option: ${choice.id}`);
|
|
@@ -537,19 +573,30 @@ async function retrySetDomainAndComplete(leaseUuid, spec, opts, callbacks, ctx)
|
|
|
537
573
|
const domain = customDomainOf(spec);
|
|
538
574
|
if (!domain) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "retry_set_domain requires a customDomain in spec.");
|
|
539
575
|
const serviceName = customDomainServiceOf(spec);
|
|
540
|
-
const setItemOpts = serviceName ? { serviceName } : void 0;
|
|
541
576
|
try {
|
|
542
|
-
await setItemCustomDomain(
|
|
577
|
+
await setItemCustomDomain({
|
|
578
|
+
chain: opts.clientManager,
|
|
579
|
+
logger: noopLogger
|
|
580
|
+
}, {
|
|
581
|
+
leaseUuid: parseLeaseUuid(leaseUuid),
|
|
582
|
+
customDomain: parseFqdn(domain),
|
|
583
|
+
serviceName
|
|
584
|
+
});
|
|
543
585
|
} catch (err) {
|
|
544
586
|
const reason = err instanceof Error ? `retry_set_domain set-item-custom-domain failed for lease ${leaseUuid}: ${err.message}` : `retry_set_domain set-item-custom-domain failed for lease ${leaseUuid}: ${String(err)}`;
|
|
545
587
|
throw new ManifestMCPError(err instanceof ManifestMCPError ? err.code : ManifestMCPErrorCode.TX_FAILED, reason);
|
|
546
588
|
}
|
|
547
|
-
const
|
|
589
|
+
const readCtx = {
|
|
590
|
+
query: await opts.clientManager.getQueryClient(),
|
|
591
|
+
chain: opts.clientManager,
|
|
592
|
+
fetch: opts.fetchFn ?? globalThis.fetch,
|
|
593
|
+
logger: noopLogger
|
|
594
|
+
};
|
|
548
595
|
let lease;
|
|
549
596
|
let providerApiUrl;
|
|
550
597
|
try {
|
|
551
|
-
lease = await fetchActiveLease(
|
|
552
|
-
providerApiUrl = await resolveProviderUrl(
|
|
598
|
+
lease = await fetchActiveLease(readCtx, leaseUuid, "cannot complete retry_set_domain");
|
|
599
|
+
providerApiUrl = await resolveProviderUrl(readCtx, lease.providerUuid);
|
|
553
600
|
} catch (err) {
|
|
554
601
|
const reason = err instanceof Error ? `retry_set_domain failed to resolve provider for lease ${leaseUuid}: ${err.message}` : `retry_set_domain failed to resolve provider for lease ${leaseUuid}: ${String(err)}`;
|
|
555
602
|
throw new ManifestMCPError(err instanceof ManifestMCPError ? err.code : ManifestMCPErrorCode.TX_FAILED, reason);
|