@mysten-incubation/devstack 0.3.0 → 0.5.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 (154) hide show
  1. package/README.md +10 -11
  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.d.mts +1 -1
  43. package/dist/index.mjs +1 -1
  44. package/dist/orchestrators/boot.d.mts +0 -10
  45. package/dist/orchestrators/boot.mjs +19 -59
  46. package/dist/orchestrators/boot.mjs.map +1 -1
  47. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  48. package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
  49. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
  50. package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
  51. package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
  52. package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
  53. package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
  54. package/dist/orchestrators/codegen/deployment.d.mts +63 -0
  55. package/dist/orchestrators/codegen/deployment.mjs +153 -0
  56. package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
  57. package/dist/orchestrators/codegen/errors.mjs +7 -9
  58. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  59. package/dist/orchestrators/codegen/format.mjs +20 -1
  60. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  61. package/dist/orchestrators/codegen/paths.mjs +1 -8
  62. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  63. package/dist/orchestrators/codegen/service.mjs +354 -141
  64. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  65. package/dist/orchestrators/layers.mjs +0 -1
  66. package/dist/orchestrators/layers.mjs.map +1 -1
  67. package/dist/orchestrators/network-options.d.mts +37 -35
  68. package/dist/orchestrators/network-options.mjs +13 -10
  69. package/dist/orchestrators/network-options.mjs.map +1 -1
  70. package/dist/plugins/account/codegen.d.mts +3 -4
  71. package/dist/plugins/account/codegen.mjs +5 -7
  72. package/dist/plugins/account/codegen.mjs.map +1 -1
  73. package/dist/plugins/account/index.mjs +1 -3
  74. package/dist/plugins/account/index.mjs.map +1 -1
  75. package/dist/plugins/coin/codegen.mjs +5 -5
  76. package/dist/plugins/coin/codegen.mjs.map +1 -1
  77. package/dist/plugins/coin/index.mjs.map +1 -1
  78. package/dist/plugins/dashboard/schema/root.mjs +3 -1
  79. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  80. package/dist/plugins/deepbook/codegen.mjs +4 -4
  81. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  82. package/dist/plugins/deepbook/index.d.mts +36 -6
  83. package/dist/plugins/deepbook/index.mjs +52 -16
  84. package/dist/plugins/deepbook/index.mjs.map +1 -1
  85. package/dist/plugins/internal/codegen-helpers.mjs +0 -1
  86. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  87. package/dist/plugins/package/codegen.d.mts +1 -12
  88. package/dist/plugins/package/codegen.mjs +43 -25
  89. package/dist/plugins/package/codegen.mjs.map +1 -1
  90. package/dist/plugins/package/dep-resolution.mjs +1 -1
  91. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  92. package/dist/plugins/package/index.d.mts +14 -11
  93. package/dist/plugins/package/index.mjs +6 -7
  94. package/dist/plugins/package/index.mjs.map +1 -1
  95. package/dist/plugins/seal/codegen.d.mts +5 -0
  96. package/dist/plugins/seal/codegen.mjs +55 -12
  97. package/dist/plugins/seal/codegen.mjs.map +1 -1
  98. package/dist/plugins/seal/index.d.mts +64 -19
  99. package/dist/plugins/seal/index.mjs +26 -36
  100. package/dist/plugins/seal/index.mjs.map +1 -1
  101. package/dist/plugins/seal/mode/fork-known.d.mts +0 -2
  102. package/dist/plugins/seal/mode/fork-known.mjs +11 -22
  103. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  104. package/dist/plugins/seal/mode/live.d.mts +36 -13
  105. package/dist/plugins/seal/mode/live.mjs +104 -43
  106. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  107. package/dist/plugins/seal/mode/local-keygen.mjs +2 -1
  108. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  109. package/dist/plugins/seal/registry-publish.d.mts +15 -3
  110. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  111. package/dist/plugins/sui/codegen.mjs +5 -4
  112. package/dist/plugins/sui/codegen.mjs.map +1 -1
  113. package/dist/plugins/sui/index.mjs +1 -2
  114. package/dist/plugins/sui/index.mjs.map +1 -1
  115. package/dist/plugins/wallet/codegen.d.mts +8 -12
  116. package/dist/plugins/wallet/codegen.mjs +22 -15
  117. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  118. package/dist/plugins/wallet/index.d.mts +4 -3
  119. package/dist/plugins/wallet/index.mjs +1 -1
  120. package/dist/plugins/wallet/index.mjs.map +1 -1
  121. package/dist/plugins/wallet/service.d.mts +2 -2
  122. package/dist/plugins/wallet/service.mjs +2 -3
  123. package/dist/plugins/wallet/service.mjs.map +1 -1
  124. package/dist/plugins/walrus/codegen.mjs +4 -4
  125. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  126. package/dist/plugins/walrus/index.d.mts +137 -8
  127. package/dist/plugins/walrus/index.mjs +46 -9
  128. package/dist/plugins/walrus/index.mjs.map +1 -1
  129. package/dist/plugins/walrus/mode/known-deploy.d.mts +5 -1
  130. package/dist/plugins/walrus/mode/known-deploy.mjs +13 -10
  131. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  132. package/dist/substrate/manifest.d.mts +17 -22
  133. package/dist/substrate/manifest.mjs +4 -6
  134. package/dist/substrate/manifest.mjs.map +1 -1
  135. package/dist/substrate/plugin-ctx.d.mts +6 -6
  136. package/dist/substrate/plugin-ctx.mjs.map +1 -1
  137. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  138. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  139. package/dist/substrate/runtime/paths.mjs +1 -1
  140. package/dist/surfaces/cli/command-tree.mjs +6 -6
  141. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  142. package/dist/surfaces/cli/index.mjs +6 -4
  143. package/dist/surfaces/cli/index.mjs.map +1 -1
  144. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  145. package/package.json +2 -2
  146. package/dist/cli/wirings/dump-ids.mjs +0 -86
  147. package/dist/cli/wirings/dump-ids.mjs.map +0 -1
  148. package/dist/orchestrators/codegen/id-config.d.mts +0 -1
  149. package/dist/orchestrators/codegen/id-config.mjs +0 -107
  150. package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
  151. package/dist/orchestrators/codegen/output-location.mjs +0 -32
  152. package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
  153. package/dist/plugins/seal/service.mjs +0 -17
  154. package/dist/plugins/seal/service.mjs.map +0 -1
