@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
@@ -16,22 +16,24 @@ const setAtPath = (root, path, value) => {
16
16
  }
17
17
  cursor[path[path.length - 1]] = value;
18
18
  };
19
- /** The `rawExpr` the STATIC path emits for a resolved binding. */
19
+ /** The `rawExpr` the STATIC path emits for a resolved binding. Reads off the
20
+ * loaded deployment's active network — the emitted file carries a
21
+ * `const dep = __deployment.forNetwork(__deployment.defaultNetwork);`
22
+ * preamble (wired by the codegen orchestrator), so these expressions
23
+ * reference `dep` / `__deployment` directly. */
20
24
  const staticExprFor = (binding) => {
21
25
  const sugar = binding.sugar;
22
- if (sugar === void 0) {
23
- const call = `resolveValue(${JSON.stringify(binding.namespace)}, ${JSON.stringify(binding.key)})`;
24
- return rawExpr(binding.tsType === void 0 ? call : `${call} as ${binding.tsType}`);
25
- }
26
+ if (sugar === void 0) return rawExpr(`requireValue${binding.tsType === void 0 ? "" : `<${binding.tsType}>`}(dep, ${JSON.stringify(binding.namespace)}, ${JSON.stringify(binding.key)})`);
26
27
  switch (sugar.kind) {
27
- case "id": return rawExpr(`resolveId(${JSON.stringify(sugar.mvrPlaceholder)})`);
28
- case "network": return rawExpr("resolveNetwork()");
29
- case "networks": return rawExpr("resolveNetworks()");
28
+ case "id": return rawExpr(`requireId(dep, ${JSON.stringify(sugar.mvrPlaceholder)})`);
29
+ case "network": return rawExpr("dep.network");
30
+ case "networks": return rawExpr("Object.fromEntries(__deployment.networkNames.map((n) => [n, __deployment.forNetwork(n)]))");
31
+ case "mvrType": return rawExpr(`\`\${requireId(dep, ${JSON.stringify(sugar.mvrPlaceholder)})}::${sugar.typeSuffix}\``);
30
32
  }
31
33
  };
