@mysten-incubation/devstack 0.3.0 → 0.4.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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dashboard-ui/assets/{grpc-Clz0oOtc.js → grpc-CpkDu4SA.js} +1 -1
  3. package/dashboard-ui/assets/{index-Cmqv9kiU.js → index-jLPRmjst.js} +2 -2
  4. package/dashboard-ui/index.html +1 -1
  5. package/dist/api/inference-network.d.mts +5 -5
  6. package/dist/api/inference-network.mjs +5 -5
  7. package/dist/api/inference-network.mjs.map +1 -1
  8. package/dist/api/run-stack-internal.mjs +1 -3
  9. package/dist/api/run-stack-internal.mjs.map +1 -1
  10. package/dist/build-integrations/dapp-kit/index.d.mts +12 -0
  11. package/dist/build-integrations/dapp-kit/index.mjs +14 -1
  12. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -1
  13. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  14. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  15. package/dist/build-integrations/playwright/index.d.mts +2 -2
  16. package/dist/build-integrations/playwright/index.mjs +2 -2
  17. package/dist/build-integrations/playwright/wallet-context.d.mts +2 -1
  18. package/dist/build-integrations/playwright/wallet-context.mjs +141 -41
  19. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  20. package/dist/build-integrations/runtime/dapp-kit-slot.mjs +1 -1
  21. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  22. package/dist/build-integrations/vite/index.d.mts +54 -42
  23. package/dist/build-integrations/vite/index.mjs +239 -106
  24. package/dist/build-integrations/vite/index.mjs.map +1 -1
  25. package/dist/build-integrations/vitest/global-setup.mjs +8 -8
  26. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -1
  27. package/dist/cli/main.mjs +3 -2
  28. package/dist/cli/main.mjs.map +1 -1
  29. package/dist/cli/wirings/apply.mjs +0 -1
  30. package/dist/cli/wirings/apply.mjs.map +1 -1
  31. package/dist/cli/wirings/codegen.mjs +2 -3
  32. package/dist/cli/wirings/codegen.mjs.map +1 -1
  33. package/dist/cli/wirings/dump-deployment.mjs +141 -0
  34. package/dist/cli/wirings/dump-deployment.mjs.map +1 -0
  35. package/dist/cli/wirings/snapshot.mjs +0 -1
  36. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  37. package/dist/contracts/codegenable.d.mts +22 -25
  38. package/dist/contracts/codegenable.mjs +35 -4
  39. package/dist/contracts/codegenable.mjs.map +1 -1
  40. package/dist/contracts/config-bindings.mjs +43 -18
  41. package/dist/contracts/config-bindings.mjs.map +1 -1
  42. package/dist/index.mjs +1 -1
  43. package/dist/orchestrators/boot.d.mts +0 -10
  44. package/dist/orchestrators/boot.mjs +19 -59
  45. package/dist/orchestrators/boot.mjs.map +1 -1
  46. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  47. package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
  48. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
  49. package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
  50. package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
  51. package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
  52. package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
  53. package/dist/orchestrators/codegen/deployment.d.mts +63 -0
  54. package/dist/orchestrators/codegen/deployment.mjs +153 -0
  55. package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
  56. package/dist/orchestrators/codegen/errors.mjs +7 -9
  57. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  58. package/dist/orchestrators/codegen/format.mjs +20 -1
  59. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  60. package/dist/orchestrators/codegen/paths.mjs +1 -8
  61. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  62. package/dist/orchestrators/codegen/service.mjs +354 -141
  63. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  64. package/dist/orchestrators/layers.mjs +0 -1
  65. package/dist/orchestrators/layers.mjs.map +1 -1
  66. package/dist/orchestrators/network-options.d.mts +37 -35
  67. package/dist/orchestrators/network-options.mjs +13 -10
  68. package/dist/orchestrators/network-options.mjs.map +1 -1
  69. package/dist/plugins/account/codegen.d.mts +3 -4
  70. package/dist/plugins/account/codegen.mjs +5 -7
  71. package/dist/plugins/account/codegen.mjs.map +1 -1
  72. package/dist/plugins/account/index.mjs +1 -3
  73. package/dist/plugins/account/index.mjs.map +1 -1
  74. package/dist/plugins/coin/codegen.mjs +5 -5
  75. package/dist/plugins/coin/codegen.mjs.map +1 -1
  76. package/dist/plugins/coin/index.mjs.map +1 -1
  77. package/dist/plugins/dashboard/schema/root.mjs +3 -1
  78. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  79. package/dist/plugins/deepbook/codegen.mjs +4 -4
  80. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  81. package/dist/plugins/deepbook/index.mjs.map +1 -1
  82. package/dist/plugins/internal/codegen-helpers.mjs +0 -1
  83. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  84. package/dist/plugins/package/codegen.d.mts +1 -12
  85. package/dist/plugins/package/codegen.mjs +43 -25
  86. package/dist/plugins/package/codegen.mjs.map +1 -1
  87. package/dist/plugins/package/dep-resolution.mjs +1 -1
  88. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  89. package/dist/plugins/package/index.d.mts +14 -11
  90. package/dist/plugins/package/index.mjs +6 -7
  91. package/dist/plugins/package/index.mjs.map +1 -1
  92. package/dist/plugins/seal/codegen.mjs +3 -3
  93. package/dist/plugins/seal/codegen.mjs.map +1 -1
  94. package/dist/plugins/seal/index.mjs.map +1 -1
  95. package/dist/plugins/sui/codegen.mjs +5 -4
  96. package/dist/plugins/sui/codegen.mjs.map +1 -1
  97. package/dist/plugins/sui/index.mjs +1 -2
  98. package/dist/plugins/sui/index.mjs.map +1 -1
  99. package/dist/plugins/wallet/codegen.d.mts +8 -12
  100. package/dist/plugins/wallet/codegen.mjs +22 -15
  101. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  102. package/dist/plugins/wallet/index.d.mts +4 -3
  103. package/dist/plugins/wallet/index.mjs +1 -1
  104. package/dist/plugins/wallet/index.mjs.map +1 -1
  105. package/dist/plugins/wallet/service.d.mts +2 -2
  106. package/dist/plugins/wallet/service.mjs +2 -3
  107. package/dist/plugins/wallet/service.mjs.map +1 -1
  108. package/dist/plugins/walrus/codegen.mjs +4 -4
  109. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  110. package/dist/plugins/walrus/index.mjs +1 -1
  111. package/dist/plugins/walrus/index.mjs.map +1 -1
  112. package/dist/substrate/manifest.d.mts +17 -22
  113. package/dist/substrate/manifest.mjs +4 -6
  114. package/dist/substrate/manifest.mjs.map +1 -1
  115. package/dist/substrate/plugin-ctx.d.mts +6 -6
  116. package/dist/substrate/plugin-ctx.mjs.map +1 -1
  117. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  118. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  119. package/dist/substrate/runtime/paths.mjs +1 -1
  120. package/dist/surfaces/cli/command-tree.mjs +6 -6
  121. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  122. package/dist/surfaces/cli/index.mjs +6 -4
  123. package/dist/surfaces/cli/index.mjs.map +1 -1
  124. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  125. package/package.json +1 -1
  126. package/dist/cli/wirings/dump-ids.mjs +0 -86
  127. package/dist/cli/wirings/dump-ids.mjs.map +0 -1
  128. package/dist/orchestrators/codegen/id-config.d.mts +0 -1
  129. package/dist/orchestrators/codegen/id-config.mjs +0 -107
  130. package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
  131. package/dist/orchestrators/codegen/output-location.mjs +0 -32
  132. package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