@@ -1,22 +1,17 @@
1
- import { decodeIdConfig } from "../../orchestrators/codegen/id-config.mjs";
2
- import { resolveNetworkOptions } from "../../orchestrators/network-options.mjs";
1
+ import { decodeDeployment, decodeNetworkDeployment } from "../../orchestrators/codegen/deployment.mjs";
3
2
  import { resolveDiscoveryEnv } from "../runtime/resolve-discovery-env.mjs";
4
3
  import { discoverManifestPath } from "../runtime/discover.mjs";
5
4
  import "../runtime/index.mjs";
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { isAbsolute, resolve } from "node:path";
5
+ import { resolveNetworkOptions } from "../../orchestrators/network-options.mjs";
6
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
7
+ import { dirname, resolve } from "node:path";
8
+ import { pathToFileURL } from "node:url";
8
9
  //#region src/build-integrations/vite/index.ts
9
10
  /** Default import-alias prefix. Customizable via `options.alias` (some
10
11
  * apps prefer `@gen`, `~generated`, …). The app MUST use the SAME
11
12
  * prefix in three derivable places: this plugin option, the
12
13
  * `tsconfig` `paths` entry, and its import specifiers. */
13
14
  const DEFAULT_GENERATED_ALIAS = "@generated";
14
- /** Default dev-extras import-alias prefix. Resolves the PRIMARY stack's
15
- * `.devstack/stacks/<stack>/generated-extras` tree (dev-only / secret
16
- * artifacts — `accounts.ts`, `dev-wallet.ts`). Mirror the `@generated`
17
- * three-place discipline: this option, the `tsconfig` `paths` entry,
18
- * and the import specifiers. */
19
- const DEFAULT_DEV_EXTRAS_ALIAS = "@devstack-dev";
20
15
  /** The committed generated-bindings subpath, relative to the Vite root.
21
16
  * The single source of bindings — written by `devstack codegen` — that
22
17
  * `@generated` always resolves to (absent the `options.generatedDir`
@@ -32,7 +27,7 @@ const RESOLVED_VIRTUAL_DEV_WALLET_ID = "\0virtual:devstack-dev-wallet";
32
27
  * misroutes to the SPA fallback). Used for the injected `<script src>`. */
33
28
  const VIRTUAL_DEV_WALLET_SCRIPT_SRC = `/@id/__x00__${VIRTUAL_DEV_WALLET_ID}`;