32
34
  /** Build the STATIC (committed-tree) aggregate projection from a binding
33
- * set — `rawExpr(resolve…())` for resolved bindings, literals for the
34
- * rest. Pure: needs no acquired state. */
35
+ * set — `rawExpr(requireValue(dep, )/requireId(dep, …)/dep.network/…)` for
36
+ * resolved bindings, literals for the rest. Pure: needs no acquired state. */
35
37
  const projectStaticConfig = (set) => {
36
38
  const root = {};
37
39
  for (const binding of set.bindings) {
@@ -51,10 +53,10 @@ const projectLiveConfig = (set, state) => {
51
53
  return root;
52
54
  };
53
55
  /**
54
- * Derive the live `idConfig.values[namespace][key]` contributions of a
56
+ * Derive the live `deployment.values[namespace][key]` contributions of a
55
57
  * binding set. Only `resolved` bindings WITHOUT a `sugar` resolver land in
56
- * the generic channel (sugar bindings feed the typed id-config fields,
57
- * sliced from the live `config.ts` bucket by `idConfigFromBucket`). The
58
+ * the generic channel (sugar bindings feed the typed deployment fields,
59
+ * sliced from the live `config.ts` bucket by `deploymentFromBucket`). The
58
60
  * generic channel is the part the fixed typed schema can't carry.
59
61
  */
60
62
  const liveValuesOf = (set, state) => {
@@ -67,19 +69,41 @@ const liveValuesOf = (set, state) => {
67
69
  return out;
68
70
  };
69
71
  /**
72
+ * Derive the STATIC TS type of each generic-channel (`values[ns][key]`)
73
+ * contribution — `valueTypes[namespace][key] = '<tsType>'`. The SAME binding
74
+ * subset `liveValuesOf` covers (every `resolved` binding WITHOUT a `sugar`
75
+ * resolver — sugar bindings feed the typed deployment fields, not `values`),
76
+ * but carries each field's declared `tsType` source string (defaulting to
77
+ * `'unknown'`) instead of its live value. Pure over the binding set — the type
78
+ * is config-known, so this is identical on the live and static paths. The
79
+ * codegen orchestrator folds it into the strict `deployment.ts`'s required
80
+ * `values` shape so a hand-written deployment is compile-checked for every
81
+ * service value.
82
+ */
83
+ const valueTypesOf = (set) => {
84
+ const out = {};
85
+ for (const binding of set.bindings) {
86
+ if (binding.variant !== "resolved" || binding.sugar !== void 0) continue;
87
+ const ns = out[binding.namespace] ??= {};
88
+ ns[binding.key] = binding.tsType ?? "unknown";
89
+ }
90
+ return out;
91
+ };
92
+ /**
70
93
  * Derive a `CodegenableDecl` from a binding set.
71
94
  *
72
95
  * `'static'` → the committed-tree decl (stack-free `codegen` verb). Its
73
96
  * aggregate emits `rawExpr(resolve…())` for resolved bindings.
74
97
  *
75
98
  * `{ mode: 'live', state }` → the boot decl. Its aggregate bakes concrete
76
- * values from `state`; boot's `assembleIdConfig` reads those back into the
77
- * loadable id-config (typed channel + the generic `values` channel).
99
+ * values from `state`; boot's `assembleDeployment` reads those back into the
100
+ * loadable deployment (typed channel + the generic `values` channel).
78
101
  */
79
102
  const configCodegenable = (set, how, options = {}) => {
80
103
  const live = how !== "static";
81
104
  const projected = live ? projectLiveConfig(set, how.state) : projectStaticConfig(set);
82
105
  const idConfigValues = live ? liveValuesOf(set, how.state) : {};
106
+ const valueTypes = valueTypesOf(set);
83
107
  const extraExports = options.extraExports;
84
108
  return {
85
109
  kind: "codegenable",
@@ -91,7 +115,8 @@ const configCodegenable = (set, how, options = {}) => {
91
115
  kind: set.kind,
92
116
  bucket: set.bucket,
93
117
  project: () => projected,
94
- ...live && Object.keys(idConfigValues).length > 0 ? { idConfigValues } : {}
118
+ ...live && Object.keys(idConfigValues).length > 0 ? { idConfigValues } : {},
119
+ ...Object.keys(valueTypes).length > 0 ? { valueTypes } : {}
95
120
  },
96
121
  emit: (ctx) => Effect.sync(() => {
97
122
  if (extraExports !== void 0) for (const [name, value] of Object.entries(extraExports)) ctx.exportConst(name, value);
@@ -147,13 +172,13 @@ const siblingBucketBindings = (spec) => {
147
172
  };
148
173
  };
149
174
  /** Derive the LIVE bucket decl — feeds concrete values into the generic
150
- * id-config `values` channel (no per-stack generated file is written). */
175
+ * deployment `values` channel (no per-stack generated file is written). */
151
176
  const liveBucketCodegen = (spec, state) => configCodegenable(siblingBucketBindings(spec), {
152
177
  mode: "live",
153
178
  state
154
179
  });
155
180
  /** Derive the STATIC (stack-free) bucket decl — emits
156
- * `resolveValue(namespace, key)` for resolved fields, literals for the
181
+ * `requireValue(dep, namespace, key)` for resolved fields, literals for the
157
182
  * rest. The committed `<bucket>.ts` carries no baked runtime value. */
158
183
  const staticBucketCodegen = (spec) => configCodegenable(siblingBucketBindings(spec), "static");
159
184
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"config-bindings.mjs","names":[],"sources":["../../src/contracts/config-bindings.ts"],"sourcesContent":["// Unified config-binding contract.\n//\n// THE PROBLEM THIS SOLVES. A config-emitting plugin used to maintain TWO\n// near-duplicate projectors:\n// - a LIVE one (boot): bakes concrete resolved values (real ids, rpc\n// URLs) into the loadable id-config (`assembleIdConfig`), and\n// - a STATIC one (the stack-free `codegen` verb): emits\n// `rawExpr(resolve…())` into the committed `config.ts` so the tree\n// carries NO on-chain id.\n// Two hand-written projectors per plugin is error-prone: forget the static\n// path and the committed tree is incomplete (broken clean-clone build);\n// the fixed typed id-config channel also can't carry arbitrary plugin live\n// values (deepbook pool ids, coin types, walrus/seal endpoints).\n//\n// THE UNIFICATION. A plugin declares its `config.ts` contributions ONCE as\n// a `ConfigBindingSet`. BOTH paths are DERIVED from it:\n// - `configCodegenable(set, 'static')` → the committed-tree decl whose\n// aggregate emits `rawExpr(resolveValue(...))` / typed-sugar resolvers\n// (and pure literals as literals).\n// - `configCodegenable(set, { mode: 'live', state })` → the boot decl\n// whose aggregate carries concrete resolved values that feed ONLY the\n// loadable id-config (typed channel + the generic `values` channel) —\n// no per-stack generated source is written; the committed `src/generated`\n// tree stays the single bindings source.\n//\n// One declaration, two derivations — no parallel projectors to drift.\n\nimport { Effect } from 'effect';\n\nimport type { CodegenableDecl } from './codegenable.ts';\nimport { rawExpr } from './codegenable.ts';\nimport type { JsonValue } from '../orchestrators/codegen/id-config.ts';\n\n// -----------------------------------------------------------------------------\n// Binding shape\n// -----------------------------------------------------------------------------\n\n/** A typed-sugar resolver a binding may target instead of the generic\n * `resolveValue(namespace, key)` channel. Each maps to a `config-runtime.ts`\n * function: `id` → `resolveId(<arg>)`, `network` → `resolveNetwork()`,\n * `networks` → `resolveNetworks()`. Sugar bindings also feed the TYPED\n * id-config fields (`mvrOverrides`/`network`/`networks`), not the generic\n * `values` channel — that keeps `config.network`/`config.mvrOverrides`\n * readable by apps exactly as before. */\nexport type ConfigSugarResolver =\n\t| { readonly kind: 'id'; readonly mvrPlaceholder: string }\n\t| { readonly kind: 'network' }\n\t| { readonly kind: 'networks' };\n\n/**\n * One config-binding. A plugin returns a list of these ONCE; the framework\n * derives both the live and static behaviors from them.\n *\n * Variants:\n * - `literal`: the SAME value in both paths (e.g. the package `mvr`\n * placeholder string, a network NAME you decide is static). Emitted\n * verbatim in `config.ts`; mirrored into the live id-config too.\n * - `resolved`: runtime-resolved. STATIC emits a resolver `rawExpr`;\n * LIVE computes the concrete value via `live(state)` and routes it into\n * the id-config — through the typed channel for a `sugar` resolver, or\n * through the generic `values[namespace][key]` channel otherwise.\n */\nexport type ConfigBinding<State = unknown> =\n\t| {\n\t\t\treadonly variant: 'literal';\n\t\t\t/** Path into the `config.ts` object literal, e.g. `['network']`\n\t\t\t * or `['packages', 'connect_four', 'mvr']`. */\n\t\t\treadonly configPath: ReadonlyArray<string>;\n\t\t\t/** The literal value (identical in both paths). */\n\t\t\treadonly value: JsonValue;\n\t }\n\t| {\n\t\t\treadonly variant: 'resolved';\n\t\t\t/** Path into the `config.ts` object literal. */\n\t\t\treadonly configPath: ReadonlyArray<string>;\n\t\t\t/** Generic-channel coordinates. Always present so the live path\n\t\t\t * can populate `idConfig.values[namespace][key]` even for a\n\t\t\t * sugar-resolved binding (the sugar ALSO feeds the typed field;\n\t\t\t * `values` is harmless redundancy and keeps the guard simple). */\n\t\t\treadonly namespace: string;\n\t\t\treadonly key: string;\n\t\t\t/** When set, the static path emits the typed-sugar resolver\n\t\t\t * (`resolveId`/`resolveNetwork`/`resolveNetworks`) and the live\n\t\t\t * path additionally feeds the TYPED id-config field. When\n\t\t\t * omitted, the static path emits `resolveValue(namespace, key)`\n\t\t\t * and the live value lands ONLY in the generic `values` channel. */\n\t\t\treadonly sugar?: ConfigSugarResolver;\n\t\t\t/** The field's STATIC TypeScript type, as a source string (e.g.\n\t\t\t * `'string'`, `'string | null'`, or a structural literal type for a\n\t\t\t * composite). When set, the static path emits\n\t\t\t * `resolveValue(ns, key) as <tsType>` so the committed value carries\n\t\t\t * its concrete type instead of the `unknown` the generic channel\n\t\t\t * returns. Ignored for sugar bindings (those use the typed resolver\n\t\t\t * whose return type is already concrete). When omitted, the static\n\t\t\t * path emits a bare `resolveValue(ns, key)` (type `unknown`). */\n\t\t\treadonly tsType?: string;\n\t\t\t/** Compute the concrete value at boot from acquired plugin state.\n\t\t\t * Only invoked on the LIVE path. */\n\t\t\treadonly live: (state: State) => JsonValue;\n\t };\n\n/**\n * A plugin's full `config.ts` contribution, declared ONCE.\n *\n * `bucket` is always `'config.ts'` for the typed app config; carried as a\n * field so the orchestrator stays name-blind (it reads the bucket off the\n * decl rather than hard-coding it).\n */\nexport interface ConfigBindingSet<State = unknown> {\n\t/** Aggregate bucket the bindings fold into (always `'config.ts'` today;\n\t * a field so the orchestrator never hard-codes it). */\n\treadonly bucket: string;\n\t/** Diagnostic tag for span attributes (e.g. `'sui-network'`,\n\t * `'package'`). The orchestrator MUST NOT branch on it. */\n\treadonly kind: string;\n\t/** The emitter name the derived `CodegenableDecl` carries. */\n\treadonly emitterName: string;\n\t/** Optional standalone output path. The derived decl is `aggregateOnly`,\n\t * so no per-decl file is written; path-resolution only needs a non-empty,\n\t * per-bucket-unique string, which defaults to `bucket` when omitted. Set\n\t * it only when a standalone path would be genuinely meaningful. */\n\treadonly outputPath?: string;\n\t/** When `true`, the derived decl sets `allowEmitterNameRepetition`\n\t * (one decl per item, e.g. one `package` per published package). */\n\treadonly allowEmitterNameRepetition?: boolean;\n\t/** The bindings. */\n\treadonly bindings: ReadonlyArray<ConfigBinding<State>>;\n}\n\n// -----------------------------------------------------------------------------\n// Derivation\n// -----------------------------------------------------------------------------\n\n/** Set `value` at `path` inside `root`, creating intermediate objects. */\nconst setAtPath = (\n\troot: Record<string, unknown>,\n\tpath: ReadonlyArray<string>,\n\tvalue: unknown,\n): void => {\n\tlet cursor = root;\n\tfor (let i = 0; i < path.length - 1; i++) {\n\t\tconst segment = path[i]!;\n\t\tconst next = cursor[segment];\n\t\tif (typeof next === 'object' && next !== null && !Array.isArray(next)) {\n\t\t\tcursor = next as Record<string, unknown>;\n\t\t} else {\n\t\t\tconst created: Record<string, unknown> = {};\n\t\t\tcursor[segment] = created;\n\t\t\tcursor = created;\n\t\t}\n\t}\n\tcursor[path[path.length - 1]!] = value;\n};\n\n/** The `rawExpr` the STATIC path emits for a resolved binding. */\nconst staticExprFor = <State>(\n\tbinding: Extract<ConfigBinding<State>, { variant: 'resolved' }>,\n): ReturnType<typeof rawExpr> => {\n\tconst sugar = binding.sugar;\n\tif (sugar === undefined) {\n\t\tconst call = `resolveValue(${JSON.stringify(binding.namespace)}, ${JSON.stringify(binding.key)})`;\n\t\t// A `tsType` carries the field's concrete static type so the committed\n\t\t// value typechecks against the app's usage (the generic channel returns\n\t\t// `unknown`). Emit the call as a typed cast; bare otherwise.\n\t\treturn rawExpr(binding.tsType === undefined ? call : `${call} as ${binding.tsType}`);\n\t}\n\tswitch (sugar.kind) {\n\t\tcase 'id':\n\t\t\treturn rawExpr(`resolveId(${JSON.stringify(sugar.mvrPlaceholder)})`);\n\t\tcase 'network':\n\t\t\treturn rawExpr('resolveNetwork()');\n\t\tcase 'networks':\n\t\t\treturn rawExpr('resolveNetworks()');\n\t}\n};\n\n/** Build the STATIC (committed-tree) aggregate projection from a binding\n * set — `rawExpr(resolve…())` for resolved bindings, literals for the\n * rest. Pure: needs no acquired state. */\nexport const projectStaticConfig = <State>(\n\tset: ConfigBindingSet<State>,\n): Record<string, unknown> => {\n\tconst root: Record<string, unknown> = {};\n\tfor (const binding of set.bindings) {\n\t\tconst value = binding.variant === 'literal' ? binding.value : staticExprFor(binding);\n\t\tsetAtPath(root, binding.configPath, value);\n\t}\n\treturn root;\n};\n\n/** Build the LIVE (boot) aggregate projection from a binding set against\n * the acquired plugin state — concrete resolved values everywhere. */\nexport const projectLiveConfig = <State>(\n\tset: ConfigBindingSet<State>,\n\tstate: State,\n): Record<string, unknown> => {\n\tconst root: Record<string, unknown> = {};\n\tfor (const binding of set.bindings) {\n\t\tconst value = binding.variant === 'literal' ? binding.value : binding.live(state);\n\t\tsetAtPath(root, binding.configPath, value);\n\t}\n\treturn root;\n};\n\n/**\n * Derive the live `idConfig.values[namespace][key]` contributions of a\n * binding set. Only `resolved` bindings WITHOUT a `sugar` resolver land in\n * the generic channel (sugar bindings feed the typed id-config fields,\n * sliced from the live `config.ts` bucket by `idConfigFromBucket`). The\n * generic channel is the part the fixed typed schema can't carry.\n */\nexport const liveValuesOf = <State>(\n\tset: ConfigBindingSet<State>,\n\tstate: State,\n): Record<string, Record<string, JsonValue>> => {\n\tconst out: Record<string, Record<string, JsonValue>> = {};\n\tfor (const binding of set.bindings) {\n\t\tif (binding.variant !== 'resolved' || binding.sugar !== undefined) continue;\n\t\tconst ns = (out[binding.namespace] ??= {});\n\t\tns[binding.key] = binding.live(state);\n\t}\n\treturn out;\n};\n\n/**\n * Derive a `CodegenableDecl` from a binding set.\n *\n * `'static'` → the committed-tree decl (stack-free `codegen` verb). Its\n * aggregate emits `rawExpr(resolve…())` for resolved bindings.\n *\n * `{ mode: 'live', state }` → the boot decl. Its aggregate bakes concrete\n * values from `state`; boot's `assembleIdConfig` reads those back into the\n * loadable id-config (typed channel + the generic `values` channel).\n */\nexport const configCodegenable = <State, Emitter extends string = string>(\n\tset: ConfigBindingSet<State>,\n\thow: 'static' | { readonly mode: 'live'; readonly state: State },\n\toptions: {\n\t\t/** Extra `export const <name> = <value>` declarations to emit on the\n\t\t * decl's `emit` context, instead of the default placeholder export.\n\t\t * The package plugin uses this to export its `packageBindings` object\n\t\t * so the orchestrator's `isPackageBindings` seam can forward it to the\n\t\t * Move-bindings emitter. When omitted, a single minimal placeholder\n\t\t * export is emitted (the projection is what the aggregate folds). */\n\t\treadonly extraExports?: Readonly<Record<string, unknown>>;\n\t} = {},\n): CodegenableDecl<Emitter> => {\n\tconst live = how !== 'static';\n\tconst projected = live ? projectLiveConfig(set, how.state) : projectStaticConfig(set);\n\tconst idConfigValues = live ? liveValuesOf(set, how.state) : {};\n\tconst extraExports = options.extraExports;\n\treturn {\n\t\tkind: 'codegenable',\n\t\temitterName: set.emitterName as Emitter,\n\t\t// `aggregateOnly` never writes a standalone file; default the\n\t\t// path-resolution placeholder to the bucket name so plugins don't\n\t\t// invent dead paths.\n\t\toutputPath: set.outputPath ?? set.bucket,\n\t\taggregateOnly: true,\n\t\t...(set.allowEmitterNameRepetition === true ? { allowEmitterNameRepetition: true } : {}),\n\t\taggregate: {\n\t\t\tkind: set.kind,\n\t\t\tbucket: set.bucket,\n\t\t\t// The projection is precomputed above (pure over `set`/`state`);\n\t\t\t// the orchestrator calls `project(exported)` with the emitted map\n\t\t\t// but the value is already fixed, so we ignore the argument.\n\t\t\tproject: () => projected,\n\t\t\t// Only the live aggregate feeds the generic id-config channel.\n\t\t\t...(live && Object.keys(idConfigValues).length > 0 ? { idConfigValues } : {}),\n\t\t},\n\t\temit: (ctx) =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tif (extraExports !== undefined) {\n\t\t\t\t\tfor (const [name, value] of Object.entries(extraExports)) {\n\t\t\t\t\t\tctx.exportConst(name, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// A placeholder export so the emitter runs; the projection is\n\t\t\t\t\t// what the aggregate folds. Kept minimal + name-stable.\n\t\t\t\t\tctx.exportConst('__configBindings', set.kind);\n\t\t\t\t}\n\t\t\t\treturn ctx.done();\n\t\t\t}),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Sibling-keyed bucket bindings\n// -----------------------------------------------------------------------------\n//\n// The own-bucket service plugins (coin → `coins.ts`, deepbook → `deepbook.ts`,\n// seal → `seal.ts`) emit a name-keyed bucket where distinct instances deep-merge\n// into one `<bucket>.ts` exporting `{ <instanceKey>: { ...fields } }`. They\n// declare their per-instance contribution as a flat list of `BucketField`s\n// (each a structural literal or a runtime-resolved value rooted under the\n// instance key); the helpers below derive the `ConfigBindingSet` and both the\n// live/static decls from it, so there are no parallel projectors to drift.\n\n/** One field of an instance's bucket entry, classified as either a pure\n * STRUCTURAL literal (a name / mode / decimals — the same in both paths)\n * or a runtime-RESOLVED value (an on-chain id, coin type, or endpoint URL —\n * the static path emits `resolveValue`, the live path feeds the concrete\n * value into the id-config). The `key` is the leaf field name written under\n * the instance key in the bucket object literal. */\nexport type BucketField<State> =\n\t| { readonly key: string; readonly variant: 'literal'; readonly value: JsonValue }\n\t| {\n\t\t\treadonly key: string;\n\t\t\treadonly variant: 'resolved';\n\t\t\t/** `resolveValue(namespace, valueKey)` coordinates. `valueKey`\n\t\t\t * defaults to `key` when omitted. */\n\t\t\treadonly valueKey?: string;\n\t\t\t/** The field's STATIC TypeScript type as a source string (see\n\t\t\t * `ConfigBinding.tsType`). When set, the static path emits\n\t\t\t * `resolveValue(...) as <tsType>` so the committed value carries its\n\t\t\t * concrete type instead of `unknown`. */\n\t\t\treadonly tsType?: string;\n\t\t\treadonly live: (state: State) => JsonValue;\n\t };\n\nexport interface SiblingBucketSpec<State> {\n\t/** The aggregate bucket filename, e.g. `'coins.ts'`. */\n\treadonly bucket: string;\n\t/** Diagnostic kind tag (e.g. `'coin'`) — the orchestrator never\n\t * branches on it. */\n\treadonly kind: string;\n\t/** The emitter name the derived decl carries (literal, e.g.\n\t * `coin/<symbol>`). */\n\treadonly emitterName: string;\n\t/** Optional standalone output path. Defaults to `bucket` (the decl is\n\t * `aggregateOnly`, so no per-decl file is written). */\n\treadonly outputPath?: string;\n\t/** The instance key the entry lives under in the bucket object\n\t * (e.g. the coin symbol, the deepbook instance name). */\n\treadonly instanceKey: string;\n\t/** The `resolveValue` namespace shared by every resolved field\n\t * (e.g. `coin:<symbol>`, `deepbook:<name>`). */\n\treadonly namespace: string;\n\t/** The instance's fields. */\n\treadonly fields: ReadonlyArray<BucketField<State>>;\n\t/** When `true`, the derived decl sets `allowEmitterNameRepetition`\n\t * (sibling instances share an emitter-name prefix). */\n\treadonly allowEmitterNameRepetition?: boolean;\n}\n\n/** Convenience constructor for the keyed-bucket shape the service plugins\n * share (coin/deepbook/seal): every sibling instance keys under `<key>` in\n * `<bucket>`, with `emitterName = `<kind>/<key>``, `namespace = `<kind>:<key>``,\n * `instanceKey = <key>`, and `allowEmitterNameRepetition` (instances share the\n * `<kind>/` emitter prefix). Only `bucket`/`kind`/`key`/`fields` vary across\n * those plugins, so this keeps the `<kind>/<key>` + `<kind>:<key>` naming\n * convention in ONE place instead of re-spelling it per plugin. */\nexport const keyedBucketSpec = <State>(input: {\n\treadonly bucket: string;\n\treadonly kind: string;\n\treadonly key: string;\n\treadonly fields: ReadonlyArray<BucketField<State>>;\n}): SiblingBucketSpec<State> => ({\n\tbucket: input.bucket,\n\tkind: input.kind,\n\temitterName: `${input.kind}/${input.key}`,\n\tinstanceKey: input.key,\n\tnamespace: `${input.kind}:${input.key}`,\n\tallowEmitterNameRepetition: true,\n\tfields: input.fields,\n});\n\n/** Build the `ConfigBindingSet` for a sibling-keyed bucket instance. The\n * `configPath` of every binding is rooted at the instance key, so distinct\n * instances deep-merge into one `<bucket>.ts` exporting\n * `{ <instanceKey>: { ...fields } }`. */\nexport const siblingBucketBindings = <State>(\n\tspec: SiblingBucketSpec<State>,\n): ConfigBindingSet<State> => {\n\tconst bindings: Array<ConfigBinding<State>> = spec.fields.map((field) => {\n\t\tconst configPath = [spec.instanceKey, field.key] as const;\n\t\tif (field.variant === 'literal') {\n\t\t\treturn { variant: 'literal', configPath: [...configPath], value: field.value };\n\t\t}\n\t\treturn {\n\t\t\tvariant: 'resolved',\n\t\t\tconfigPath: [...configPath],\n\t\t\tnamespace: spec.namespace,\n\t\t\tkey: field.valueKey ?? field.key,\n\t\t\t// No `sugar` — these are generic `resolveValue` bindings (the typed\n\t\t\t// id-config channel only carries network/packages/mvrOverrides).\n\t\t\t...(field.tsType !== undefined ? { tsType: field.tsType } : {}),\n\t\t\tlive: field.live,\n\t\t};\n\t});\n\treturn {\n\t\tbucket: spec.bucket,\n\t\tkind: spec.kind,\n\t\temitterName: spec.emitterName,\n\t\t...(spec.outputPath !== undefined ? { outputPath: spec.outputPath } : {}),\n\t\t...(spec.allowEmitterNameRepetition === true ? { allowEmitterNameRepetition: true } : {}),\n\t\tbindings,\n\t};\n};\n\n/** Derive the LIVE bucket decl — feeds concrete values into the generic\n * id-config `values` channel (no per-stack generated file is written). */\nexport const liveBucketCodegen = <State>(\n\tspec: SiblingBucketSpec<State>,\n\tstate: State,\n): CodegenableDecl => configCodegenable(siblingBucketBindings(spec), { mode: 'live', state });\n\n/** Derive the STATIC (stack-free) bucket decl — emits\n * `resolveValue(namespace, key)` for resolved fields, literals for the\n * rest. The committed `<bucket>.ts` carries no baked runtime value. */\nexport const staticBucketCodegen = <State>(spec: SiblingBucketSpec<State>): CodegenableDecl =>\n\tconfigCodegenable(siblingBucketBindings(spec), 'static');\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-bindings.mjs","names":[],"sources":["../../src/contracts/config-bindings.ts"],"sourcesContent":["// Unified config-binding contract.\n//\n// THE PROBLEM THIS SOLVES. A config-emitting plugin used to maintain TWO\n// near-duplicate projectors:\n// - a LIVE one (boot): bakes concrete resolved values (real ids, rpc\n// URLs) into the loadable deployment (`assembleDeployment`), and\n// - a STATIC one (the stack-free `codegen` verb): emits\n// `rawExpr(resolve…())` into the committed `config.ts` so the tree\n// carries NO on-chain id.\n// Two hand-written projectors per plugin is error-prone: forget the static\n// path and the committed tree is incomplete (broken clean-clone build);\n// the fixed typed deployment channel also can't carry arbitrary plugin live\n// values (deepbook pool ids, coin types, walrus/seal endpoints).\n//\n// THE UNIFICATION. A plugin declares its `config.ts` contributions ONCE as\n// a `ConfigBindingSet`. BOTH paths are DERIVED from it:\n// - `configCodegenable(set, 'static')` → the committed-tree decl whose\n// aggregate emits `rawExpr(requireValue(dep, ...))` / typed-sugar\n// deployment accessors (and pure literals as literals).\n// - `configCodegenable(set, { mode: 'live', state })` → the boot decl\n// whose aggregate carries concrete resolved values that feed ONLY the\n// loadable deployment (typed channel + the generic `values` channel) —\n// no per-stack generated source is written; the committed `src/generated`\n// tree stays the single bindings source.\n//\n// One declaration, two derivations — no parallel projectors to drift.\n\nimport { Effect } from 'effect';\n\nimport type { CodegenableDecl } from './codegenable.ts';\nimport { rawExpr } from './codegenable.ts';\nimport type { JsonValue } from '../orchestrators/codegen/deployment.ts';\n\n// -----------------------------------------------------------------------------\n// Binding shape\n// -----------------------------------------------------------------------------\n\n/** A typed-sugar resolver a binding may target instead of the generic\n * `requireValue(dep, namespace, key)` channel. Each maps to a deployment\n * accessor: `id` → `requireId(dep, <arg>)`, `network` → `dep.network`,\n * `networks` → `Object.fromEntries(__deployment.networkNames.map((n) =>\n * [n, __deployment.forNetwork(n)]))`, `mvrType` →\n * `` `${requireId(dep, \"<mvr>\")}::<typeSuffix>` `` (an MVR `types` override\n * entry). Sugar bindings also feed the TYPED\n * deployment fields (`mvrOverrides`/`network`/`networks`), not the generic\n * `values` channel — that keeps `config.network`/`config.mvrOverrides`\n * readable by apps exactly as before. */\nexport type ConfigSugarResolver =\n\t| { readonly kind: 'id'; readonly mvrPlaceholder: string }\n\t| { readonly kind: 'network' }\n\t| { readonly kind: 'networks' }\n\t| {\n\t\t\t/** An MVR `types` override entry. The static path emits the\n\t\t\t * per-network resolved type tag\n\t\t\t * `` `${requireId(dep, \"<mvrPlaceholder>\")}::<typeSuffix>` `` (the\n\t\t\t * `@local/<slug>` package prefix substituted with the active-network\n\t\t\t * package id); the live path's value is IGNORED by the live deployment\n\t\t\t * slice (`deploymentFromBucket` keeps `mvrOverrides.types: {}`), so the\n\t\t\t * committed `config.ts` is the only carrier of the declared types. */\n\t\t\treadonly kind: 'mvrType';\n\t\t\treadonly mvrPlaceholder: string;\n\t\t\t/** The `<module>::<Name>` suffix beneath the package prefix. */\n\t\t\treadonly typeSuffix: string;\n\t };\n\n/**\n * One config-binding. A plugin returns a list of these ONCE; the framework\n * derives both the live and static behaviors from them.\n *\n * Variants:\n * - `literal`: the SAME value in both paths (e.g. the package `mvr`\n * placeholder string, a network NAME you decide is static). Emitted\n * verbatim in `config.ts`; mirrored into the live deployment too.\n * - `resolved`: runtime-resolved. STATIC emits a resolver `rawExpr`;\n * LIVE computes the concrete value via `live(state)` and routes it into\n * the deployment — through the typed channel for a `sugar` resolver, or\n * through the generic `values[namespace][key]` channel otherwise.\n */\nexport type ConfigBinding<State = unknown> =\n\t| {\n\t\t\treadonly variant: 'literal';\n\t\t\t/** Path into the `config.ts` object literal, e.g. `['network']`\n\t\t\t * or `['packages', 'connect_four', 'mvr']`. */\n\t\t\treadonly configPath: ReadonlyArray<string>;\n\t\t\t/** The literal value (identical in both paths). */\n\t\t\treadonly value: JsonValue;\n\t }\n\t| {\n\t\t\treadonly variant: 'resolved';\n\t\t\t/** Path into the `config.ts` object literal. */\n\t\t\treadonly configPath: ReadonlyArray<string>;\n\t\t\t/** Generic-channel coordinates. Always present so the live path\n\t\t\t * can populate `deployment.values[namespace][key]` even for a\n\t\t\t * sugar-resolved binding (the sugar ALSO feeds the typed field;\n\t\t\t * `values` is harmless redundancy and keeps the guard simple). */\n\t\t\treadonly namespace: string;\n\t\t\treadonly key: string;\n\t\t\t/** When set, the static path emits the typed-sugar deployment\n\t\t\t * accessor (`requireId(dep, …)` / `dep.network` / the networks\n\t\t\t * `Object.fromEntries(...)` expr) and the live path additionally\n\t\t\t * feeds the TYPED deployment field. When omitted, the static path\n\t\t\t * emits `requireValue(dep, namespace, key)` and the live value lands\n\t\t\t * ONLY in the generic `values` channel. */\n\t\t\treadonly sugar?: ConfigSugarResolver;\n\t\t\t/** The field's STATIC TypeScript type, as a source string (e.g.\n\t\t\t * `'string'`, `'string | null'`, or a structural literal type for a\n\t\t\t * composite). When set, the static path emits\n\t\t\t * `requireValue<tsType>(dep, ns, key)` so the committed value carries\n\t\t\t * its concrete type instead of the `unknown` the generic channel\n\t\t\t * returns. Ignored for sugar bindings (those use the typed accessor\n\t\t\t * whose return type is already concrete). When omitted, the static\n\t\t\t * path emits a bare `requireValue(dep, ns, key)` (type `unknown`). */\n\t\t\treadonly tsType?: string;\n\t\t\t/** Compute the concrete value at boot from acquired plugin state.\n\t\t\t * Only invoked on the LIVE path. */\n\t\t\treadonly live: (state: State) => JsonValue;\n\t };\n\n/**\n * A plugin's full `config.ts` contribution, declared ONCE.\n *\n * `bucket` is always `'config.ts'` for the typed app config; carried as a\n * field so the orchestrator stays name-blind (it reads the bucket off the\n * decl rather than hard-coding it).\n */\nexport interface ConfigBindingSet<State = unknown> {\n\t/** Aggregate bucket the bindings fold into (always `'config.ts'` today;\n\t * a field so the orchestrator never hard-codes it). */\n\treadonly bucket: string;\n\t/** Diagnostic tag for span attributes (e.g. `'sui-network'`,\n\t * `'package'`). The orchestrator MUST NOT branch on it. */\n\treadonly kind: string;\n\t/** The emitter name the derived `CodegenableDecl` carries. */\n\treadonly emitterName: string;\n\t/** Optional standalone output path. The derived decl is `aggregateOnly`,\n\t * so no per-decl file is written; path-resolution only needs a non-empty,\n\t * per-bucket-unique string, which defaults to `bucket` when omitted. Set\n\t * it only when a standalone path would be genuinely meaningful. */\n\treadonly outputPath?: string;\n\t/** When `true`, the derived decl sets `allowEmitterNameRepetition`\n\t * (one decl per item, e.g. one `package` per published package). */\n\treadonly allowEmitterNameRepetition?: boolean;\n\t/** The bindings. */\n\treadonly bindings: ReadonlyArray<ConfigBinding<State>>;\n}\n\n// -----------------------------------------------------------------------------\n// Derivation\n// -----------------------------------------------------------------------------\n\n/** Set `value` at `path` inside `root`, creating intermediate objects. */\nconst setAtPath = (\n\troot: Record<string, unknown>,\n\tpath: ReadonlyArray<string>,\n\tvalue: unknown,\n): void => {\n\tlet cursor = root;\n\tfor (let i = 0; i < path.length - 1; i++) {\n\t\tconst segment = path[i]!;\n\t\tconst next = cursor[segment];\n\t\tif (typeof next === 'object' && next !== null && !Array.isArray(next)) {\n\t\t\tcursor = next as Record<string, unknown>;\n\t\t} else {\n\t\t\tconst created: Record<string, unknown> = {};\n\t\t\tcursor[segment] = created;\n\t\t\tcursor = created;\n\t\t}\n\t}\n\tcursor[path[path.length - 1]!] = value;\n};\n\n/** The `rawExpr` the STATIC path emits for a resolved binding. Reads off the\n * loaded deployment's active network — the emitted file carries a\n * `const dep = __deployment.forNetwork(__deployment.defaultNetwork);`\n * preamble (wired by the codegen orchestrator), so these expressions\n * reference `dep` / `__deployment` directly. */\nconst staticExprFor = <State>(\n\tbinding: Extract<ConfigBinding<State>, { variant: 'resolved' }>,\n): ReturnType<typeof rawExpr> => {\n\tconst sugar = binding.sugar;\n\tif (sugar === undefined) {\n\t\t// Generic channel: `requireValue<tsType>(dep, \"ns\", \"key\")`. The optional\n\t\t// `tsType` carries the field's concrete static type so the committed value\n\t\t// typechecks against the app's usage (the generic channel returns\n\t\t// `unknown`); emitted as a type argument on `requireValue`.\n\t\tconst typeArg = binding.tsType === undefined ? '' : `<${binding.tsType}>`;\n\t\tconst ns = JSON.stringify(binding.namespace);\n\t\tconst key = JSON.stringify(binding.key);\n\t\treturn rawExpr(`requireValue${typeArg}(dep, ${ns}, ${key})`);\n\t}\n\tswitch (sugar.kind) {\n\t\tcase 'id':\n\t\t\treturn rawExpr(`requireId(dep, ${JSON.stringify(sugar.mvrPlaceholder)})`);\n\t\tcase 'network':\n\t\t\treturn rawExpr('dep.network');\n\t\tcase 'networks':\n\t\t\treturn rawExpr(\n\t\t\t\t'Object.fromEntries(__deployment.networkNames.map((n) => [n, __deployment.forNetwork(n)]))',\n\t\t\t);\n\t\tcase 'mvrType':\n\t\t\t// `` `${requireId(dep, \"<mvr>\")}::<module>::<Name>` `` — the package\n\t\t\t// prefix substituted with the active-network resolved id, never baked.\n\t\t\treturn rawExpr(\n\t\t\t\t`\\`\\${requireId(dep, ${JSON.stringify(sugar.mvrPlaceholder)})}::${sugar.typeSuffix}\\``,\n\t\t\t);\n\t}\n};\n\n/** Build the STATIC (committed-tree) aggregate projection from a binding\n * set — `rawExpr(requireValue(dep, …)/requireId(dep, …)/dep.network/…)` for\n * resolved bindings, literals for the rest. Pure: needs no acquired state. */\nexport const projectStaticConfig = <State>(\n\tset: ConfigBindingSet<State>,\n): Record<string, unknown> => {\n\tconst root: Record<string, unknown> = {};\n\tfor (const binding of set.bindings) {\n\t\tconst value = binding.variant === 'literal' ? binding.value : staticExprFor(binding);\n\t\tsetAtPath(root, binding.configPath, value);\n\t}\n\treturn root;\n};\n\n/** Build the LIVE (boot) aggregate projection from a binding set against\n * the acquired plugin state — concrete resolved values everywhere. */\nexport const projectLiveConfig = <State>(\n\tset: ConfigBindingSet<State>,\n\tstate: State,\n): Record<string, unknown> => {\n\tconst root: Record<string, unknown> = {};\n\tfor (const binding of set.bindings) {\n\t\tconst value = binding.variant === 'literal' ? binding.value : binding.live(state);\n\t\tsetAtPath(root, binding.configPath, value);\n\t}\n\treturn root;\n};\n\n/**\n * Derive the live `deployment.values[namespace][key]` contributions of a\n * binding set. Only `resolved` bindings WITHOUT a `sugar` resolver land in\n * the generic channel (sugar bindings feed the typed deployment fields,\n * sliced from the live `config.ts` bucket by `deploymentFromBucket`). The\n * generic channel is the part the fixed typed schema can't carry.\n */\nexport const liveValuesOf = <State>(\n\tset: ConfigBindingSet<State>,\n\tstate: State,\n): Record<string, Record<string, JsonValue>> => {\n\tconst out: Record<string, Record<string, JsonValue>> = {};\n\tfor (const binding of set.bindings) {\n\t\tif (binding.variant !== 'resolved' || binding.sugar !== undefined) continue;\n\t\tconst ns = (out[binding.namespace] ??= {});\n\t\tns[binding.key] = binding.live(state);\n\t}\n\treturn out;\n};\n\n/**\n * Derive the STATIC TS type of each generic-channel (`values[ns][key]`)\n * contribution — `valueTypes[namespace][key] = '<tsType>'`. The SAME binding\n * subset `liveValuesOf` covers (every `resolved` binding WITHOUT a `sugar`\n * resolver — sugar bindings feed the typed deployment fields, not `values`),\n * but carries each field's declared `tsType` source string (defaulting to\n * `'unknown'`) instead of its live value. Pure over the binding set — the type\n * is config-known, so this is identical on the live and static paths. The\n * codegen orchestrator folds it into the strict `deployment.ts`'s required\n * `values` shape so a hand-written deployment is compile-checked for every\n * service value.\n */\nexport const valueTypesOf = <State>(\n\tset: ConfigBindingSet<State>,\n): Record<string, Record<string, string>> => {\n\tconst out: Record<string, Record<string, string>> = {};\n\tfor (const binding of set.bindings) {\n\t\tif (binding.variant !== 'resolved' || binding.sugar !== undefined) continue;\n\t\tconst ns = (out[binding.namespace] ??= {});\n\t\tns[binding.key] = binding.tsType ?? 'unknown';\n\t}\n\treturn out;\n};\n\n/**\n * Derive a `CodegenableDecl` from a binding set.\n *\n * `'static'` → the committed-tree decl (stack-free `codegen` verb). Its\n * aggregate emits `rawExpr(resolve…())` for resolved bindings.\n *\n * `{ mode: 'live', state }` → the boot decl. Its aggregate bakes concrete\n * values from `state`; boot's `assembleDeployment` reads those back into the\n * loadable deployment (typed channel + the generic `values` channel).\n */\nexport const configCodegenable = <State, Emitter extends string = string>(\n\tset: ConfigBindingSet<State>,\n\thow: 'static' | { readonly mode: 'live'; readonly state: State },\n\toptions: {\n\t\t/** Extra `export const <name> = <value>` declarations to emit on the\n\t\t * decl's `emit` context, instead of the default placeholder export.\n\t\t * The package plugin uses this to export its `packageBindings` object\n\t\t * so the orchestrator's `isPackageBindings` seam can forward it to the\n\t\t * Move-bindings emitter. When omitted, a single minimal placeholder\n\t\t * export is emitted (the projection is what the aggregate folds). */\n\t\treadonly extraExports?: Readonly<Record<string, unknown>>;\n\t} = {},\n): CodegenableDecl<Emitter> => {\n\tconst live = how !== 'static';\n\tconst projected = live ? projectLiveConfig(set, how.state) : projectStaticConfig(set);\n\tconst idConfigValues = live ? liveValuesOf(set, how.state) : {};\n\t// Present on BOTH paths — the TS type is config-known (resolution-\n\t// independent). Drives the strict `deployment.ts`'s required `values` shape.\n\tconst valueTypes = valueTypesOf(set);\n\tconst extraExports = options.extraExports;\n\treturn {\n\t\tkind: 'codegenable',\n\t\temitterName: set.emitterName as Emitter,\n\t\t// `aggregateOnly` never writes a standalone file; default the\n\t\t// path-resolution placeholder to the bucket name so plugins don't\n\t\t// invent dead paths.\n\t\toutputPath: set.outputPath ?? set.bucket,\n\t\taggregateOnly: true,\n\t\t...(set.allowEmitterNameRepetition === true ? { allowEmitterNameRepetition: true } : {}),\n\t\taggregate: {\n\t\t\tkind: set.kind,\n\t\t\tbucket: set.bucket,\n\t\t\t// The projection is precomputed above (pure over `set`/`state`);\n\t\t\t// the orchestrator calls `project(exported)` with the emitted map\n\t\t\t// but the value is already fixed, so we ignore the argument.\n\t\t\tproject: () => projected,\n\t\t\t// Only the live aggregate feeds the generic deployment channel.\n\t\t\t...(live && Object.keys(idConfigValues).length > 0 ? { idConfigValues } : {}),\n\t\t\t// The static `valueTypes` channel is present on BOTH paths (the\n\t\t\t// committed `codegen` verb runs the STATIC aggregates, so the strict\n\t\t\t// `deployment.ts`'s required `values` shape must be derivable there).\n\t\t\t...(Object.keys(valueTypes).length > 0 ? { valueTypes } : {}),\n\t\t},\n\t\temit: (ctx) =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tif (extraExports !== undefined) {\n\t\t\t\t\tfor (const [name, value] of Object.entries(extraExports)) {\n\t\t\t\t\t\tctx.exportConst(name, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// A placeholder export so the emitter runs; the projection is\n\t\t\t\t\t// what the aggregate folds. Kept minimal + name-stable.\n\t\t\t\t\tctx.exportConst('__configBindings', set.kind);\n\t\t\t\t}\n\t\t\t\treturn ctx.done();\n\t\t\t}),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Sibling-keyed bucket bindings\n// -----------------------------------------------------------------------------\n//\n// The own-bucket service plugins (coin → `coins.ts`, deepbook → `deepbook.ts`,\n// seal → `seal.ts`) emit a name-keyed bucket where distinct instances deep-merge\n// into one `<bucket>.ts` exporting `{ <instanceKey>: { ...fields } }`. They\n// declare their per-instance contribution as a flat list of `BucketField`s\n// (each a structural literal or a runtime-resolved value rooted under the\n// instance key); the helpers below derive the `ConfigBindingSet` and both the\n// live/static decls from it, so there are no parallel projectors to drift.\n\n/** One field of an instance's bucket entry, classified as either a pure\n * STRUCTURAL literal (a name / mode / decimals — the same in both paths)\n * or a runtime-RESOLVED value (an on-chain id, coin type, or endpoint URL —\n * the static path emits `requireValue(dep, …)`, the live path feeds the\n * concrete value into the deployment). The `key` is the leaf field name written\n * under the instance key in the bucket object literal. */\nexport type BucketField<State> =\n\t| { readonly key: string; readonly variant: 'literal'; readonly value: JsonValue }\n\t| {\n\t\t\treadonly key: string;\n\t\t\treadonly variant: 'resolved';\n\t\t\t/** `requireValue(dep, namespace, valueKey)` coordinates. `valueKey`\n\t\t\t * defaults to `key` when omitted. */\n\t\t\treadonly valueKey?: string;\n\t\t\t/** The field's STATIC TypeScript type as a source string (see\n\t\t\t * `ConfigBinding.tsType`). When set, the static path emits\n\t\t\t * `requireValue<tsType>(dep, …)` so the committed value carries its\n\t\t\t * concrete type instead of `unknown`. */\n\t\t\treadonly tsType?: string;\n\t\t\treadonly live: (state: State) => JsonValue;\n\t };\n\nexport interface SiblingBucketSpec<State> {\n\t/** The aggregate bucket filename, e.g. `'coins.ts'`. */\n\treadonly bucket: string;\n\t/** Diagnostic kind tag (e.g. `'coin'`) — the orchestrator never\n\t * branches on it. */\n\treadonly kind: string;\n\t/** The emitter name the derived decl carries (literal, e.g.\n\t * `coin/<symbol>`). */\n\treadonly emitterName: string;\n\t/** Optional standalone output path. Defaults to `bucket` (the decl is\n\t * `aggregateOnly`, so no per-decl file is written). */\n\treadonly outputPath?: string;\n\t/** The instance key the entry lives under in the bucket object\n\t * (e.g. the coin symbol, the deepbook instance name). */\n\treadonly instanceKey: string;\n\t/** The `requireValue` namespace shared by every resolved field\n\t * (e.g. `coin:<symbol>`, `deepbook:<name>`). */\n\treadonly namespace: string;\n\t/** The instance's fields. */\n\treadonly fields: ReadonlyArray<BucketField<State>>;\n\t/** When `true`, the derived decl sets `allowEmitterNameRepetition`\n\t * (sibling instances share an emitter-name prefix). */\n\treadonly allowEmitterNameRepetition?: boolean;\n}\n\n/** Convenience constructor for the keyed-bucket shape the service plugins\n * share (coin/deepbook/seal): every sibling instance keys under `<key>` in\n * `<bucket>`, with `emitterName = `<kind>/<key>``, `namespace = `<kind>:<key>``,\n * `instanceKey = <key>`, and `allowEmitterNameRepetition` (instances share the\n * `<kind>/` emitter prefix). Only `bucket`/`kind`/`key`/`fields` vary across\n * those plugins, so this keeps the `<kind>/<key>` + `<kind>:<key>` naming\n * convention in ONE place instead of re-spelling it per plugin. */\nexport const keyedBucketSpec = <State>(input: {\n\treadonly bucket: string;\n\treadonly kind: string;\n\treadonly key: string;\n\treadonly fields: ReadonlyArray<BucketField<State>>;\n}): SiblingBucketSpec<State> => ({\n\tbucket: input.bucket,\n\tkind: input.kind,\n\temitterName: `${input.kind}/${input.key}`,\n\tinstanceKey: input.key,\n\tnamespace: `${input.kind}:${input.key}`,\n\tallowEmitterNameRepetition: true,\n\tfields: input.fields,\n});\n\n/** Build the `ConfigBindingSet` for a sibling-keyed bucket instance. The\n * `configPath` of every binding is rooted at the instance key, so distinct\n * instances deep-merge into one `<bucket>.ts` exporting\n * `{ <instanceKey>: { ...fields } }`. */\nexport const siblingBucketBindings = <State>(\n\tspec: SiblingBucketSpec<State>,\n): ConfigBindingSet<State> => {\n\tconst bindings: Array<ConfigBinding<State>> = spec.fields.map((field) => {\n\t\tconst configPath = [spec.instanceKey, field.key] as const;\n\t\tif (field.variant === 'literal') {\n\t\t\treturn { variant: 'literal', configPath: [...configPath], value: field.value };\n\t\t}\n\t\treturn {\n\t\t\tvariant: 'resolved',\n\t\t\tconfigPath: [...configPath],\n\t\t\tnamespace: spec.namespace,\n\t\t\tkey: field.valueKey ?? field.key,\n\t\t\t// No `sugar` — these are generic `requireValue` bindings (the typed\n\t\t\t// deployment channel only carries network/packages/mvrOverrides).\n\t\t\t...(field.tsType !== undefined ? { tsType: field.tsType } : {}),\n\t\t\tlive: field.live,\n\t\t};\n\t});\n\treturn {\n\t\tbucket: spec.bucket,\n\t\tkind: spec.kind,\n\t\temitterName: spec.emitterName,\n\t\t...(spec.outputPath !== undefined ? { outputPath: spec.outputPath } : {}),\n\t\t...(spec.allowEmitterNameRepetition === true ? { allowEmitterNameRepetition: true } : {}),\n\t\tbindings,\n\t};\n};\n\n/** Derive the LIVE bucket decl — feeds concrete values into the generic\n * deployment `values` channel (no per-stack generated file is written). */\nexport const liveBucketCodegen = <State>(\n\tspec: SiblingBucketSpec<State>,\n\tstate: State,\n): CodegenableDecl => configCodegenable(siblingBucketBindings(spec), { mode: 'live', state });\n\n/** Derive the STATIC (stack-free) bucket decl — emits\n * `requireValue(dep, namespace, key)` for resolved fields, literals for the\n * rest. The committed `<bucket>.ts` carries no baked runtime value. */\nexport const staticBucketCodegen = <State>(spec: SiblingBucketSpec<State>): CodegenableDecl =>\n\tconfigCodegenable(siblingBucketBindings(spec), 'static');\n"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -14,11 +14,11 @@ import { retry_policy_exports } from "./substrate/runtime/retry-policy.mjs";
14
14
  import { ContainerRuntimeService } from "./runtime/docker/service.mjs";
15
15
  import { process_supervisor_exports } from "./substrate/runtime/process-supervisor.mjs";
16
16
  import { PluginContext } from "./substrate/plugin-ctx.mjs";
17
+ import { DEFAULT_DEVSTACK_NETWORK, DEFAULT_STACK_NAME, DEVSTACK_NETWORK_NAMES, DevstackNetworkParseError, LOCAL_NETWORK_NAME, chainIdForNetwork, networkNameFromChain, parseDevstackNetwork, parseDevstackNetworkName, resolveAppName, resolveNetwork, resolveNetworkSync, resolveStackName, resolveStateDir } from "./api/inference-network.mjs";
17
18
  import { http_probe_exports } from "./substrate/runtime/http-probe.mjs";
18
19
  import { managed_container_exports } from "./substrate/runtime/managed-container.mjs";
19
20
  import { config_validation_exports } from "./substrate/runtime/config-validation.mjs";
20
21
  import { ManifestExtrasInvalid, ManifestExtrasLookupError } from "./substrate/manifest.mjs";
21
- import { DEFAULT_DEVSTACK_NETWORK, DEFAULT_STACK_NAME, DEVSTACK_NETWORK_NAMES, DevstackNetworkParseError, LOCAL_NETWORK_NAME, chainIdForNetwork, networkNameFromChain, parseDevstackNetwork, parseDevstackNetworkName, resolveAppName, resolveNetwork, resolveNetworkSync, resolveStackName, resolveStateDir } from "./api/inference-network.mjs";
22
22
  import { runStack } from "./api/run-stack.mjs";
23
23
  import { projection } from "./api/define-capabilities.mjs";
24
24
  import { defineModeNamespace } from "./api/mode-narrowed-factory.mjs";
@@ -4,16 +4,6 @@ import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner
4
4
  //#region src/orchestrators/boot.d.ts
5
5
  interface ProductionCodegenOptions {
6
6
  readonly appRoot?: string;
7
- /** Resolved absolute path to the dev-only + secret `generated-extras`
8
- * tree for this stack, threaded into `CodegenRoot.extrasDir` and
9
- * recorded in the manifest as `codegen.extrasDir` for the
10
- * `@devstack-dev` Vite alias. This is the ONLY tree boot's codegen
11
- * writes (`emitExtras`); boot never emits the committed `src/generated`
12
- * tree, so it pins no live `outputDir` — the `CodegenRoot.outputDir`
13
- * the production path carries is an unwritten default. The committed
14
- * tree is owned solely by the stack-free `codegen` verb (wired
15
- * separately, where it resolves its own output path). */
16
- readonly extrasDir?: string;
17
7
  /** Forwarded verbatim to `@mysten/codegen`'s
18
8
  * `generateFromPackageSummary` via `layerMystenMoveCodegen` — see
19
9
  * `DevstackOptions['codegen']` for the full contract. Default `false`
@@ -26,8 +26,7 @@ import { CodegenWriteFailed } from "./codegen/errors.mjs";
26
26
  import { MoveCodegenService, MoveSummaryRunnerService, layerMystenMoveCodegen } from "./codegen/bindings.mjs";
27
27
  import { layerSuiMoveSummaryRunnerDocker } from "../plugins/sui/move-summary-runner.mjs";
28
28
  import { CodegenPathsService, layerCodegenPaths, layerCodegenRoot } from "./codegen/paths.mjs";
29
- import { resolveCodegenOutput } from "./codegen/output-location.mjs";
30
- import { ID_CONFIG_FILENAME, writeIdConfig } from "./codegen/id-config.mjs";
29
+ import { DEPLOYMENT_FILENAME, writeDeployment } from "./codegen/deployment.mjs";
31
30
  import { CodegenOrchestratorService, layerCodegenOrchestrator } from "./codegen/service.mjs";
32
31
  import { DEFAULT_TRAEFIK_IMAGE, layerTraefikContainerOpsDocker } from "./router/traefik-container.mjs";
33
32
  import { makeDefaultRouterProfile } from "./router/profile.mjs";
@@ -38,11 +37,10 @@ import { BUILT_IN_ENTRYPOINTS } from "../plugins/router-entrypoints.mjs";
38
37
  import { ManifestExtrasLookupError, resolveManifestExtras } from "../substrate/manifest.mjs";
39
38
  import { buildEnvelope, writeManifest } from "../substrate/runtime/manifest/manifest.mjs";
40
39
  import "../substrate/runtime/manifest/index.mjs";
41
- import { resolveNetworkOptions } from "./network-options.mjs";
42
40
  import { CoinRegistryService, layerCoinRegistry } from "../plugins/coin/registry.mjs";
43
41
  import { PackageRegistryService, layerPackageRegistry } from "../plugins/package/registry.mjs";
44
42
  import { Context, Effect, FileSystem, Layer, Ref } from "effect";
45
- import { isAbsolute, join, resolve } from "node:path";
43
+ import { join, resolve } from "node:path";
46
44
  import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem";
47
45
  import * as NodePath from "@effect/platform-node/NodePath";
48
46
  import * as NodeChildProcessSpawner from "@effect/platform-node/NodeChildProcessSpawner";
@@ -113,28 +111,14 @@ const superviseStackEffect = (stack, identity, state, opts = {}) => Effect.gen(f
113
111
  * The ONE boot seam that maps a stack's codegen config to the production
114
112
  * codegen orchestrator options for a LIVE (`'ran'`) projection. Both
115
113
  * composition entry points (`api/run-stack.ts` and `orchestrators/layers.ts`)
116
- * call this so the live output-dir decision (via `resolveCodegenOutput`)
117
- * is wired exactly once: EVERY live run including what used to be the
118
- * "primary" stack emits into `<appRoot>/.devstack/stacks/<stack>/generated`,
119
- * so the id-bearing live tree never lands in the committed source tree and
120
- * two stacks never clobber. The committed `src/generated` tree is owned
121
- * solely by the stack-free `codegen` verb. The resolved literal
122
- * `outputDir`/`stackSubdir`/`extrasDir` flow into
123
- * `layerProductionOrchestrators({ codegen })` unchanged — `paths.ts` keeps
124
- * consuming literals (minimal blast radius).
125
- *
126
- * The per-stack inputs: the app root, the resolved effective stack
127
- * (already through the explicit-`--stack` > `config.stackName` > inferred
128
- * ladder), and the app's optional explicit `codegen` pins.
114
+ * call this. Boot writes no committed `src/generated` tree (owned solely by
115
+ * the stack-free `codegen` verb), so there is no live dev-output dir to
116
+ * resolve; only the app root + the pass-through phantom-type flag flow into
117
+ * `layerProductionOrchestrators({ codegen })`.
129
118
  */
130
119
  const resolveProductionCodegenOptions = (input) => {
131
- const resolved = resolveCodegenOutput({
132
- appRoot: input.appRoot,
133
- effectiveStack: input.effectiveStack
134
- });
135
120
  return {
136
121
  appRoot: input.appRoot,
137
- extrasDir: resolved.extrasDir,
138
122
  ...input.codegen?.includePhantomTypeParameters === void 0 ? {} : { includePhantomTypeParameters: input.codegen.includePhantomTypeParameters }
139
123
  };
140
124
  };
@@ -160,22 +144,13 @@ const layerManifestEndpointRegistry = Layer.effect(ManifestEndpointRegistryServi
160
144
  }));
161
145
  const productionRouterProfile = (options = {}) => makeDefaultRouterProfile(options);
162
146
  /** `outputDir` for the `CodegenRoot` of a `layerProductionOrchestrators`
163
- * composition. The production codegen path NEVER emits the committed
164
- * `src/generated` tree (boot writes only `generated-extras` via
165
- * `emitExtras`), so this directory is never written it only has to wire
166
- * a valid, non-crashing `CodegenRoot`. It resolves to `<appRoot>/src/generated`
167
- * by convention. The committed tree is owned solely by the stack-free
168
- * `codegen` verb (wired separately, where it pins its own output path). */
147
+ * composition `<appRoot>/src/generated`. Boot's `assembleDeployment`
148
+ * writes no file here; the dev-`up` `emitBindings` refresh DOES re-emit
149
+ * this committed tree from the STATIC (id-free) contributions so an edited
150
+ * Move package's new shapes reach the app. `apply` / `runStack` pass no
151
+ * `emitBindings`, so they leave it untouched. The stack-free `codegen` verb
152
+ * owns the canonical emit (wired separately, where it pins its own path). */
169
153
  const productionCodegenOutputDir = (appRoot) => resolve(appRoot, "src/generated");
170
- /** Fallback `generated-extras` dir for the cold-start / no-config
171
- * composition path (`buildDirectSnapshotLayers`). Callers that know
172
- * their stack (`run-stack`, the verb wirings) pass the resolved
173
- * per-stack value; this default only feeds direct-snapshot verbs that
174
- * never run codegen. */
175
- const productionCodegenExtrasDir = (appRoot, extrasDir) => {
176
- const target = extrasDir ?? ".devstack/generated-extras";
177
- return isAbsolute(target) ? target : resolve(appRoot, target);
178
- };
179
154
  const layerProductionOrchestrators = (router = {}) => {
180
155
  const profile = productionRouterProfile();
181
156
  return Layer.mergeAll(layerSnapshotOrchestrator, layerManifestEndpointRegistry, layerRouterService.pipe(Layer.provideMerge(Layer.mergeAll(layerEntrypointRegistry(BUILT_IN_ENTRYPOINTS), layerTraefikContainerOpsDocker, layerDockerUpstreamResolver(profile), layerRouterConfigLiteral({
@@ -185,8 +160,7 @@ const layerProductionOrchestrators = (router = {}) => {
185
160
  routeReadinessProbe: { enabled: router.disabled !== true }
186
161
  })))), layerCodegenOrchestrator, layerCodegenPaths.pipe(Layer.provideMerge(layerCodegenRoot({
187
162
  outputDir: productionCodegenOutputDir(router.codegen?.appRoot ?? process.cwd()),
188
- stackSubdir: null,
189
- extrasDir: productionCodegenExtrasDir(router.codegen?.appRoot ?? process.cwd(), router.codegen?.extrasDir)
163
+ stackSubdir: null
190
164
  }))), layerSuiMoveSummaryRunnerDocker, layerMystenMoveCodegen({ includePhantomTypeParameters: router.codegen?.includePhantomTypeParameters }));
191
165
  };
192
166
  /** The single adapter for routable endpoints: ONE `ResolvedRoute` (the
@@ -345,13 +319,13 @@ const buildProductionPostAcquireHook = (options = {}) => Effect.gen(function* ()
345
319
  const extras = yield* resolveManifestExtras(options.extras, makeManifestExtrasContext(ctx));
346
320
  const routableEndpoints = yield* manifestEndpoints.entries;
347
321
  const endpoints = [...routableEndpoints, ...operationalManifestEndpointEntries(ctx, routableEndpoints)];
348
- const idConfig = yield* codegen.assembleIdConfig(String(ctx.identity.network)).pipe(Effect.mapError((cause) => new CodegenWriteFailed({
349
- outputPath: ID_CONFIG_FILENAME,
322
+ const deployment = yield* codegen.assembleDeployment(String(ctx.identity.network)).pipe(Effect.mapError((cause) => new CodegenWriteFailed({
323
+ outputPath: DEPLOYMENT_FILENAME,
350
324
  stage: "write",
351
325
  cause
352
326
  })));
353
- const idsFile = join(stackPaths.stackRoot, ID_CONFIG_FILENAME);
354
- yield* writeIdConfig(idsFile, idConfig).pipe(Effect.provideService(FileSystem.FileSystem, fs));
327
+ const deploymentFile = join(stackPaths.stackRoot, DEPLOYMENT_FILENAME);
328
+ yield* writeDeployment(deploymentFile, deployment).pipe(Effect.provideService(FileSystem.FileSystem, fs));
355
329
  yield* writeManifest(yield* buildEnvelope({
356
330
  identity: {
357
331
  app: ctx.identity.app,
@@ -360,17 +334,8 @@ const buildProductionPostAcquireHook = (options = {}) => Effect.gen(function* ()
360
334
  },
361
335
  endpoints,
362
336
  extras,
363
- codegen: {
364
- extrasDir: paths.extrasDir,
365
- idsFile
366
- }
337
+ codegen: { deploymentFile }
367
338
  }), join(stackPaths.stackRoot, "manifest.json")).pipe(Effect.provideService(FileSystem.FileSystem, fs));
368
- const netOpts = resolveNetworkOptions(ctx.identity.network, options.networkOptions);
369
- const extrasFiles = [];
370
- if (netOpts.devWallet) {
371
- const extras = yield* codegen.emitExtras().pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(CodegenPathsService, paths), Effect.provideService(MoveSummaryRunnerService, moveRunner), Effect.provideService(MoveCodegenService, moveCodegen));
372
- extrasFiles.push(...extras.filesWritten, ...extras.filesChmod);
373
- }
374
339
  const bindingFiles = [];
375
340
  if (options.emitBindings !== void 0) {
376
341
  const emitted = yield* codegen.emitBindings(options.emitBindings).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(CodegenPathsService, paths), Effect.provideService(MoveSummaryRunnerService, moveRunner), Effect.provideService(MoveCodegenService, moveCodegen));
@@ -383,11 +348,7 @@ const buildProductionPostAcquireHook = (options = {}) => Effect.gen(function* ()
383
348
  at: Date.now()
384
349
  }, {
385
350
  tag: "codegen.emitted",
386
- files: [
387
- idsFile,
388
- ...extrasFiles,
389
- ...bindingFiles
390
- ],
351
+ files: [deploymentFile, ...bindingFiles],
391
352
  at: Date.now()
392
353
  }];
393
354
  });
@@ -430,7 +391,6 @@ const superviseStackWithProductionBoot = (stack, identity, state, opts = {}) =>
430
391
  contributionDispatcher: yield* buildProductionContributionDispatcher(),
431
392
  postAcquireHook: yield* buildProductionPostAcquireHook({
432
393
  ...opts.extras === void 0 ? {} : { extras: opts.extras },
433
- ...opts.networkOptions === void 0 ? {} : { networkOptions: opts.networkOptions },
434
394
  ...opts.emitBindings === void 0 ? {} : { emitBindings: opts.emitBindings }
435
395
  }),
436
396
  ...opts.lifetime === void 0 ? {} : { lifetime: opts.lifetime },