@@ -90,6 +90,48 @@ const createWalletAdapter = (options = {}) => {
90
90
  const DAPP_KIT_SLOT = DAPP_KIT_SLOT_KEY;
91
91
  const SELECT_ACCOUNT_SLOT_TIMEOUT_MS = 1e4;
92
92
  const SELECT_ACCOUNT_SLOT_POLL_MS = 50;
93
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
94
+ /**
95
+ * Shared poll-evaluate-until-deadline loop for the dapp-kit slot helpers.
96
+ *
97
+ * Factored out so `selectAccount` and `switchNetwork` can't drift on
98
+ * retry/timeout semantics. Responsibilities owned here:
99
+ * - Run `evaluate` against the page, retrying on a destroyed JS
100
+ * execution context (a network/account switch can tear the context
101
+ * down mid-evaluate) until the deadline, then surfacing a typed
102
+ * error via `onContextTimeout`.
103
+ * - Hand each successful `evaluate` result to `classify`, which decides
104
+ * whether the loop is `done`, should `retry` (polling until the
105
+ * deadline), or has definitively `fail`ed.
106
+ *
107
+ * The caller owns *what* a result means (success/retry/failure) and how
108
+ * to build its terminal errors; this helper owns the *when* (timing,
109
+ * polling, context-loss recovery).
110
+ */
111
+ const pollSlotUntilDeadline = async (args) => {
112
+ const deadline = Date.now() + SELECT_ACCOUNT_SLOT_TIMEOUT_MS;
113
+ let lastEvaluateError;
114
+ for (;;) {
115
+ let result;
116
+ try {
117
+ result = await args.evaluate(args.page);
118
+ } catch (cause) {
119
+ lastEvaluateError = cause;
120
+ if (Date.now() < deadline) {
121
+ await sleep(SELECT_ACCOUNT_SLOT_POLL_MS);
122
+ continue;
123
+ }
124
+ throw args.onContextTimeout(lastEvaluateError);
125
+ }
126
+ const outcome = args.classify(result, Date.now() < deadline);
127
+ if (outcome.kind === "done") return;
128
+ if (outcome.kind === "retry") {
129
+ await sleep(SELECT_ACCOUNT_SLOT_POLL_MS);
130
+ continue;
131
+ }
132
+ throw args.onFail(outcome.cause);
133
+ }
134
+ };
93
135
  /**
94
136
  * Connect/switch the app's active dev-wallet account through the dapp-kit
95
137
  * slot the app populates at boot.
@@ -115,54 +157,112 @@ const connectAs = async (page, accountName) => {
115
157
  * faster + less flaky than clicking the wallet's UI.
116
158
  */
117
159
  const selectAccount = async (page, accountName) => {
118
- const deadline = Date.now() + SELECT_ACCOUNT_SLOT_TIMEOUT_MS;
119
- let lastEvaluateError;
120
- for (;;) {
121
- let result;
122
- try {
123
- result = await page.evaluate(async (name) => {
124
- const slot = globalThis.__devstackDAppKit__;
125
- if (slot === void 0 || slot.selectAccount === void 0) return {
160
+ await pollSlotUntilDeadline({
161
+ page,
162
+ evaluate: async (p) => await p.evaluate(async (name) => {
163
+ const slot = globalThis.__devstackDAppKit__;
164
+ if (slot === void 0 || slot.selectAccount === void 0) return {
165
+ ok: false,
166
+ reason: "slot-not-populated"
167
+ };
168
+ try {
169
+ await slot.selectAccount(name);
170
+ return { ok: true };
171
+ } catch (err) {
172
+ return {
126
173
  ok: false,
127
- reason: "slot-not-populated"
174
+ reason: err instanceof Error ? err.message : String(err)
128
175
  };
129
- try {
130
- await slot.selectAccount(name);
131
- return { ok: true };
132
- } catch (err) {
133
- return {
134
- ok: false,
135
- reason: err instanceof Error ? err.message : String(err)
136
- };
137
- }
138
- }, accountName);
139
- } catch (cause) {
140
- lastEvaluateError = cause;
141
- if (Date.now() < deadline) {
142
- await new Promise((resolve) => setTimeout(resolve, SELECT_ACCOUNT_SLOT_POLL_MS));
143
- continue;
144
176
  }
145
- throw new PlaywrightWalletAdapterError({
146
- message: `selectAccount("${accountName}") failed: page evaluation did not settle before ${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading before calling connectAs().`,
147
- operation: "switch-account",
148
- cause: lastEvaluateError
149
- });
150
- }
151
- if (result.ok) return;
152
- if (result.reason === "slot-not-populated" && Date.now() < deadline) {
153
- await new Promise((resolve) => setTimeout(resolve, SELECT_ACCOUNT_SLOT_POLL_MS));
154
- continue;
155
- }
156
- throw new PlaywrightWalletAdapterError({
157
- message: `selectAccount("${accountName}") failed: ${result.reason ?? "unknown"}. Confirm \`globalThis.${DAPP_KIT_SLOT}\` is populated by the app's dapp-kit module at boot.`,
177
+ }, accountName),
178
+ classify: (result, beforeDeadline) => {
179
+ if (result.ok) return { kind: "done" };
180
+ if (result.reason === "slot-not-populated" && beforeDeadline) return { kind: "retry" };
181
+ return {
182
+ kind: "fail",
183
+ cause: result.reason
184
+ };
185
+ },
186
+ onContextTimeout: (lastEvaluateError) => new PlaywrightWalletAdapterError({
187
+ message: `selectAccount("${accountName}") failed: page evaluation did not settle before ${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading before calling connectAs().`,
158
188
  operation: "switch-account",
159
- cause: result.reason
160
- });
161
- }
189
+ cause: lastEvaluateError
190
+ }),
191
+ onFail: (cause) => new PlaywrightWalletAdapterError({
192
+ message: `selectAccount("${accountName}") failed: ${cause ?? "unknown"}. Confirm \`globalThis.${DAPP_KIT_SLOT}\` is populated by the app's dapp-kit module at boot.`,
193
+ operation: "switch-account",
194
+ cause
195
+ })
196
+ });
197
+ };
198
+ /**
199
+ * Switch the app's active dApp Kit network through the same dapp-kit slot
200
+ * `selectAccount` uses — one level over (network instead of account). Drives
201
+ * dApp Kit's public `switchNetwork`; the dev wallet (registered once via
202
+ * wallet-standard) stays mounted across the switch — only the active
203
+ * network/client changes.
204
+ *
205
+ * Resolution semantics:
206
+ * - When the app exposes `currentNetwork`, resolves once the slot reports
207
+ * the current network is `network` (the switch deterministically took
208
+ * effect).
209
+ * - When it does NOT, there is no post-switch confirmation signal, so the
210
+ * helper lets the swap settle (see `SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS`)
211
+ * rather than resolving the instant `switchNetwork()` returns `ok`.
212
+ */
213
+ const SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS = 250;
214
+ const switchNetwork = async (page, network) => {
215
+ let unconfirmedOkSince;
216
+ await pollSlotUntilDeadline({
217
+ page,
218
+ evaluate: async (p) => await p.evaluate(async (net) => {
219
+ const slot = globalThis.__devstackDAppKit__;
220
+ if (slot === void 0 || slot.switchNetwork === void 0) return {
221
+ ok: false,
222
+ reason: "slot-not-populated"
223
+ };
224
+ try {
225
+ await slot.switchNetwork(net);
226
+ return {
227
+ ok: true,
228
+ current: slot.currentNetwork?.()
229
+ };
230
+ } catch (err) {
231
+ return {
232
+ ok: false,
233
+ reason: err instanceof Error ? err.message : String(err)
234
+ };
235
+ }
236
+ }, network),
237
+ classify: (result, beforeDeadline) => {
238
+ if (result.ok && result.current === network) return { kind: "done" };
239
+ if (result.ok && result.current === void 0) {
240
+ const now = Date.now();
241
+ unconfirmedOkSince ??= now;
242
+ if (now - unconfirmedOkSince >= SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS) return { kind: "done" };
243
+ return beforeDeadline ? { kind: "retry" } : { kind: "done" };
244
+ }
245
+ if ((result.reason === "slot-not-populated" || result.ok) && beforeDeadline) return { kind: "retry" };
246
+ return {
247
+ kind: "fail",
248
+ cause: result.reason ?? `current is "${result.current}"`
249
+ };
250
+ },
251
+ onContextTimeout: (lastEvaluateError) => new PlaywrightWalletAdapterError({
252
+ message: `switchNetwork("${network}") failed: page evaluation did not settle before ${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading and \`globalThis.${DAPP_KIT_SLOT}\` is populated.`,
253
+ operation: "switch-network",
254
+ cause: lastEvaluateError
255
+ }),
256
+ onFail: (cause) => new PlaywrightWalletAdapterError({
257
+ message: `switchNetwork("${network}") failed: ${cause ?? "unknown"}. Confirm the network is in the app's deployment (a committed deployments/${network}.ts or the live local stack) and \`globalThis.${DAPP_KIT_SLOT}\` is populated.`,
258
+ operation: "switch-network",
259
+ cause
260
+ })
261
+ });
162
262
  };
163
263
  /** Test-side accessor for the full manifest (already decoded). */
164
264
  const loadStackManifest = (options = {}) => readStackContext(options);
165
265
  //#endregion
166
- export { DAPP_KIT_SLOT, connectAs, createWalletAdapter, loadStackManifest, selectAccount };
266
+ export { DAPP_KIT_SLOT, connectAs, createWalletAdapter, loadStackManifest, selectAccount, switchNetwork };
167
267
 
168
268
  //# sourceMappingURL=wallet-context.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-context.mjs","names":[],"sources":["../../../src/build-integrations/playwright/wallet-context.ts"],"sourcesContent":["// Wallet-context test helpers.\n//\n// Architecture (distilled/23-build-integrations.md § Playwright /\n// \"What it produces\"):\n//\n// In-spec helpers (`connectAs`, `selectAccount`) and the\n// `loadStackManifest` artifact loader. (`loadStackKeypair` is not\n// implemented — keys never leave the wallet plugin; tests sign via\n// the wallet's HTTP API.)\n//\n// And (per the user task brief): tests sign txs via the wallet's HTTP\n// API rather than driving the browser's wallet-UI flow. That is the\n// load-bearing wallet-context contract: a tiny typed HTTP client over\n// the dev wallet's endpoint exposed in the manifest.\n//\n// Discipline:\n// - This module performs NO browser interaction. The `page` arg in\n// `connectAs` is the Playwright `Page` (kept structural — we do\n// not import `@playwright/test`), but the helpers here only use\n// it to expose the dev-wallet selection / account-switch flow\n// through `evaluate`. The actual key handling stays server-side\n// in the wallet plugin.\n// - HTTP calls go through `fetch`. We do NOT pull in `@mysten/sui`\n// here — txs are constructed by tests, serialized, and POSTed\n// to the wallet for signing. The wallet plugin is the\n// authoritative key holder.\n// - Account-switch via the global slot (`globalThis.__devstackDAppKit__`)\n// for dapp-kit-driven in-browser context; HTTP wallet helpers\n// are the spec-level lower-friction path.\n\nimport {\n\treadStackContext,\n\ttype ResolveStackContextOptions,\n\ttype StackContext,\n} from './stack-context.ts';\nimport { readStashedFixture } from './global-setup.ts';\nimport { PlaywrightWalletAdapterError } from './errors.ts';\nimport { DAPP_KIT_SLOT_KEY, type DAppKitSlot } from '../runtime/dapp-kit-slot.ts';\n// The wallet plugin owns the wire-protocol path constants AND the\n// canonical endpoint name. Both are surfaced through the L5 runtime\n// bridge so this adapter never reaches into L2 plugin code directly\n// (ARCHITECTURE.md § Layer table — L5 reads only the runtime bridge).\nimport { WalletHttpPath, WALLET_ENDPOINT_KEY } from '../runtime/wallet-paths.ts';\n\n// -----------------------------------------------------------------------------\n// Structural Playwright `Page` shape — we keep `@playwright/test` an\n// optional peer.\n// -----------------------------------------------------------------------------\n\n/** Subset of `Page` we use. */\nexport interface PlaywrightPageLike {\n\treadonly evaluate: <T>(fn: (arg: unknown) => T, arg?: unknown) => Promise<T>;\n}\n\n// -----------------------------------------------------------------------------\n// Wallet adapter — HTTP client targeting the wallet plugin's endpoint\n// -----------------------------------------------------------------------------\n\n// `WALLET_ENDPOINT_KEY` is the short form Playwright/vitest helpers look\n// up — the manifest stores the canonical endpoint name\n// (`WALLET_ENDPOINT_NAME` — `'wallet-app'`) but the substrate's alias\n// resolver folds the key to the canonical name. Re-exported from the L5\n// runtime bridge so the spelling + canonical pairing stay aligned with\n// the wallet plugin.\nexport { WALLET_ENDPOINT_KEY };\n\nexport interface WalletAdapterOptions extends ResolveStackContextOptions {\n\t/** Override the resolved wallet URL. Useful for tests targeting a\n\t * remote / non-default stack. */\n\treadonly walletUrl?: string;\n\t/** Custom `fetch` for tests. Defaults to `globalThis.fetch`. */\n\treadonly fetch?: typeof fetch;\n\t/** Per-request timeout in ms. Default: 5_000. */\n\treadonly timeoutMs?: number;\n}\n\n/** Public shape of the wallet adapter — typed by-key methods plus the\n * raw `request` escape hatch. */\nexport interface WalletAdapter {\n\t/** Resolved base URL of the wallet plugin. */\n\treadonly walletUrl: string;\n\n\t/** List dev-wallet account names + addresses. */\n\treadonly listAccounts: () => Promise<ReadonlyArray<DevAccount>>;\n\n\t/** Sign + execute a serialized transaction as `accountName`.\n\t * `txBytes` is the canonical Sui tx bytes (base64). Returns the\n\t * wallet's response body (typed `unknown` — caller decodes).\n\t *\n\t * NOTE on account switching: the HTTP wallet server has no\n\t * `/accounts/switch` endpoint — active-account selection is owned\n\t * by the dapp-kit slot. Use `selectAccount` / `connectAs` below. */\n\treadonly signTransaction: (input: SignTxRequest) => Promise<SignTxResponse>;\n\n\t/** Raw POST escape hatch. Used by the helpers above and by tests\n\t * that need a wallet-endpoint not in the typed surface. */\n\treadonly request: <T>(path: string, body?: Record<string, unknown>) => Promise<T>;\n}\n\nexport interface DevAccount {\n\treadonly name: string;\n\treadonly address: string;\n}\n\nexport interface SignTxRequest {\n\treadonly accountName: string;\n\t/** Canonical Sui tx bytes, base64-encoded. */\n\treadonly txBytesBase64: string;\n\t/** Optional caller-supplied label for correlated trace output. */\n\treadonly label?: string;\n}\n\nexport interface SignTxResponse {\n\treadonly digest: string;\n\treadonly signature: string;\n\t/** Raw response payload (wallet-plugin-versioned shape). */\n\treadonly raw: unknown;\n}\n\n// -----------------------------------------------------------------------------\n// Resolver: locate the wallet URL via fixture > manifest > error\n// -----------------------------------------------------------------------------\n\n/**\n * Resolve the dev-wallet URL. Precedence:\n * 1. `options.walletUrl` (explicit override).\n * 2. The fixture stashed by `globalSetup` on `globalThis`.\n * 3. A fresh manifest read.\n *\n * Throws `PlaywrightWalletAdapterError` when every path misses. */\nconst resolveWalletUrl = (options: WalletAdapterOptions): string => {\n\tif (options.walletUrl !== undefined) return options.walletUrl;\n\n\tconst fixture = readStashedFixture();\n\tif (fixture !== null && fixture.walletEndpoint !== null) {\n\t\treturn fixture.walletEndpoint;\n\t}\n\n\tlet ctx: StackContext;\n\ttry {\n\t\tctx = readStackContext(options);\n\t} catch (cause) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage:\n\t\t\t\t`unable to resolve dev-wallet URL — no globalSetup fixture and ` + `manifest read failed`,\n\t\t\toperation: 'fetch',\n\t\t\tcause,\n\t\t});\n\t}\n\tconst walletUrl = ctx.endpointMaybe(WALLET_ENDPOINT_KEY);\n\tif (walletUrl === null) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage:\n\t\t\t\t`manifest has no \\`${WALLET_ENDPOINT_KEY}\\` endpoint (alias for ` +\n\t\t\t\t`\\`wallet-app\\`) — is the dev-wallet plugin present in your stack? ` +\n\t\t\t\t`Available endpoint names: ${ctx.endpointNames.join(', ') || '(none)'}. ` +\n\t\t\t\t`Raw manifest keys: ${ctx.manifestEndpointKeys.join(', ') || '(none)'}.`,\n\t\t\toperation: 'fetch',\n\t\t});\n\t}\n\treturn walletUrl;\n};\n\n// -----------------------------------------------------------------------------\n// Factory\n// -----------------------------------------------------------------------------\n\n/**\n * Build a wallet adapter. Most tests call this once per `test`\n * fixture; the resolution is sync (a hash-lookup on the\n * fixture / manifest) so this is cheap.\n */\nexport const createWalletAdapter = (options: WalletAdapterOptions = {}): WalletAdapter => {\n\tconst walletUrl = resolveWalletUrl(options).replace(/\\/$/, '');\n\tconst fetchImpl = options.fetch ?? globalThis.fetch;\n\t// 30s default — Playwright's webServer cold-start (vite + first\n\t// devstack bring-up) routinely exceeds 5s under CI parallelism; the\n\t// shorter default surfaces as a spurious AbortError before the\n\t// wallet plugin has finished publishing its HTTP route. Callers can\n\t// still tighten via `options.timeoutMs` for hot-path assertions.\n\tconst timeoutMs = options.timeoutMs ?? 30_000;\n\n\tconst request = async <T>(path: string, body?: Record<string, unknown>): Promise<T> => {\n\t\tconst url = `${walletUrl}${path.startsWith('/') ? path : `/${path}`}`;\n\t\tconst controller = new AbortController();\n\t\tconst handle = setTimeout(() => controller.abort(), timeoutMs);\n\t\ttry {\n\t\t\tconst res = await fetchImpl(url, {\n\t\t\t\tmethod: body === undefined ? 'GET' : 'POST',\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\tbody: body === undefined ? undefined : JSON.stringify(body),\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\t\t\tmessage: `wallet request ${path} failed: HTTP ${res.status}`,\n\t\t\t\t\toperation: 'fetch',\n\t\t\t\t\turl,\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn (await res.json()) as T;\n\t\t} catch (cause) {\n\t\t\tif (cause instanceof PlaywrightWalletAdapterError) throw cause;\n\t\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\t\tmessage: `wallet request ${path} threw`,\n\t\t\t\toperation: 'fetch',\n\t\t\t\turl,\n\t\t\t\tcause,\n\t\t\t});\n\t\t} finally {\n\t\t\tclearTimeout(handle);\n\t\t}\n\t};\n\n\treturn {\n\t\twalletUrl,\n\t\t// Paths come from the wallet plugin's canonical wire-protocol\n\t\t// module. Hard-coded literals here would silently 404 the moment\n\t\t// `WalletHttpPath` is reorganised, with no compile-time signal.\n\t\tlistAccounts: () => request<ReadonlyArray<DevAccount>>(WalletHttpPath.ACCOUNTS),\n\t\tsignTransaction: (input: SignTxRequest) =>\n\t\t\trequest<SignTxResponse>(WalletHttpPath.SIGN_TRANSACTION, {\n\t\t\t\taccountName: input.accountName,\n\t\t\t\ttxBytesBase64: input.txBytesBase64,\n\t\t\t\tlabel: input.label,\n\t\t\t}),\n\t\trequest,\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// In-spec helpers — `connectAs` and `selectAccount`\n// -----------------------------------------------------------------------------\n\n/** Slot name owned by the app's `dapp-kit.ts`. The build integration\n * reads it; the app populates it. Re-exported from `runtime/`'s\n * canonical contract — kept here as a name alias for the\n * in-spec-helpers' import path. */\nexport const DAPP_KIT_SLOT = DAPP_KIT_SLOT_KEY;\n\nconst SELECT_ACCOUNT_SLOT_TIMEOUT_MS = 10_000;\nconst SELECT_ACCOUNT_SLOT_POLL_MS = 50;\n\n/**\n * Connect/switch the app's active dev-wallet account through the dapp-kit\n * slot the app populates at boot.\n *\n * This intentionally avoids driving the wallet UI. The app-side slot\n * implementation still goes through dapp-kit + wallet-standard, so pairing,\n * origin, and account discovery failures surface as real browser failures.\n */\nexport const connectAs = async (page: PlaywrightPageLike, accountName: string): Promise<void> => {\n\ttry {\n\t\tawait selectAccount(page, accountName);\n\t} catch (cause) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage: `connectAs(\"${accountName}\") failed`,\n\t\t\toperation: 'switch-account',\n\t\t\tcause,\n\t\t});\n\t}\n};\n\n/**\n * Switch the dev-wallet's active account by routing through the\n * dapp-kit global slot the app populates at module init. Strictly\n * faster + less flaky than clicking the wallet's UI.\n */\nexport const selectAccount = async (\n\tpage: PlaywrightPageLike,\n\taccountName: string,\n): Promise<void> => {\n\tconst deadline = Date.now() + SELECT_ACCOUNT_SLOT_TIMEOUT_MS;\n\tlet lastEvaluateError: unknown;\n\t// `evaluate`'s closure is serialized into the browser; the slot\n\t// shape (`DAppKitSlot`) lives in `runtime/dapp-kit-slot.ts` — the\n\t// in-browser closure can't import it, but the global-augmentation\n\t// `globalThis.__devstackDAppKit__` is the typed contract both sides\n\t// rely on.\n\tfor (;;) {\n\t\tlet result: { ok: boolean; reason?: string };\n\t\ttry {\n\t\t\tresult = await page.evaluate(async (name): Promise<{ ok: boolean; reason?: string }> => {\n\t\t\t\tconst slot = (globalThis as { __devstackDAppKit__?: DAppKitSlot }).__devstackDAppKit__;\n\t\t\t\tif (slot === undefined || slot.selectAccount === undefined) {\n\t\t\t\t\treturn { ok: false, reason: 'slot-not-populated' };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait slot.selectAccount(name as string);\n\t\t\t\t\treturn { ok: true };\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\treason: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}, accountName);\n\t\t} catch (cause) {\n\t\t\tlastEvaluateError = cause;\n\t\t\tif (Date.now() < deadline) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, SELECT_ACCOUNT_SLOT_POLL_MS));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\t\tmessage:\n\t\t\t\t\t`selectAccount(\"${accountName}\") failed: page evaluation did not settle before ` +\n\t\t\t\t\t`${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading before ` +\n\t\t\t\t\t`calling connectAs().`,\n\t\t\t\toperation: 'switch-account',\n\t\t\t\tcause: lastEvaluateError,\n\t\t\t});\n\t\t}\n\n\t\tif (result.ok) return;\n\t\tif (result.reason === 'slot-not-populated' && Date.now() < deadline) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, SELECT_ACCOUNT_SLOT_POLL_MS));\n\t\t\tcontinue;\n\t\t}\n\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage:\n\t\t\t\t`selectAccount(\"${accountName}\") failed: ${result.reason ?? 'unknown'}. ` +\n\t\t\t\t`Confirm \\`globalThis.${DAPP_KIT_SLOT}\\` is populated by the app's ` +\n\t\t\t\t`dapp-kit module at boot.`,\n\t\t\toperation: 'switch-account',\n\t\t\t// `cause` survives the `page.evaluate` boundary as a string —\n\t\t\t// the browser-side `Error` instance is lost across the bridge,\n\t\t\t// but the message is the load-bearing diagnostic. Preserving\n\t\t\t// it on the typed error keeps the underlying detail attached\n\t\t\t// when consumers inspect `cause` rather than `message`.\n\t\t\tcause: result.reason,\n\t\t});\n\t}\n};\n\n// -----------------------------------------------------------------------------\n// Artifact loaders\n// -----------------------------------------------------------------------------\n\n/** Test-side accessor for the full manifest (already decoded). */\nexport const loadStackManifest = (options: ResolveStackContextOptions = {}): StackContext =>\n\treadStackContext(options);\n"],"mappings":"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"}
1
+ {"version":3,"file":"wallet-context.mjs","names":[],"sources":["../../../src/build-integrations/playwright/wallet-context.ts"],"sourcesContent":["// Wallet-context test helpers.\n//\n// Architecture (distilled/23-build-integrations.md § Playwright /\n// \"What it produces\"):\n//\n// In-spec helpers (`connectAs`, `selectAccount`) and the\n// `loadStackManifest` artifact loader. (`loadStackKeypair` is not\n// implemented — keys never leave the wallet plugin; tests sign via\n// the wallet's HTTP API.)\n//\n// And (per the user task brief): tests sign txs via the wallet's HTTP\n// API rather than driving the browser's wallet-UI flow. That is the\n// load-bearing wallet-context contract: a tiny typed HTTP client over\n// the dev wallet's endpoint exposed in the manifest.\n//\n// Discipline:\n// - This module performs NO browser interaction. The `page` arg in\n// `connectAs` is the Playwright `Page` (kept structural — we do\n// not import `@playwright/test`), but the helpers here only use\n// it to expose the dev-wallet selection / account-switch flow\n// through `evaluate`. The actual key handling stays server-side\n// in the wallet plugin.\n// - HTTP calls go through `fetch`. We do NOT pull in `@mysten/sui`\n// here — txs are constructed by tests, serialized, and POSTed\n// to the wallet for signing. The wallet plugin is the\n// authoritative key holder.\n// - Account-switch via the global slot (`globalThis.__devstackDAppKit__`)\n// for dapp-kit-driven in-browser context; HTTP wallet helpers\n// are the spec-level lower-friction path.\n\nimport {\n\treadStackContext,\n\ttype ResolveStackContextOptions,\n\ttype StackContext,\n} from './stack-context.ts';\nimport { readStashedFixture } from './global-setup.ts';\nimport { PlaywrightWalletAdapterError } from './errors.ts';\nimport { DAPP_KIT_SLOT_KEY, type DAppKitSlot } from '../runtime/dapp-kit-slot.ts';\n// The wallet plugin owns the wire-protocol path constants AND the\n// canonical endpoint name. Both are surfaced through the L5 runtime\n// bridge so this adapter never reaches into L2 plugin code directly\n// (ARCHITECTURE.md § Layer table — L5 reads only the runtime bridge).\nimport { WalletHttpPath, WALLET_ENDPOINT_KEY } from '../runtime/wallet-paths.ts';\n\n// -----------------------------------------------------------------------------\n// Structural Playwright `Page` shape — we keep `@playwright/test` an\n// optional peer.\n// -----------------------------------------------------------------------------\n\n/** Subset of `Page` we use. */\nexport interface PlaywrightPageLike {\n\treadonly evaluate: <T>(fn: (arg: unknown) => T, arg?: unknown) => Promise<T>;\n}\n\n// -----------------------------------------------------------------------------\n// Wallet adapter — HTTP client targeting the wallet plugin's endpoint\n// -----------------------------------------------------------------------------\n\n// `WALLET_ENDPOINT_KEY` is the short form Playwright/vitest helpers look\n// up — the manifest stores the canonical endpoint name\n// (`WALLET_ENDPOINT_NAME` — `'wallet-app'`) but the substrate's alias\n// resolver folds the key to the canonical name. Re-exported from the L5\n// runtime bridge so the spelling + canonical pairing stay aligned with\n// the wallet plugin.\nexport { WALLET_ENDPOINT_KEY };\n\nexport interface WalletAdapterOptions extends ResolveStackContextOptions {\n\t/** Override the resolved wallet URL. Useful for tests targeting a\n\t * remote / non-default stack. */\n\treadonly walletUrl?: string;\n\t/** Custom `fetch` for tests. Defaults to `globalThis.fetch`. */\n\treadonly fetch?: typeof fetch;\n\t/** Per-request timeout in ms. Default: 5_000. */\n\treadonly timeoutMs?: number;\n}\n\n/** Public shape of the wallet adapter — typed by-key methods plus the\n * raw `request` escape hatch. */\nexport interface WalletAdapter {\n\t/** Resolved base URL of the wallet plugin. */\n\treadonly walletUrl: string;\n\n\t/** List dev-wallet account names + addresses. */\n\treadonly listAccounts: () => Promise<ReadonlyArray<DevAccount>>;\n\n\t/** Sign + execute a serialized transaction as `accountName`.\n\t * `txBytes` is the canonical Sui tx bytes (base64). Returns the\n\t * wallet's response body (typed `unknown` — caller decodes).\n\t *\n\t * NOTE on account switching: the HTTP wallet server has no\n\t * `/accounts/switch` endpoint — active-account selection is owned\n\t * by the dapp-kit slot. Use `selectAccount` / `connectAs` below. */\n\treadonly signTransaction: (input: SignTxRequest) => Promise<SignTxResponse>;\n\n\t/** Raw POST escape hatch. Used by the helpers above and by tests\n\t * that need a wallet-endpoint not in the typed surface. */\n\treadonly request: <T>(path: string, body?: Record<string, unknown>) => Promise<T>;\n}\n\nexport interface DevAccount {\n\treadonly name: string;\n\treadonly address: string;\n}\n\nexport interface SignTxRequest {\n\treadonly accountName: string;\n\t/** Canonical Sui tx bytes, base64-encoded. */\n\treadonly txBytesBase64: string;\n\t/** Optional caller-supplied label for correlated trace output. */\n\treadonly label?: string;\n}\n\nexport interface SignTxResponse {\n\treadonly digest: string;\n\treadonly signature: string;\n\t/** Raw response payload (wallet-plugin-versioned shape). */\n\treadonly raw: unknown;\n}\n\n// -----------------------------------------------------------------------------\n// Resolver: locate the wallet URL via fixture > manifest > error\n// -----------------------------------------------------------------------------\n\n/**\n * Resolve the dev-wallet URL. Precedence:\n * 1. `options.walletUrl` (explicit override).\n * 2. The fixture stashed by `globalSetup` on `globalThis`.\n * 3. A fresh manifest read.\n *\n * Throws `PlaywrightWalletAdapterError` when every path misses. */\nconst resolveWalletUrl = (options: WalletAdapterOptions): string => {\n\tif (options.walletUrl !== undefined) return options.walletUrl;\n\n\tconst fixture = readStashedFixture();\n\tif (fixture !== null && fixture.walletEndpoint !== null) {\n\t\treturn fixture.walletEndpoint;\n\t}\n\n\tlet ctx: StackContext;\n\ttry {\n\t\tctx = readStackContext(options);\n\t} catch (cause) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage:\n\t\t\t\t`unable to resolve dev-wallet URL — no globalSetup fixture and ` + `manifest read failed`,\n\t\t\toperation: 'fetch',\n\t\t\tcause,\n\t\t});\n\t}\n\tconst walletUrl = ctx.endpointMaybe(WALLET_ENDPOINT_KEY);\n\tif (walletUrl === null) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage:\n\t\t\t\t`manifest has no \\`${WALLET_ENDPOINT_KEY}\\` endpoint (alias for ` +\n\t\t\t\t`\\`wallet-app\\`) — is the dev-wallet plugin present in your stack? ` +\n\t\t\t\t`Available endpoint names: ${ctx.endpointNames.join(', ') || '(none)'}. ` +\n\t\t\t\t`Raw manifest keys: ${ctx.manifestEndpointKeys.join(', ') || '(none)'}.`,\n\t\t\toperation: 'fetch',\n\t\t});\n\t}\n\treturn walletUrl;\n};\n\n// -----------------------------------------------------------------------------\n// Factory\n// -----------------------------------------------------------------------------\n\n/**\n * Build a wallet adapter. Most tests call this once per `test`\n * fixture; the resolution is sync (a hash-lookup on the\n * fixture / manifest) so this is cheap.\n */\nexport const createWalletAdapter = (options: WalletAdapterOptions = {}): WalletAdapter => {\n\tconst walletUrl = resolveWalletUrl(options).replace(/\\/$/, '');\n\tconst fetchImpl = options.fetch ?? globalThis.fetch;\n\t// 30s default — Playwright's webServer cold-start (vite + first\n\t// devstack bring-up) routinely exceeds 5s under CI parallelism; the\n\t// shorter default surfaces as a spurious AbortError before the\n\t// wallet plugin has finished publishing its HTTP route. Callers can\n\t// still tighten via `options.timeoutMs` for hot-path assertions.\n\tconst timeoutMs = options.timeoutMs ?? 30_000;\n\n\tconst request = async <T>(path: string, body?: Record<string, unknown>): Promise<T> => {\n\t\tconst url = `${walletUrl}${path.startsWith('/') ? path : `/${path}`}`;\n\t\tconst controller = new AbortController();\n\t\tconst handle = setTimeout(() => controller.abort(), timeoutMs);\n\t\ttry {\n\t\t\tconst res = await fetchImpl(url, {\n\t\t\t\tmethod: body === undefined ? 'GET' : 'POST',\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\tbody: body === undefined ? undefined : JSON.stringify(body),\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\t\t\tmessage: `wallet request ${path} failed: HTTP ${res.status}`,\n\t\t\t\t\toperation: 'fetch',\n\t\t\t\t\turl,\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn (await res.json()) as T;\n\t\t} catch (cause) {\n\t\t\tif (cause instanceof PlaywrightWalletAdapterError) throw cause;\n\t\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\t\tmessage: `wallet request ${path} threw`,\n\t\t\t\toperation: 'fetch',\n\t\t\t\turl,\n\t\t\t\tcause,\n\t\t\t});\n\t\t} finally {\n\t\t\tclearTimeout(handle);\n\t\t}\n\t};\n\n\treturn {\n\t\twalletUrl,\n\t\t// Paths come from the wallet plugin's canonical wire-protocol\n\t\t// module. Hard-coded literals here would silently 404 the moment\n\t\t// `WalletHttpPath` is reorganised, with no compile-time signal.\n\t\tlistAccounts: () => request<ReadonlyArray<DevAccount>>(WalletHttpPath.ACCOUNTS),\n\t\tsignTransaction: (input: SignTxRequest) =>\n\t\t\trequest<SignTxResponse>(WalletHttpPath.SIGN_TRANSACTION, {\n\t\t\t\taccountName: input.accountName,\n\t\t\t\ttxBytesBase64: input.txBytesBase64,\n\t\t\t\tlabel: input.label,\n\t\t\t}),\n\t\trequest,\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// In-spec helpers — `connectAs` and `selectAccount`\n// -----------------------------------------------------------------------------\n\n/** Slot name owned by the app's `dapp-kit.ts`. The build integration\n * reads it; the app populates it. Re-exported from `runtime/`'s\n * canonical contract — kept here as a name alias for the\n * in-spec-helpers' import path. */\nexport const DAPP_KIT_SLOT = DAPP_KIT_SLOT_KEY;\n\nconst SELECT_ACCOUNT_SLOT_TIMEOUT_MS = 10_000;\nconst SELECT_ACCOUNT_SLOT_POLL_MS = 50;\n\n/**\n * Outcome of classifying a single `page.evaluate` result inside the\n * slot-poll loop. `done` resolves the loop; `retry` waits a poll\n * interval and re-evaluates (until the deadline); `fail` aborts.\n */\ntype SlotPollOutcome = { kind: 'done' } | { kind: 'retry' } | { kind: 'fail'; cause: unknown };\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Shared poll-evaluate-until-deadline loop for the dapp-kit slot helpers.\n *\n * Factored out so `selectAccount` and `switchNetwork` can't drift on\n * retry/timeout semantics. Responsibilities owned here:\n * - Run `evaluate` against the page, retrying on a destroyed JS\n * execution context (a network/account switch can tear the context\n * down mid-evaluate) until the deadline, then surfacing a typed\n * error via `onContextTimeout`.\n * - Hand each successful `evaluate` result to `classify`, which decides\n * whether the loop is `done`, should `retry` (polling until the\n * deadline), or has definitively `fail`ed.\n *\n * The caller owns *what* a result means (success/retry/failure) and how\n * to build its terminal errors; this helper owns the *when* (timing,\n * polling, context-loss recovery).\n */\nconst pollSlotUntilDeadline = async <T>(args: {\n\treadonly page: PlaywrightPageLike;\n\treadonly evaluate: (page: PlaywrightPageLike) => Promise<T>;\n\treadonly classify: (result: T, beforeDeadline: boolean) => SlotPollOutcome;\n\treadonly onContextTimeout: (lastEvaluateError: unknown) => PlaywrightWalletAdapterError;\n\treadonly onFail: (cause: unknown) => PlaywrightWalletAdapterError;\n}): Promise<void> => {\n\tconst deadline = Date.now() + SELECT_ACCOUNT_SLOT_TIMEOUT_MS;\n\tlet lastEvaluateError: unknown;\n\tfor (;;) {\n\t\tlet result: T;\n\t\ttry {\n\t\t\tresult = await args.evaluate(args.page);\n\t\t} catch (cause) {\n\t\t\t// A network/account switch can destroy the JS execution context\n\t\t\t// mid-evaluate (\"Execution context was destroyed\"); the raw\n\t\t\t// rejection is transient, so retry until the deadline rather than\n\t\t\t// letting it escape as a flaky failure.\n\t\t\tlastEvaluateError = cause;\n\t\t\tif (Date.now() < deadline) {\n\t\t\t\tawait sleep(SELECT_ACCOUNT_SLOT_POLL_MS);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow args.onContextTimeout(lastEvaluateError);\n\t\t}\n\n\t\tconst outcome = args.classify(result, Date.now() < deadline);\n\t\tif (outcome.kind === 'done') return;\n\t\tif (outcome.kind === 'retry') {\n\t\t\tawait sleep(SELECT_ACCOUNT_SLOT_POLL_MS);\n\t\t\tcontinue;\n\t\t}\n\t\tthrow args.onFail(outcome.cause);\n\t}\n};\n\n/**\n * Connect/switch the app's active dev-wallet account through the dapp-kit\n * slot the app populates at boot.\n *\n * This intentionally avoids driving the wallet UI. The app-side slot\n * implementation still goes through dapp-kit + wallet-standard, so pairing,\n * origin, and account discovery failures surface as real browser failures.\n */\nexport const connectAs = async (page: PlaywrightPageLike, accountName: string): Promise<void> => {\n\ttry {\n\t\tawait selectAccount(page, accountName);\n\t} catch (cause) {\n\t\tthrow new PlaywrightWalletAdapterError({\n\t\t\tmessage: `connectAs(\"${accountName}\") failed`,\n\t\t\toperation: 'switch-account',\n\t\t\tcause,\n\t\t});\n\t}\n};\n\n/**\n * Switch the dev-wallet's active account by routing through the\n * dapp-kit global slot the app populates at module init. Strictly\n * faster + less flaky than clicking the wallet's UI.\n */\nexport const selectAccount = async (\n\tpage: PlaywrightPageLike,\n\taccountName: string,\n): Promise<void> => {\n\t// `evaluate`'s closure is serialized into the browser; the slot\n\t// shape (`DAppKitSlot`) lives in `runtime/dapp-kit-slot.ts` — the\n\t// in-browser closure can't import it, but the global-augmentation\n\t// `globalThis.__devstackDAppKit__` is the typed contract both sides\n\t// rely on.\n\tawait pollSlotUntilDeadline<{ ok: boolean; reason?: string }>({\n\t\tpage,\n\t\t// `await` here collapses the page-bridge's nested promise (the browser\n\t\t// function is async) so the callback resolves to the awaited result.\n\t\tevaluate: async (p) =>\n\t\t\tawait p.evaluate(async (name): Promise<{ ok: boolean; reason?: string }> => {\n\t\t\t\tconst slot = (globalThis as { __devstackDAppKit__?: DAppKitSlot }).__devstackDAppKit__;\n\t\t\t\tif (slot === undefined || slot.selectAccount === undefined) {\n\t\t\t\t\treturn { ok: false, reason: 'slot-not-populated' };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait slot.selectAccount(name as string);\n\t\t\t\t\treturn { ok: true };\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\treason: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}, accountName),\n\t\tclassify: (result, beforeDeadline) => {\n\t\t\tif (result.ok) return { kind: 'done' };\n\t\t\tif (result.reason === 'slot-not-populated' && beforeDeadline) return { kind: 'retry' };\n\t\t\treturn { kind: 'fail', cause: result.reason };\n\t\t},\n\t\tonContextTimeout: (lastEvaluateError) =>\n\t\t\tnew PlaywrightWalletAdapterError({\n\t\t\t\tmessage:\n\t\t\t\t\t`selectAccount(\"${accountName}\") failed: page evaluation did not settle before ` +\n\t\t\t\t\t`${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading before ` +\n\t\t\t\t\t`calling connectAs().`,\n\t\t\t\toperation: 'switch-account',\n\t\t\t\tcause: lastEvaluateError,\n\t\t\t}),\n\t\tonFail: (cause) =>\n\t\t\tnew PlaywrightWalletAdapterError({\n\t\t\t\tmessage:\n\t\t\t\t\t`selectAccount(\"${accountName}\") failed: ${(cause as string | undefined) ?? 'unknown'}. ` +\n\t\t\t\t\t`Confirm \\`globalThis.${DAPP_KIT_SLOT}\\` is populated by the app's ` +\n\t\t\t\t\t`dapp-kit module at boot.`,\n\t\t\t\toperation: 'switch-account',\n\t\t\t\t// `cause` survives the `page.evaluate` boundary as a string —\n\t\t\t\t// the browser-side `Error` instance is lost across the bridge,\n\t\t\t\t// but the message is the load-bearing diagnostic. Preserving\n\t\t\t\t// it on the typed error keeps the underlying detail attached\n\t\t\t\t// when consumers inspect `cause` rather than `message`.\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n};\n\n/**\n * Switch the app's active dApp Kit network through the same dapp-kit slot\n * `selectAccount` uses — one level over (network instead of account). Drives\n * dApp Kit's public `switchNetwork`; the dev wallet (registered once via\n * wallet-standard) stays mounted across the switch — only the active\n * network/client changes.\n *\n * Resolution semantics:\n * - When the app exposes `currentNetwork`, resolves once the slot reports\n * the current network is `network` (the switch deterministically took\n * effect).\n * - When it does NOT, there is no post-switch confirmation signal, so the\n * helper lets the swap settle (see `SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS`)\n * rather than resolving the instant `switchNetwork()` returns `ok`.\n */\n// When the app's slot does not expose `currentNetwork`, the helper has no\n// post-switch signal to confirm the client swap propagated. Resolving the\n// instant `switchNetwork()` returns `ok` (before the swap settles) produces\n// flaky stale reads. Without a confirmation source we instead let the swap\n// settle: keep re-confirming the slot reports `ok` across this window before\n// accepting success. This is best-effort — apps that want a crisp signal\n// should expose `currentNetwork` so the switch is confirmed deterministically.\nconst SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS = 250;\n\nexport const switchNetwork = async (page: PlaywrightPageLike, network: string): Promise<void> => {\n\t// Tracks the first tick on which an unconfirmable switch (no\n\t// `currentNetwork` exposed) reported `ok`, so we can require the swap to\n\t// hold `ok` for a settle window rather than returning on the first tick.\n\tlet unconfirmedOkSince: number | undefined;\n\tawait pollSlotUntilDeadline<{ ok: boolean; reason?: string; current?: string }>({\n\t\tpage,\n\t\t// `await` here collapses the page-bridge's nested promise (the browser\n\t\t// function is async) so the callback resolves to the awaited result.\n\t\tevaluate: async (p) =>\n\t\t\tawait p.evaluate(async (net): Promise<{ ok: boolean; reason?: string; current?: string }> => {\n\t\t\t\tconst slot = (globalThis as { __devstackDAppKit__?: DAppKitSlot }).__devstackDAppKit__;\n\t\t\t\tif (slot === undefined || slot.switchNetwork === undefined) {\n\t\t\t\t\treturn { ok: false, reason: 'slot-not-populated' };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait slot.switchNetwork(net as string);\n\t\t\t\t\treturn { ok: true, current: slot.currentNetwork?.() };\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn { ok: false, reason: err instanceof Error ? err.message : String(err) };\n\t\t\t\t}\n\t\t\t}, network),\n\t\tclassify: (result, beforeDeadline) => {\n\t\t\tif (result.ok && result.current === network) return { kind: 'done' };\n\t\t\t// No `currentNetwork` to confirm against — accept `ok`, but only\n\t\t\t// after it has held across the settle window so the client swap has\n\t\t\t// a real chance to propagate before downstream reads.\n\t\t\tif (result.ok && result.current === undefined) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tunconfirmedOkSince ??= now;\n\t\t\t\tif (now - unconfirmedOkSince >= SWITCH_NETWORK_UNCONFIRMED_SETTLE_MS) {\n\t\t\t\t\treturn { kind: 'done' };\n\t\t\t\t}\n\t\t\t\treturn beforeDeadline ? { kind: 'retry' } : { kind: 'done' };\n\t\t\t}\n\t\t\t// `slot-not-populated`, or switched-but-not-yet-propagated\n\t\t\t// (`ok` with a stale `current`): keep polling until the deadline.\n\t\t\tif ((result.reason === 'slot-not-populated' || result.ok) && beforeDeadline) {\n\t\t\t\treturn { kind: 'retry' };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: 'fail',\n\t\t\t\tcause: result.reason ?? `current is \"${result.current}\"`,\n\t\t\t};\n\t\t},\n\t\tonContextTimeout: (lastEvaluateError) =>\n\t\t\tnew PlaywrightWalletAdapterError({\n\t\t\t\tmessage:\n\t\t\t\t\t`switchNetwork(\"${network}\") failed: page evaluation did not settle before ` +\n\t\t\t\t\t`${SELECT_ACCOUNT_SLOT_TIMEOUT_MS}ms. Confirm the app finished loading and ` +\n\t\t\t\t\t`\\`globalThis.${DAPP_KIT_SLOT}\\` is populated.`,\n\t\t\t\toperation: 'switch-network',\n\t\t\t\tcause: lastEvaluateError,\n\t\t\t}),\n\t\tonFail: (cause) =>\n\t\t\tnew PlaywrightWalletAdapterError({\n\t\t\t\tmessage:\n\t\t\t\t\t`switchNetwork(\"${network}\") failed: ${(cause as string | undefined) ?? 'unknown'}. ` +\n\t\t\t\t\t`Confirm the network is in the app's deployment (a committed deployments/${network}.ts ` +\n\t\t\t\t\t`or the live local stack) and \\`globalThis.${DAPP_KIT_SLOT}\\` is populated.`,\n\t\t\t\toperation: 'switch-network',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n};\n\n// -----------------------------------------------------------------------------\n// Artifact loaders\n// -----------------------------------------------------------------------------\n\n/** Test-side accessor for the full manifest (already decoded). */\nexport const loadStackManifest = (options: ResolveStackContextOptions = {}): StackContext =>\n\treadStackContext(options);\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  //#region src/build-integrations/runtime/dapp-kit-slot.ts
2
2
  /** The literal property name on `globalThis` that the app writes the
3
3
  * kit handle to. Renames here cascade through every consumer
4
- * (Playwright config-load, in-spec helpers, app-side dapp-kit-config
4
+ * (Playwright config-load, in-spec helpers, app-side dapp-kit
5
5
  * emit). The slot's name is part of the contract. */
6
6
  const DAPP_KIT_SLOT_KEY = "__devstackDAppKit__";
7
7
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"dapp-kit-slot.mjs","names":[],"sources":["../../../src/build-integrations/runtime/dapp-kit-slot.ts"],"sourcesContent":["// Typed contract for the `globalThis.__devstackDAppKit__` test bridge.\n//\n// This is intentionally narrow: app code writes only the account\n// switcher Playwright needs. It is not a place to stash the full\n// dAppKit instance or manifest projection.\n//\n// This module evaluates in browser bundles and in Node build\n// integration callers. Discipline: no `node:*` imports here.\n\n/** The literal property name on `globalThis` that the app writes the\n * kit handle to. Renames here cascade through every consumer\n * (Playwright config-load, in-spec helpers, app-side dapp-kit-config\n * emit). The slot's name is part of the contract. */\nexport const DAPP_KIT_SLOT_KEY = '__devstackDAppKit__' as const;\n\nexport interface DAppKitSlot {\n\t/** Account switcher entry point consumed by Playwright's\n\t * `connectAs` / `selectAccount` helpers. App dev-account UIs do NOT\n\t * read accounts from this slot — they read the connected wallet's\n\t * account list directly from dApp Kit (each account's `label` is the\n\t * devstack account name). */\n\treadonly selectAccount?: (accountName: string) => void | Promise<void>;\n}\n\ndeclare global {\n\t// eslint-disable-next-line no-var\n\tvar __devstackDAppKit__: DAppKitSlot | undefined;\n}\n"],"mappings":";;;;;AAaA,MAAa,oBAAoB"}
1
+ {"version":3,"file":"dapp-kit-slot.mjs","names":[],"sources":["../../../src/build-integrations/runtime/dapp-kit-slot.ts"],"sourcesContent":["// Typed contract for the `globalThis.__devstackDAppKit__` test bridge.\n//\n// This is intentionally narrow: app code writes only the account\n// switcher Playwright needs. It is not a place to stash the full\n// dAppKit instance or manifest projection.\n//\n// This module evaluates in browser bundles and in Node build\n// integration callers. Discipline: no `node:*` imports here.\n\n/** The literal property name on `globalThis` that the app writes the\n * kit handle to. Renames here cascade through every consumer\n * (Playwright config-load, in-spec helpers, app-side dapp-kit\n * emit). The slot's name is part of the contract. */\nexport const DAPP_KIT_SLOT_KEY = '__devstackDAppKit__' as const;\n\nexport interface DAppKitSlot {\n\t/** Account switcher entry point consumed by Playwright's\n\t * `connectAs` / `selectAccount` helpers. App dev-account UIs do NOT\n\t * read accounts from this slot — they read the connected wallet's\n\t * account list directly from dApp Kit (each account's `label` is the\n\t * devstack account name). */\n\treadonly selectAccount?: (accountName: string) => void | Promise<void>;\n\t/** Network switcher entry point consumed by Playwright's `switchNetwork`\n\t * helper. Calls dApp Kit's public `switchNetwork(network)` — the same\n\t * bridge mechanism as `selectAccount`, one level over (network instead of\n\t * account). The dev wallet stays registered across the switch; only the\n\t * active network/client changes. */\n\treadonly switchNetwork?: (network: string) => void | Promise<void>;\n\t/** Reads dApp Kit's current network name (`stores.$currentNetwork`) so the\n\t * helper can assert the switch took effect. */\n\treadonly currentNetwork?: () => string;\n}\n\ndeclare global {\n\t// eslint-disable-next-line no-var\n\tvar __devstackDAppKit__: DAppKitSlot | undefined;\n}\n"],"mappings":";;;;;AAaA,MAAa,oBAAoB"}
@@ -1,27 +1,18 @@
1
+ import { NetworkDeployment } from "../../orchestrators/codegen/deployment.mjs";
2
+
1
3
  //#region src/build-integrations/vite/index.d.ts
2
4
  /** Default import-alias prefix. Customizable via `options.alias` (some
3
5
  * apps prefer `@gen`, `~generated`, …). The app MUST use the SAME
4
6
  * prefix in three derivable places: this plugin option, the
5
7
  * `tsconfig` `paths` entry, and its import specifiers. */
6
8
  declare const DEFAULT_GENERATED_ALIAS = "@generated";
7
- /** Default dev-extras import-alias prefix. Resolves the PRIMARY stack's
8
- * `.devstack/stacks/<stack>/generated-extras` tree (dev-only / secret
9
- * artifacts — `accounts.ts`, `dev-wallet.ts`). Mirror the `@generated`
10
- * three-place discipline: this option, the `tsconfig` `paths` entry,
11
- * and the import specifiers. */
12
- declare const DEFAULT_DEV_EXTRAS_ALIAS = "@devstack-dev";
13
9
  interface DevstackVitePluginOptions {
14
10
  /** Import-alias prefix. Default `'@generated'`. */
15
11
  readonly alias?: string;
16
- /** Dev-extras import-alias prefix. Default `'@devstack-dev'`. */
17
- readonly devExtrasAlias?: string;
18
12
  /** Explicit generated dir — bypasses manifest discovery entirely
19
13
  * (escape hatch for unusual layouts / tests). Relative paths
20
14
  * resolve against the Vite root. */
21
15
  readonly generatedDir?: string;
22
- /** Explicit dev-extras dir — bypasses manifest discovery. Relative
23
- * paths resolve against the Vite root. */
24
- readonly extrasDir?: string;
25
16
  /** Inject + register the devstack dev wallet on the page in DEV
26
17
  * (wallet-standard, so dApp Kit auto-discovers it). Defaults to
27
18
  * `true`. Production builds (`command === 'build'`) inject nothing
@@ -30,33 +21,53 @@ interface DevstackVitePluginOptions {
30
21
  /** Auto-approve all dev-wallet signing requests (headless Playwright /
31
22
  * in-app "Open/Join as" buttons). Defaults to the `DEVSTACK_AUTO_APPROVE`
32
23
  * env (`'1'`/`'true'`), then to the active network's `autoApproveSigning`
33
- * per-network policy (ON for every network except live `mainnet`). A
34
- * single switch, replacing per-app `VITE_*_AUTO_APPROVE`.
24
+ * per-network policy (OFF by default on every network a normal `pnpm dev`
25
+ * shows the real connect + approve UX; opt in per-network). A single
26
+ * switch, replacing per-app `VITE_*_AUTO_APPROVE`.
35
27
  *
36
- * HARD-CLAMP: on live `mainnet` the per-network policy forces
28
+ * PRECEDENCE: an explicit value here ALWAYS wins — passing `autoApprove:
29
+ * false` forces it off even when `DEVSTACK_AUTO_APPROVE` is set, and
30
+ * `autoApprove: true` forces it on. The `DEVSTACK_AUTO_APPROVE` env and the
31
+ * per-network policy default apply ONLY when this option is left undefined.
32
+ *
33
+ * HARD-CLAMP: on live `mainnet` the per-network policy default forces
37
34
  * auto-approve OFF — a real-funds signature is NEVER granted without a
38
- * human in the loop. An explicit `autoApprove: true` here, or
39
- * `DEVSTACK_AUTO_APPROVE`, still take precedence (the author opted in
40
- * deliberately), but the policy default never silently auto-approves on
41
- * mainnet. */
35
+ * human in the loop. The policy default never silently auto-approves on
36
+ * mainnet; an explicit `autoApprove: true` (or, when this option is
37
+ * undefined, `DEVSTACK_AUTO_APPROVE`) is still the author opting in
38
+ * deliberately. */
42
39
  readonly autoApprove?: boolean;
43
40
  /** Per-network overrides for the dev-convenience policy (the same
44
41
  * `networkOptions` shape `defineDevstack` takes, forwarded verbatim).
45
42
  * Only the `autoApproveSigning` field is read here, to resolve the
46
43
  * auto-approve default for the active network. Omitted ⇒ the built-in
47
- * policy (ON except live `mainnet`) applies. The override RECORD is not
44
+ * policy (OFF by default; opt in per-network) applies. The override RECORD is not
48
45
  * otherwise on disk, so an app that customizes per-network signing must
49
46
  * thread it here explicitly; the mainnet hard-clamp holds regardless. */
50
47
  readonly networkOptions?: Readonly<Record<string, unknown>>;
51
- /** Production id-config FILEthe known deployment's `devstack-ids.json`
52
- * (same schema the dev stack writes), committed at e.g.
53
- * `config/<network>.ids.json`. Used only for `command === 'build'` to
54
- * inject `__DEVSTACK_IDS__`. Relative paths resolve against the Vite
55
- * root. If omitted, the `DEVSTACK_IDS_FILE` env (a path pointer) is used.
56
- * Neither no ids baked, and the generated resolver throws loudly at
57
- * id-access time. We deliberately take a FILE, not a JSON env blob: a
58
- * real deployment's ids are many + nested. */
59
- readonly ids?: string;
48
+ /** Committed, per-network PROD deployments `{ <net>: () => import('./deployments/<net>.ts') }`,
49
+ * each thunk resolving to `{ deployment: NetworkDeployment }` (the typed
50
+ * hand-written / `dump-deployment`-emitted file). These are the
51
+ * non-local networks a production `build` ships, and the additional
52
+ * networks a dev `serve` makes selectable alongside the live local one.
53
+ * Each thunk's `deployment` is validated against `NetworkDeploymentSchema`
54
+ * at config-load a malformed committed file fails LOUDLY rather than
55
+ * silently injecting a broken network.
56
+ *
57
+ * DEFAULT (when omitted): AUTO-DISCOVERY of `<root>/deployments/*.ts` (D7
58
+ * — "just drop a file"). Each filename (sans `.ts`) becomes a live network
59
+ * name keyed to a dynamic-`import()` thunk reading the file's `deployment`
60
+ * export. Supplying this option OVERRIDES auto-discovery entirely (a
61
+ * custom dir / explicit paths). No `deployments/` dir + no option ⇒ no
62
+ * committed networks. */
63
+ readonly deployments?: Readonly<Record<string, () => Promise<{
64
+ deployment: NetworkDeployment;
65
+ }>>>;
66
+ /** The network the app opens on when no live local network is present
67
+ * (a pure production build, or a dev serve with only committed
68
+ * networks). Defaults to the first committed network key. The live
69
+ * local network always wins as the default in dev. */
70
+ readonly defaultNetwork?: string;
60
71
  }
61
72
  /** A `vite` `Plugin`'s `config` hook receives the partial user config.
62
73
  * We only ever read `config.root` and return a `resolve.alias` patch,
@@ -98,7 +109,7 @@ interface ViteDevServerLike {
98
109
  }
99
110
  interface DevstackVitePlugin {
100
111
  readonly name: string;
101
- readonly config: (config: ViteUserConfigLike, env?: ViteConfigEnvLike) => {
112
+ readonly config: (config: ViteUserConfigLike, env?: ViteConfigEnvLike) => Promise<{
102
113
  readonly resolve: {
103
114
  readonly alias: Record<string, string>;
104
115
  readonly dedupe?: string[];
@@ -106,17 +117,18 @@ interface DevstackVitePlugin {
106
117
  readonly optimizeDeps?: {
107
118
  readonly include: string[];
108
119
  };
109
- /** `define` injecting the on-chain ids as `__DEVSTACK_IDS__`. In a
110
- * prod `build` this is the static id literal; in dev `serve` it is a
111
- * reference to the `globalThis.__DEVSTACK_IDS_LIVE__` runtime global
112
- * the `transformIndexHtml` hook sets fresh per page load, so a
113
- * republished id reaches the app on reload (`define` is fixed for the
114
- * dev server's lifetime and could never hot-update). */
120
+ /** `define` injecting the deployment envelope as
121
+ * `__DEVSTACK_DEPLOYMENT__`. In a prod `build` this is the static
122
+ * envelope literal; in dev `serve` it is a reference to the
123
+ * `globalThis.__DEVSTACK_DEPLOYMENT_LIVE__` runtime global the
124
+ * `transformIndexHtml` hook sets fresh per page load, so a republished
125
+ * id reaches the app on reload (`define` is fixed for the dev server's
126
+ * lifetime and could never hot-update). */
115
127
  readonly define: Record<string, string>;
116
- };
128
+ }>;
117
129
  /** Capture the resolved command so injection is DEV-only. */
118
130
  readonly configResolved: (config: ViteUserConfigLike) => void;
119
- /** Dev-only: watch the live `devstack-ids.json` and full-reload the page
131
+ /** Dev-only: watch the live `deployment.json` and full-reload the page
120
132
  * when it changes, so a republished package id (rewritten by the
121
133
  * supervisor's post-acquire hook) reaches the running app. */
122
134
  readonly configureServer: (server: ViteDevServerLike) => void;
@@ -124,10 +136,10 @@ interface DevstackVitePlugin {
124
136
  readonly resolveId: (id: string) => string | undefined;
125
137
  /** Emit the dev-wallet register module (or a no-op when not applicable). */
126
138
  readonly load: (id: string) => string | undefined;
127
- /** Inject the dev-only HTML tags: the `__DEVSTACK_IDS_LIVE__` global
128
- * (read fresh from the ids file per request) and, when the app carries
129
- * the dev wallet, the `<script type="module">` importing the virtual
130
- * module. The return shape mirrors a structural subset of Vite's
139
+ /** Inject the dev-only HTML tags: the `__DEVSTACK_DEPLOYMENT_LIVE__`
140
+ * global (read fresh from the deployment file per request) and, when the
141
+ * app carries the dev wallet, the `<script type="module">` importing the
142
+ * virtual module. The return shape mirrors a structural subset of Vite's
131
143
  * `IndexHtmlTransformResult` so the plugin stays assignable to Vite's
132
144
  * `Plugin` without devstack importing `vite`. */
133
145
  readonly transformIndexHtml: (html: string) => {
@@ -142,5 +154,5 @@ interface DevstackVitePlugin {
142
154
  }
143
155
  declare const devstackVitePlugin: (options?: DevstackVitePluginOptions) => DevstackVitePlugin;
144
156
  //#endregion
145
- export { DEFAULT_DEV_EXTRAS_ALIAS, DEFAULT_GENERATED_ALIAS, DevstackVitePlugin, DevstackVitePluginOptions, devstackVitePlugin };
157
+ export { DEFAULT_GENERATED_ALIAS, DevstackVitePlugin, DevstackVitePluginOptions, devstackVitePlugin };
146
158
  //# sourceMappingURL=index.d.mts.map