34
29
  /** Best-effort, SYNC read of a string-valued field at `dottedPath` (e.g.
35
- * `'codegen.idsFile'`, `'identity.network'`) from the active stack's
30
+ * `'codegen.deploymentFile'`, `'identity.network'`) from the active stack's
36
31
  * manifest. Walks each path segment as a nested object, returning the leaf
37
32
  * value, or `null` on ANY miss (absent / partially-written / version-
38
33
  * mismatched manifest, a non-object hop, a missing or non-string/empty
@@ -41,9 +36,9 @@ const VIRTUAL_DEV_WALLET_SCRIPT_SRC = `/@id/__x00__${VIRTUAL_DEV_WALLET_ID}`;
41
36
  * and throws on a version mismatch) so an out-of-date or partially-written
42
37
  * manifest degrades gracefully instead of crashing the dev server. Never
43
38
  * throws — the single discover→parse→guard→degrade-to-null reader every
44
- * manifest field above (`codegen.idsFile`, `codegen.extrasDir`,
45
- * `identity.network`) routes through. */
46
- const readManifestField = (env, cwd, dottedPath) => {
39
+ * manifest field above (`codegen.deploymentFile`, `identity.network`)
40
+ * routes through. */
41
+ const readManifestObject = (env, cwd) => {
47
42
  try {
48
43
  const { stack, stateDir } = resolveDiscoveryEnv(env, { cwd });
49
44
  const manifestPath = discoverManifestPath({
@@ -53,49 +48,138 @@ const readManifestField = (env, cwd, dottedPath) => {
53
48
  cwd
54
49
  });
55
50
  if (manifestPath === void 0 || !existsSync(manifestPath)) return null;
56
- let node = JSON.parse(readFileSync(manifestPath, "utf8"));
57
- for (const segment of dottedPath.split(".")) {
58
- if (typeof node !== "object" || node === null) return null;
59
- node = node[segment];
60
- }
61
- return typeof node === "string" && node.length > 0 ? node : null;
51
+ return JSON.parse(readFileSync(manifestPath, "utf8"));
62
52
  } catch {
63
53
  return null;
64
54
  }
65
55
  };
66
- /** The gitignored `devstack-ids.json` path the boot wrote for the active
67
- * stack (`codegen.idsFile`), or `null` on any miss. */
68
- const readIdsFileFromManifest = (env, cwd) => readManifestField(env, cwd, "codegen.idsFile");
69
- /** SYNC read + schema-decode of an id-config FILE. The MISSING-file case
70
- * (absent path, no file on disk) collapses to `null` so the Vite config
56
+ /** Walk `dottedPath` over an already-parsed manifest object, returning the
57
+ * non-empty string leaf or `null` on ANY miss (non-object hop, missing /
58
+ * non-string / empty leaf). Lets one parsed manifest serve several field
59
+ * reads without re-parsing. */
60
+ const pickManifestString = (manifest, dottedPath) => {
61
+ let node = manifest;
62
+ for (const segment of dottedPath.split(".")) {
63
+ if (typeof node !== "object" || node === null) return null;
64
+ node = node[segment];
65
+ }
66
+ return typeof node === "string" && node.length > 0 ? node : null;
67
+ };
68
+ const readManifestField = (env, cwd, dottedPath) => pickManifestString(readManifestObject(env, cwd), dottedPath);
69
+ /** The gitignored `deployment.json` path the boot wrote for the active
70
+ * stack (`codegen.deploymentFile`), or `null` on any miss. */
71
+ const readIdsFileFromManifest = (env, cwd) => readManifestField(env, cwd, "codegen.deploymentFile");
72
+ /** SYNC read + schema-decode of a deployment ENVELOPE file. The MISSING-file
73
+ * case (absent path, no file on disk) collapses to `null` so the Vite config
71
74
  * load degrades gracefully when no stack has booted / no committed file is
72
- * wired. A PRESENT-but-malformed file is NOT swallowed: it flows through
73
- * the shared {@link decodeIdConfig}, which THROWS on bad JSON or a shape
74
- * that violates `IdConfigSchema` — surfacing a genuinely broken committed
75
- * id-config at config-load instead of silently injecting `null`. */
76
- const readIdConfigFile = (idsFile) => {
77
- if (idsFile === null || !existsSync(idsFile)) return null;
78
- return decodeIdConfig(readFileSync(idsFile, "utf8"));
75
+ * wired. A PRESENT-but-malformed file is NOT swallowed: it flows through the
76
+ * shared {@link decodeDeployment}, which THROWS on bad JSON or a shape that
77
+ * violates `DevstackDeploymentSchema` — surfacing a genuinely broken
78
+ * deployment at config-load instead of silently injecting `null`. */
79
+ const readDeploymentFile = (file) => {
80
+ if (file === null || !existsSync(file)) return null;
81
+ return decodeDeployment(readFileSync(file, "utf8"));
82
+ };
83
+ /** The LIVE local-stack deployment envelope for the active stack — the
84
+ * `deployment.json` boot wrote (via the manifest `codegen.deploymentFile`),
85
+ * or `null` on any miss. Read fresh so a republish reaches the app. */
86
+ const readLiveEnvelope = (env, root) => readDeploymentFile(readIdsFileFromManifest(env, root));
87
+ /** Resolve + validate the committed per-network deployments — the
88
+ * `deployments` option's thunks, each `() => Promise<{ deployment }>`. Each
89
+ * `deployment` is validated against `NetworkDeploymentSchema` (loud-fail on a
90
+ * malformed committed file) and stamped `{ network: <key>, local: false }` so
91
+ * the envelope key is authoritative and the deploy filter treats it as a real
92
+ * (non-local) network. Empty when no `deployments` are supplied. */
93
+ const resolveCommittedNetworks = async (deployments) => {
94
+ const committed = {};
95
+ for (const [net, thunk] of Object.entries(deployments)) committed[net] = {
96
+ ...decodeNetworkDeployment((await thunk()).deployment, `deployments['${net}']`),
97
+ network: net,
98
+ local: false
99
+ };
100
+ return committed;
101
+ };
102
+ /** Auto-discover the committed per-network deployment thunks by globbing
103
+ * `<root>/deployments/*.ts` (D7 — "just drop a file" UX). Each filename
104
+ * (sans `.ts`) becomes a live network name keyed to a thunk that
105
+ * dynamically `import()`s the absolute file path and reads its `deployment`
106
+ * export (the `dump-deployment`-emitted / hand-written
107
+ * `export const deployment = {…} satisfies AppNetworkDeployment`). Returns
108
+ * `{}` when there is no `deployments/` dir (a clean clone / template — a
109
+ * pure types-only `deployment.ts` with an empty `ProvidedDeployments`). The
110
+ * explicit `deployments` option overrides this entirely (custom dir/paths).
111
+ * File CONTENTS are not read here — only the import is wired; ids load when
112
+ * Vite transforms the thunk at build/serve. */
113
+ const autoDiscoverDeployments = (root) => {
114
+ const deploymentsDir = resolve(root, "deployments");
115
+ if (!existsSync(deploymentsDir)) return {};
116
+ const thunks = {};
117
+ let files;
118
+ try {
119
+ files = readdirSync(deploymentsDir);
120
+ } catch {
121
+ return {};
122
+ }
123
+ for (const file of files) {
124
+ if (!file.endsWith(".ts") || file.endsWith(".d.ts")) continue;
125
+ const net = file.slice(0, -3);
126
+ if (net.length === 0) continue;
127
+ const abs = resolve(deploymentsDir, file);
128
+ thunks[net] = () => import(
129
+ /* @vite-ignore */
130
+ pathToFileURL(abs).href
131
+ );
132
+ }
133
+ return thunks;
79
134
  };
80
- /** Resolve the on-chain ids to inject as the `__DEVSTACK_IDS__` global —
81
- * ALWAYS from an id-config FILE (same schema in dev and prod), never a
82
- * JSON env blob. Dev (`serve`): the live `devstack-ids.json` (via the
83
- * manifest `codegen.idsFile`). Prod (`build`): the committed known-
84
- * deployment file the plugin `ids` option, else the `DEVSTACK_IDS_FILE`
85
- * env (a PATH pointer, not data). Neither ⇒ `null`, so the generated
86
- * resolver throws loudly at id-access time. */
87
- const resolveInjectedIds = (env, root, command, idsOption) => {
135
+ /** The committed per-network deployments to merge the explicit
136
+ * `deployments` option when supplied, else auto-discovery of
137
+ * `<root>/deployments/*.ts` (D7). */
138
+ const resolveDeploymentThunks = (options, root) => options.deployments !== void 0 ? { ...options.deployments } : autoDiscoverDeployments(root);
139
+ /** The first key of a record, or `undefined` when empty. */
140
+ const firstKey = (record) => Object.keys(record)[0];
141
+ /** Merge the committed + live deployments into the envelope to inject as
142
+ * `__DEVSTACK_DEPLOYMENT__`.
143
+ * - `command === 'build'` (DEPLOY): the committed, NON-local networks only —
144
+ * the live local network is dropped. Empty ⇒ `null` (the generated
145
+ * resolver throws loudly at access time).
146
+ * - dev `serve` (and config-load default): the committed networks OVERLAID
147
+ * with the live local network(s), the live default winning. No live
148
+ * envelope ⇒ committed only (default = `defaultNetwork` option / first
149
+ * committed key).
150
+ * The live envelope's entries are forced `local: true` (they ARE the running
151
+ * local stack) so a later `build` would drop them. */
152
+ const mergeDeployment = (command, committed, live, defaultNetworkOption) => {
88
153
  if (command === "build") {
89
- const pointer = idsOption ?? env["DEVSTACK_IDS_FILE"];
90
- if (pointer === void 0 || pointer.length === 0) return null;
91
- return readIdConfigFile(isAbsolute(pointer) ? pointer : resolve(root, pointer));
154
+ if (Object.keys(committed).length === 0) return null;
155
+ const fallback = firstKey(committed);
156
+ return {
157
+ defaultNetwork: defaultNetworkOption !== void 0 && committed[defaultNetworkOption] !== void 0 ? defaultNetworkOption : fallback,
158
+ networks: committed,
159
+ accounts: {}
160
+ };
161
+ }
162
+ const networks = { ...committed };
163
+ if (live !== null) {
164
+ for (const [net, dep] of Object.entries(live.networks)) networks[net] = {
165
+ ...dep,
166
+ network: net,
167
+ local: true
168
+ };
169
+ return {
170
+ defaultNetwork: live.defaultNetwork,
171
+ networks,
172
+ accounts: live.accounts ?? {}
173
+ };
92
174
  }
93
- return readIdConfigFile(readIdsFileFromManifest(env, root));
175
+ const fallback = firstKey(networks);
176
+ if (fallback === void 0) return null;
177
+ return {
178
+ defaultNetwork: defaultNetworkOption !== void 0 && networks[defaultNetworkOption] !== void 0 ? defaultNetworkOption : fallback,
179
+ networks,
180
+ accounts: {}
181
+ };
94
182
  };
95
- /** The manifest-recorded dev-extras tree (`codegen.extrasDir`) the
96
- * `@devstack-dev` alias points at for the active stack, or `null` on any
97
- * miss. */
98
- const readExtrasDirFromManifest = (env, cwd) => readManifestField(env, cwd, "codegen.extrasDir");
99
183
  /**
100
184
  * Build the devstack Vite plugin that aliases `options.alias`
101
185
  * (default `@generated`) at the committed `<root>/src/generated` tree.
@@ -106,34 +190,53 @@ const readExtrasDirFromManifest = (env, cwd) => readManifestField(env, cwd, "cod
106
190
  * // or devstackVitePlugin({ alias: '@gen' })
107
191
  *
108
192
  * The plugin's `config` hook merges `resolve.alias[<prefix>] = <dir>`
109
- * into the user config (Vite deep-merges the returned partial). Sync;
110
- * reads `process.env` + the manifest (for `__DEVSTACK_IDS__` / the
111
- * `@devstack-dev` extras dir) once at config-load.
193
+ * into the user config (Vite deep-merges the returned partial). Async
194
+ * (it awaits the committed `deployments` thunks); reads `process.env` +
195
+ * the manifest (for `__DEVSTACK_DEPLOYMENT__`) once at config-load.
112
196
  */
113
- /** Derive the cold-start fallback dev-extras dir
114
- * (`<root>/.devstack/stacks/<stack>/generated-extras`) for the active
115
- * stack used when no manifest / `codegen.extrasDir` is on disk yet.
116
- * Mirrors `output-location.ts`'s `extrasDirFor`. Best-effort: a
117
- * discovery failure collapses to the `default` stack name. */
118
- const fallbackExtrasDir = (env, root) => {
119
- let stack = "default";
197
+ /** The on-disk dev-wallet pairing-token for the active stack, given the
198
+ * already-resolved `deploymentFile` path (the manifest's
199
+ * `codegen.deploymentFile`). The token lives in a `0o600` side-channel file
200
+ * (`<stackRoot>/wallet/token`, written by `pairing.ts`), NEVER in the
201
+ * world-readable `deployment.json`. The boot writes `deployment.json` into the
202
+ * SAME `<stackRoot>`, so the token sits at `<dirname(deploymentFile)>/wallet/
203
+ * token`. Read in Node by the `load` hook (which runs server-side) so the
204
+ * secret stays off the manifest/deployment surface. Returns `null` on any
205
+ * miss (including a `null` deployment file). */
206
+ const readDevWalletToken = (deploymentFile) => {
207
+ if (deploymentFile === null) return null;
208
+ const tokenFile = resolve(dirname(deploymentFile), "wallet", "token");
120
209
  try {
121
- stack = resolveDiscoveryEnv(env, { cwd: root }).stack;
122
- } catch {}
123
- return resolve(root, ".devstack", "stacks", stack, "generated-extras");
124
- };
125
- /** Resolve the dev-extras dir for the active stack (shared by the alias
126
- * config and the dev-wallet virtual module). Explicit option wins, else
127
- * manifest `codegen.extrasDir`, else the derived cold-start path. */
128
- const resolveExtrasDir = (options, root, env) => {
129
- const explicitExtras = options.extrasDir;
130
- return explicitExtras !== void 0 ? resolve(root, explicitExtras) : readExtrasDirFromManifest(env, root) ?? fallbackExtrasDir(env, root);
210
+ if (!existsSync(tokenFile)) return null;
211
+ const raw = readFileSync(tokenFile, "utf8").trim();
212
+ return /^[0-9a-f]{32}$/.test(raw) ? raw : null;
213
+ } catch {
214
+ return null;
215
+ }
131
216
  };
217
+ /** Escape a `JSON.stringify` result for safe embedding in an inline
218
+ * `<script>` element's text. Unlike an external file, inline-script text is
219
+ * parsed by the HTML tokenizer first, so a raw `<\/script>` (or `<!--`) inside
220
+ * any string value would terminate the tag early — and a lone `<` is enough to
221
+ * matter. We escape `<` / `>` / `&` to their `\uXXXX` JS-string forms (valid
222
+ * inside JSON-as-JS, and inert to the HTML tokenizer) and the U+2028/U+2029
223
+ * line separators (legal in JSON strings but illegal as raw JS line
224
+ * terminators in older engines). Used ONLY on the inline-script injection path
225
+ * — the `define` build path embeds into a JS module, not HTML, so it needs no
226
+ * such escaping. */
227
+ const escapeForInlineScript = (json) => json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/[\u2028\u2029]/g, (ch) => "\\u" + ch.charCodeAt(0).toString(16).padStart(4, "0"));
228
+ /** A boolean env flag is truthy when set to `'1'` or `'true'`
229
+ * (case-insensitive). Shared by the auto-approve + e2e env readers. */
230
+ const isTruthyEnvFlag = (raw) => raw === "1" || raw?.toLowerCase() === "true";
132
231
  /** Read the `DEVSTACK_AUTO_APPROVE` env (`'1'`/`'true'`, case-insensitive). */
133
- const autoApproveFromEnv = (env) => {
134
- const raw = env["DEVSTACK_AUTO_APPROVE"];
135
- return raw === "1" || raw?.toLowerCase() === "true";
136
- };
232
+ const autoApproveFromEnv = (env) => isTruthyEnvFlag(env["DEVSTACK_AUTO_APPROVE"]);
233
+ /** True under a Playwright e2e run (`DEVSTACK_E2E` set to `'1'`/`'true'`,
234
+ * case-insensitive). DEDICATED signal distinct from `DEVSTACK_AUTO_APPROVE`
235
+ * — driving the injected `__DEVSTACK_E2E__` global. Gates dApp Kit's
236
+ * `autoConnect` ON only under e2e, so a normal `pnpm dev` serve exercises the
237
+ * real connect UX. A prod `vite build` never sets the env ⇒ injects `false`
238
+ * (tree-shakeable). */
239
+ const e2eFromEnv = (env) => isTruthyEnvFlag(env["DEVSTACK_E2E"]);
137
240
  /** Lit packages deduped to a single instance. The injected dev-wallet UI and
138
241
  * the app's dapp-kit UI are both Lit-based; if Vite loads two Lit copies they
139
242
  * register custom elements in separate realms, and the second realm's element
@@ -177,35 +280,47 @@ const DEV_WALLET_OPTIMIZE_ENTRIES = ["@mysten-incubation/dev-wallet/inject", "@m
177
280
  const devWalletInstalled = (root) => existsSync(resolve(root, "node_modules", "@mysten-incubation", "dev-wallet", "package.json"));
178
281
  const devstackVitePlugin = (options = {}) => {
179
282
  const alias = options.alias ?? "@generated";
180
- const devExtrasAlias = options.devExtrasAlias ?? "@devstack-dev";
181
283
  const injectDevWallet = options.injectDevWallet ?? true;
182
284
  let resolvedRoot = process.cwd();
183
- let resolvedExtrasDir = null;
184
285
  let isServe = false;
286
+ let devWalletPresent = false;
287
+ let resolvedCommittedNetworks = {};
288
+ let liveEnvelopeFresh = false;
289
+ let liveEnvelopeCache = null;
290
+ const readLiveEnvelopeCached = (env) => {
291
+ if (liveEnvelopeFresh) return liveEnvelopeCache;
292
+ const live = readLiveEnvelope(env, resolvedRoot);
293
+ if (live !== null) {
294
+ liveEnvelopeCache = live;
295
+ liveEnvelopeFresh = true;
296
+ } else liveEnvelopeCache = null;
297
+ return live;
298
+ };
185
299
  return {
186
300
  name: "devstack:generated-alias",
187
- config: (config, configEnv) => {
301
+ config: async (config, configEnv) => {
188
302
  const root = config.root ?? process.cwd();
189
303
  resolvedRoot = root;
190
304
  const env = process.env;
191
305
  const command = configEnv?.command ?? config.command ?? "build";
192
306
  const explicit = options.generatedDir;
193
307
  const generatedDir = explicit !== void 0 ? resolve(root, explicit) : resolve(root, GENERATED_SUBPATH);
194
- const extrasDir = resolveExtrasDir(options, root, env);
195
- resolvedExtrasDir = extrasDir;
196
- const includeDevWallet = injectDevWallet && devWalletInstalled(root);
197
- const injectedIds = resolveInjectedIds(env, root, command, options.ids);
308
+ devWalletPresent = devWalletInstalled(root);
309
+ const includeDevWallet = injectDevWallet && devWalletPresent;
310
+ resolvedCommittedNetworks = await resolveCommittedNetworks(resolveDeploymentThunks(options, root));
311
+ const injectedLive = command === "build" ? null : readLiveEnvelope(env, root);
312
+ const injectedDeployment = mergeDeployment(command, resolvedCommittedNetworks, injectedLive, options.defaultNetwork);
198
313
  const isVitest = env["VITEST"] !== void 0;
199
- const idsDefine = command === "serve" && !isVitest ? "globalThis.__DEVSTACK_IDS_LIVE__" : JSON.stringify(injectedIds ?? null);
314
+ const deploymentDefine = command === "serve" && !isVitest ? "globalThis.__DEVSTACK_DEPLOYMENT_LIVE__" : JSON.stringify(injectedDeployment ?? null);
200
315
  return {
201
316
  resolve: {
202
- alias: {
203
- [alias]: generatedDir,
204
- [devExtrasAlias]: extrasDir
205
- },
317
+ alias: { [alias]: generatedDir },
206
318
  dedupe: resolvableLitDedupe(root)
207
319
  },
208
- define: { __DEVSTACK_IDS__: idsDefine },
320
+ define: {
321
+ __DEVSTACK_DEPLOYMENT__: deploymentDefine,
322
+ __DEVSTACK_E2E__: JSON.stringify(e2eFromEnv(env))
323
+ },
209
324
  ...includeDevWallet ? { optimizeDeps: { include: [...DEV_WALLET_OPTIMIZE_ENTRIES] } } : {}
210
325
  };
211
326
  },
@@ -217,28 +332,44 @@ const devstackVitePlugin = (options = {}) => {
217
332
  },
218
333
  load: (id) => {
219
334
  if (id !== RESOLVED_VIRTUAL_DEV_WALLET_ID) return void 0;
220
- const extrasDir = resolvedExtrasDir ?? resolveExtrasDir(options, resolvedRoot, process.env);
221
- const devWalletFile = resolve(extrasDir, "dev-wallet.ts");
222
- const accountsFile = resolve(extrasDir, "accounts.ts");
223
- if (!injectDevWallet || !isServe || !existsSync(devWalletFile) || !existsSync(accountsFile)) return "export {};";
224
335
  const env = process.env;
225
- const netOpts = resolveNetworkOptions(readManifestField(env, resolvedRoot, "identity.network") ?? "mainnet", options.networkOptions);
336
+ const manifest = readManifestObject(env, resolvedRoot);
337
+ const token = readDevWalletToken(pickManifestString(manifest, "codegen.deploymentFile"));
338
+ if (!injectDevWallet || !isServe || token === null) return "export {};";
339
+ const netOpts = resolveNetworkOptions(pickManifestString(manifest, "identity.network") ?? "mainnet", options.networkOptions);
226
340
  const autoApprove = options.autoApprove ?? (autoApproveFromEnv(env) || netOpts.autoApproveSigning);
227
341
  return [
228
342
  `import { registerDevstackDevWallet } from '@mysten-incubation/dev-wallet/inject';`,
229
- `import { parseDevstackToken } from '@mysten-incubation/dev-wallet/adapters';`,
230
- `import { devWallet } from '${devExtrasAlias}/dev-wallet.js';`,
231
- `import { accounts } from '${devExtrasAlias}/accounts.js';`,
232
343
  `import { config as __devstackConfig } from '${alias}/config.js';`,
233
- `registerDevstackDevWallet({`,
234
- ` serverOrigin: devWallet.walletUrl,`,
235
- ` token: parseDevstackToken(devWallet.pairUrl),`,
236
- ` accounts,`,
237
- ` rpcUrl: __devstackConfig.networks[__devstackConfig.network].rpc,`,
238
- ` network: devWallet.network,`,
239
- ` autoApprove: ${autoApprove ? "true" : "false"},`,
240
- ` mountUI: true,`,
241
- `}).catch((err) => console.error('[devstack] dev-wallet injection failed:', err));`
344
+ `import { resolveAccounts, optionalValue } from '${alias}/config-runtime.js';`,
345
+ `const __devstackToken = ${JSON.stringify(token)};`,
346
+ `const __devstackAccounts = Object.fromEntries(`,
347
+ ` Object.entries(resolveAccounts()).map(([__name, __address]) => [`,
348
+ ` __name,`,
349
+ ` { name: __name, address: __address },`,
350
+ ` ]),`,
351
+ `);`,
352
+ `const __devstackNetworks = Object.fromEntries(`,
353
+ ` Object.entries(__devstackConfig.networks).map(([__net, __dep]) => [`,
354
+ ` __net,`,
355
+ ` { rpc: __dep.rpc, faucet: __dep.faucet ?? null },`,
356
+ ` ]),`,
357
+ `);`,
358
+ `const __devstackDefaultDep = __devstackConfig.networks[__devstackConfig.defaultNetwork];`,
359
+ `const __devstackConnection = __devstackDefaultDep`,
360
+ ` ? optionalValue(__devstackDefaultDep, 'dev-wallet', 'connection')`,
361
+ ` : undefined;`,
362
+ `if (__devstackConnection) {`,
363
+ ` registerDevstackDevWallet({`,
364
+ ` serverOrigin: __devstackConnection.walletUrl,`,
365
+ ` token: __devstackToken,`,
366
+ ` accounts: __devstackAccounts,`,
367
+ ` networks: __devstackNetworks,`,
368
+ ` defaultNetwork: __devstackConfig.defaultNetwork,`,
369
+ ` autoApprove: ${autoApprove ? "true" : "false"},`,
370
+ ` mountUI: true,`,
371
+ ` }).catch((err) => console.error('[devstack] dev-wallet injection failed:', err));`,
372
+ `}`
242
373
  ].join("\n");
243
374
  },
244
375
  configureServer: (server) => {
@@ -249,6 +380,7 @@ const devstackVitePlugin = (options = {}) => {
249
380
  server.watcher.add(idsFile);
250
381
  const reloadOnIdsChange = (changed) => {
251
382
  if (resolve(resolvedRoot, changed) !== resolve(idsFile)) return;
383
+ liveEnvelopeFresh = false;
252
384
  (server.hot ?? server.ws)?.send({ type: "full-reload" });
253
385
  };
254
386
  server.watcher.on("change", reloadOnIdsChange);
@@ -257,13 +389,14 @@ const devstackVitePlugin = (options = {}) => {
257
389
  transformIndexHtml: (html) => {
258
390
  if (!isServe) return void 0;
259
391
  const env = process.env;
260
- const liveIds = resolveInjectedIds(env, resolvedRoot, "serve", options.ids);
392
+ const live = readLiveEnvelopeCached(env);
393
+ const liveDeployment = mergeDeployment("serve", resolvedCommittedNetworks, live, options.defaultNetwork);
261
394
  const tags = [{
262
395
  tag: "script",
263
- children: `globalThis.__DEVSTACK_IDS_LIVE__ = ${JSON.stringify(liveIds ?? null)};`,
396
+ children: `globalThis.__DEVSTACK_DEPLOYMENT_LIVE__ = ${escapeForInlineScript(JSON.stringify(liveDeployment ?? null))};`,
264
397
  injectTo: "head-prepend"
265
398
  }];
266
- if (injectDevWallet && devWalletInstalled(resolvedRoot)) tags.push({
399
+ if (injectDevWallet && devWalletPresent) tags.push({
267
400
  tag: "script",
268
401
  attrs: {
269
402
  type: "module",
@@ -279,6 +412,6 @@ const devstackVitePlugin = (options = {}) => {
279
412
  };
280
413
  };
281
414
  //#endregion
282
- export { DEFAULT_DEV_EXTRAS_ALIAS, DEFAULT_GENERATED_ALIAS, devstackVitePlugin };
415
+ export { DEFAULT_GENERATED_ALIAS, devstackVitePlugin };
283
416
 
284
417
  //# sourceMappingURL=index.mjs.map