@mysten-incubation/devstack 0.2.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 (159) hide show
  1. package/README.md +1 -1
  2. package/dashboard-ui/assets/{grpc-a4usE3Nk.js → grpc-CpkDu4SA.js} +1 -1
  3. package/dashboard-ui/assets/{index-CRYJ4pru.js → index-jLPRmjst.js} +39 -33
  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 +2 -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/config.d.mts +2 -1
  14. package/dist/build-integrations/playwright/config.mjs +1 -1
  15. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  16. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  17. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  18. package/dist/build-integrations/playwright/index.d.mts +2 -2
  19. package/dist/build-integrations/playwright/index.mjs +2 -2
  20. package/dist/build-integrations/playwright/wallet-context.d.mts +2 -1
  21. package/dist/build-integrations/playwright/wallet-context.mjs +141 -41
  22. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  23. package/dist/build-integrations/runtime/dapp-kit-slot.mjs +1 -1
  24. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  25. package/dist/build-integrations/vite/index.d.mts +82 -40
  26. package/dist/build-integrations/vite/index.mjs +281 -112
  27. package/dist/build-integrations/vite/index.mjs.map +1 -1
  28. package/dist/build-integrations/vitest/config.mjs +3 -4
  29. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  30. package/dist/build-integrations/vitest/global-setup.mjs +8 -8
  31. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -1
  32. package/dist/cli/doctor-probes.mjs +7 -2
  33. package/dist/cli/doctor-probes.mjs.map +1 -1
  34. package/dist/cli/main.mjs +5 -4
  35. package/dist/cli/main.mjs.map +1 -1
  36. package/dist/cli/wirings/apply.mjs +0 -1
  37. package/dist/cli/wirings/apply.mjs.map +1 -1
  38. package/dist/cli/wirings/codegen.mjs +37 -38
  39. package/dist/cli/wirings/codegen.mjs.map +1 -1
  40. package/dist/cli/wirings/dump-deployment.mjs +141 -0
  41. package/dist/cli/wirings/dump-deployment.mjs.map +1 -0
  42. package/dist/cli/wirings/snapshot.mjs +0 -1
  43. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  44. package/dist/cli/wirings/up.mjs +7 -0
  45. package/dist/cli/wirings/up.mjs.map +1 -1
  46. package/dist/contracts/codegenable.d.mts +22 -25
  47. package/dist/contracts/codegenable.mjs +35 -4
  48. package/dist/contracts/codegenable.mjs.map +1 -1
  49. package/dist/contracts/config-bindings.mjs +43 -18
  50. package/dist/contracts/config-bindings.mjs.map +1 -1
  51. package/dist/index.mjs +1 -1
  52. package/dist/orchestrators/boot.d.mts +0 -10
  53. package/dist/orchestrators/boot.mjs +24 -54
  54. package/dist/orchestrators/boot.mjs.map +1 -1
  55. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  56. package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
  57. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
  58. package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
  59. package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
  60. package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
  61. package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
  62. package/dist/orchestrators/codegen/deployment.d.mts +63 -0
  63. package/dist/orchestrators/codegen/deployment.mjs +153 -0
  64. package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
  65. package/dist/orchestrators/codegen/errors.mjs +7 -9
  66. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  67. package/dist/orchestrators/codegen/format.mjs +20 -1
  68. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  69. package/dist/orchestrators/codegen/paths.mjs +1 -8
  70. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  71. package/dist/orchestrators/codegen/service.mjs +369 -141
  72. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  73. package/dist/orchestrators/layers.mjs +0 -1
  74. package/dist/orchestrators/layers.mjs.map +1 -1
  75. package/dist/orchestrators/network-options.d.mts +37 -35
  76. package/dist/orchestrators/network-options.mjs +13 -10
  77. package/dist/orchestrators/network-options.mjs.map +1 -1
  78. package/dist/plugins/account/codegen.d.mts +3 -4
  79. package/dist/plugins/account/codegen.mjs +5 -7
  80. package/dist/plugins/account/codegen.mjs.map +1 -1
  81. package/dist/plugins/account/index.mjs +1 -3
  82. package/dist/plugins/account/index.mjs.map +1 -1
  83. package/dist/plugins/coin/codegen.mjs +5 -5
  84. package/dist/plugins/coin/codegen.mjs.map +1 -1
  85. package/dist/plugins/coin/index.mjs.map +1 -1
  86. package/dist/plugins/dashboard/domain.mjs +18 -1
  87. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  88. package/dist/plugins/dashboard/schema/root.mjs +5 -3
  89. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  90. package/dist/plugins/dashboard/schema/types.mjs +15 -2
  91. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  92. package/dist/plugins/deepbook/codegen.mjs +4 -4
  93. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  94. package/dist/plugins/deepbook/index.d.mts +7 -3
  95. package/dist/plugins/deepbook/index.mjs +3 -3
  96. package/dist/plugins/deepbook/index.mjs.map +1 -1
  97. package/dist/plugins/internal/codegen-helpers.mjs +0 -1
  98. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  99. package/dist/plugins/package/codegen.d.mts +1 -12
  100. package/dist/plugins/package/codegen.mjs +43 -25
  101. package/dist/plugins/package/codegen.mjs.map +1 -1
  102. package/dist/plugins/package/dep-resolution.mjs +1 -1
  103. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  104. package/dist/plugins/package/index.d.mts +14 -11
  105. package/dist/plugins/package/index.mjs +6 -7
  106. package/dist/plugins/package/index.mjs.map +1 -1
  107. package/dist/plugins/seal/codegen.mjs +3 -3
  108. package/dist/plugins/seal/codegen.mjs.map +1 -1
  109. package/dist/plugins/seal/index.mjs.map +1 -1
  110. package/dist/plugins/sui/codegen.mjs +5 -4
  111. package/dist/plugins/sui/codegen.mjs.map +1 -1
  112. package/dist/plugins/sui/index.d.mts +10 -10
  113. package/dist/plugins/sui/index.mjs +1 -2
  114. package/dist/plugins/sui/index.mjs.map +1 -1
  115. package/dist/plugins/sui/move-summary-runner.mjs +29 -2
  116. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  117. package/dist/plugins/wallet/codegen.d.mts +8 -12
  118. package/dist/plugins/wallet/codegen.mjs +22 -15
  119. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  120. package/dist/plugins/wallet/index.d.mts +4 -3
  121. package/dist/plugins/wallet/index.mjs +1 -1
  122. package/dist/plugins/wallet/index.mjs.map +1 -1
  123. package/dist/plugins/wallet/service.d.mts +2 -2
  124. package/dist/plugins/wallet/service.mjs +2 -3
  125. package/dist/plugins/wallet/service.mjs.map +1 -1
  126. package/dist/plugins/walrus/codegen.mjs +4 -4
  127. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  128. package/dist/plugins/walrus/index.mjs +1 -1
  129. package/dist/plugins/walrus/index.mjs.map +1 -1
  130. package/dist/substrate/manifest.d.mts +17 -22
  131. package/dist/substrate/manifest.mjs +4 -6
  132. package/dist/substrate/manifest.mjs.map +1 -1
  133. package/dist/substrate/plugin-ctx.d.mts +6 -6
  134. package/dist/substrate/plugin-ctx.mjs.map +1 -1
  135. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  136. package/dist/substrate/runtime/index.mjs +1 -0
  137. package/dist/substrate/runtime/lifecycle/file-watcher.d.mts +1 -0
  138. package/dist/substrate/runtime/lifecycle/file-watcher.mjs +54 -0
  139. package/dist/substrate/runtime/lifecycle/file-watcher.mjs.map +1 -0
  140. package/dist/substrate/runtime/lifecycle/index.mjs +1 -0
  141. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +76 -6
  142. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  143. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  144. package/dist/substrate/runtime/paths.mjs +1 -1
  145. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +2 -6
  146. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  147. package/dist/surfaces/cli/command-tree.mjs +6 -6
  148. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  149. package/dist/surfaces/cli/index.mjs +6 -4
  150. package/dist/surfaces/cli/index.mjs.map +1 -1
  151. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  152. package/package.json +1 -1
  153. package/dist/cli/wirings/dump-ids.mjs +0 -86
  154. package/dist/cli/wirings/dump-ids.mjs.map +0 -1
  155. package/dist/orchestrators/codegen/id-config.d.mts +0 -1
  156. package/dist/orchestrators/codegen/id-config.mjs +0 -107
  157. package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
  158. package/dist/orchestrators/codegen/output-location.mjs +0 -32
  159. package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. `ctx.codegen` — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. `ctx.endpoint` — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, makeSealStaticCodegen, type SealBindings } from './codegen.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { bootSealService, type SealMode } from './service.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport { type SealError, type SealAnyError, type SealConfigError } from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet). */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n/** Fork-known-mode options. */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n// ---------------------------------------------------------------------------\n// The three seal `start` bodies emit their contributions inline via the typed\n// `ctx` verbs after resolving the value. The decl shapes + emit ORDER are\n// load-bearing.\n//\n// ⚠ ID-STABILITY: the snapshotable decl captures the seal vault / master-key\n// secret material subtree; its shape (subtree paths, container label tuple,\n// secretMaterial / missingTolerance flags) MUST stay byte-identical.\n// ---------------------------------------------------------------------------\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\t// Stack-free codegen: the key-server object id / URL / committee are\n\t\t// LOADED CONFIG DATA -- the committed `seal.ts` stub emits\n\t\t// `resolveValue('seal:<name>', '<key>')`, never a baked object id.\n\t\tstaticCodegen: () => [makeSealStaticCodegen({ name: resolved.name, mode: 'local-keygen' })],\n\t\t// `deps` auto-infers the resolved `{ sui, signer }` dependency\n\t\t// object from seal's `dependsOn: { sui: suiResource, signer:\n\t\t// opts.signer }`. `ctx` is the typed plugin-authoring surface the\n\t\t// contribution emission below drives; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chainId);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchainId: sui.chainId,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\t// Emit the resolved contributions inline: snapshot (seal vault /\n\t\t\t\t// master-key secret-material subtree) → codegen → routable (key\n\t\t\t\t// server). `resolvedValue` is the just-resolved `SealResolved`;\n\t\t\t\t// `identity` (from `IdentityContext`) stamps the snapshot +\n\t\t\t\t// routable container name. The codegen bindings carry the REAL\n\t\t\t\t// objectId / keyServerUrl / serverConfigs.\n\t\t\t\tctx.snapshotExtra(\n\t\t\t\t\tmakeLocalKeygenSnapshotable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tobjectId: resolvedValue.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolvedValue.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolvedValue.serverConfigs,\n\t\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeSealRoutable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work.\n\tconst validated = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: validated.objectId,\n\t\tkeyServerUrl: validated.keyServerUrl,\n\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}` tuple\n\t\t// at factory time (DECLARED config) — bake them as literals in the\n\t\t// committed `seal.ts` (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'live',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Live mode has no `dependsOn`, so `start` is zero-arg. `ctx`\n\t\t// drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst mode: SealMode = { mode: 'live', name, resolved: validated };\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\t// Emit inline: snapshot → codegen. `snap` + `bindings` are\n\t\t\t\t// resolved at FACTORY time for live mode (validated\n\t\t\t\t// `{objectId, keyServerUrl}`), so the emit reuses the same\n\t\t\t\t// precomputed values.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeSealCodegenable(bindings));\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Fork-known mode resolves its `{objectId, keyServerUrl}` tuple at\n\t\t// factory time (DECLARED config, via `validateForkKnownInputs`) — bake\n\t\t// them as literals in the committed `seal.ts` (mirrors `knownPackage`).\n\t\t// The committee `serverConfigs` is the single declared key-server (the\n\t\t// same shape `acquireLive` derives), so it is declared config too.\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'fork-known',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Fork-known mode has no `dependsOn`, so `start` is zero-arg.\n\t\t// `ctx` drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Symmetric with the live branch's `{ mode, name, resolved }`\n\t\t\t\t// envelope. `upstream` rides through for downstream\n\t\t\t\t// span attribution; `resolved` carries the validated\n\t\t\t\t// `{objectId, keyServerUrl}` tuple.\n\t\t\t\tconst mode: SealMode = {\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tname,\n\t\t\t\t\tupstream: opts.upstream,\n\t\t\t\t\tresolved: validated,\n\t\t\t\t};\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t};\n\t\t\t\t// Emit inline: snapshot → codegen. `bindings` is built from the\n\t\t\t\t// post-acquire `resolved.keyServer` (`{objectId, keyServerUrl,\n\t\t\t\t// serverConfigs}`); `snap` is factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tobjectId: resolved.keyServer.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolved.keyServer.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolved.keyServer.serverConfigs,\n\t\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\tcustom: (\n\t\t\topts: Required<Pick<SealLiveOptions, 'objectId' | 'keyServerUrl'>> & SealLiveOptions,\n\t\t) => buildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. `ctx.codegen` — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. `ctx.endpoint` — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, makeSealStaticCodegen, type SealBindings } from './codegen.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { bootSealService, type SealMode } from './service.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport { type SealError, type SealAnyError, type SealConfigError } from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet). */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n/** Fork-known-mode options. */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n// ---------------------------------------------------------------------------\n// The three seal `start` bodies emit their contributions inline via the typed\n// `ctx` verbs after resolving the value. The decl shapes + emit ORDER are\n// load-bearing.\n//\n// ⚠ ID-STABILITY: the snapshotable decl captures the seal vault / master-key\n// secret material subtree; its shape (subtree paths, container label tuple,\n// secretMaterial / missingTolerance flags) MUST stay byte-identical.\n// ---------------------------------------------------------------------------\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\t// Stack-free codegen: the key-server object id / URL / committee are\n\t\t// LOADED CONFIG DATA -- the committed `seal.ts` stub emits\n\t\t// `requireValue(dep, 'seal:<name>', '<key>')`, never a baked object id.\n\t\tstaticCodegen: () => [makeSealStaticCodegen({ name: resolved.name, mode: 'local-keygen' })],\n\t\t// `deps` auto-infers the resolved `{ sui, signer }` dependency\n\t\t// object from seal's `dependsOn: { sui: suiResource, signer:\n\t\t// opts.signer }`. `ctx` is the typed plugin-authoring surface the\n\t\t// contribution emission below drives; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chainId);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchainId: sui.chainId,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\t// Emit the resolved contributions inline: snapshot (seal vault /\n\t\t\t\t// master-key secret-material subtree) → codegen → routable (key\n\t\t\t\t// server). `resolvedValue` is the just-resolved `SealResolved`;\n\t\t\t\t// `identity` (from `IdentityContext`) stamps the snapshot +\n\t\t\t\t// routable container name. The codegen bindings carry the REAL\n\t\t\t\t// objectId / keyServerUrl / serverConfigs.\n\t\t\t\tctx.snapshotExtra(\n\t\t\t\t\tmakeLocalKeygenSnapshotable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tobjectId: resolvedValue.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolvedValue.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolvedValue.serverConfigs,\n\t\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeSealRoutable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work.\n\tconst validated = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: validated.objectId,\n\t\tkeyServerUrl: validated.keyServerUrl,\n\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}` tuple\n\t\t// at factory time (DECLARED config) — bake them as literals in the\n\t\t// committed `seal.ts` (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'live',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Live mode has no `dependsOn`, so `start` is zero-arg. `ctx`\n\t\t// drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst mode: SealMode = { mode: 'live', name, resolved: validated };\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\t// Emit inline: snapshot → codegen. `snap` + `bindings` are\n\t\t\t\t// resolved at FACTORY time for live mode (validated\n\t\t\t\t// `{objectId, keyServerUrl}`), so the emit reuses the same\n\t\t\t\t// precomputed values.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeSealCodegenable(bindings));\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Fork-known mode resolves its `{objectId, keyServerUrl}` tuple at\n\t\t// factory time (DECLARED config, via `validateForkKnownInputs`) — bake\n\t\t// them as literals in the committed `seal.ts` (mirrors `knownPackage`).\n\t\t// The committee `serverConfigs` is the single declared key-server (the\n\t\t// same shape `acquireLive` derives), so it is declared config too.\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'fork-known',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Fork-known mode has no `dependsOn`, so `start` is zero-arg.\n\t\t// `ctx` drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Symmetric with the live branch's `{ mode, name, resolved }`\n\t\t\t\t// envelope. `upstream` rides through for downstream\n\t\t\t\t// span attribution; `resolved` carries the validated\n\t\t\t\t// `{objectId, keyServerUrl}` tuple.\n\t\t\t\tconst mode: SealMode = {\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tname,\n\t\t\t\t\tupstream: opts.upstream,\n\t\t\t\t\tresolved: validated,\n\t\t\t\t};\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t};\n\t\t\t\t// Emit inline: snapshot → codegen. `bindings` is built from the\n\t\t\t\t// post-acquire `resolved.keyServer` (`{objectId, keyServerUrl,\n\t\t\t\t// serverConfigs}`); `snap` is factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tobjectId: resolved.keyServer.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolved.keyServer.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolved.keyServer.serverConfigs,\n\t\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\tcustom: (\n\t\t\topts: Required<Pick<SealLiveOptions, 'objectId' | 'keyServerUrl'>> & SealLiveOptions,\n\t\t) => buildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
@@ -3,8 +3,8 @@ import { configCodegenable } from "../../contracts/config-bindings.mjs";
3
3
  //#region src/plugins/sui/codegen.ts
4
4
  /** The sui-plugin's config bindings, declared ONCE. Both the live boot decl
5
5
  * and the static committed-tree decl are derived from this set:
6
- * - `network` — sugar `resolveNetwork()` / live = `"localnet"`.
7
- * - `networks` — sugar `resolveNetworks()` / live = `{ localnet: entry }`.
6
+ * - `network` — sugar `dep.network` / live = `"localnet"`.
7
+ * - `networks` — sugar `Object.fromEntries(networkNames.map(forNetwork))` / live = `{ localnet: entry }`.
8
8
  * The network NAME + connection map are environment/live data, so both are
9
9
  * RESOLVED bindings (never literals). */
10
10
  const suiConfigBindings = () => {
@@ -39,13 +39,14 @@ const suiConfigBindings = () => {
39
39
  };
40
40
  /** The LIVE Codegenable contribution. Bakes the resolved network entry into
41
41
  * the combined `config.ts` aggregate (chainId/rpc/faucet/graphql) — boot's
42
- * `assembleIdConfig` slices it back into the loadable id-config. */
42
+ * `assembleDeployment` slices it back into the loadable deployment. */
43
43
  const makeCodegenable = (resolved) => configCodegenable(suiConfigBindings(), {
44
44
  mode: "live",
45
45
  state: resolved
46
46
  });
47
47
  /** The STATIC (stack-free) Codegenable contribution for the `codegen` verb.
48
- * Emits `resolveNetwork()` / `resolveNetworks()` raw expressions — the
48
+ * Emits `dep.network` / `Object.fromEntries(networkNames.map(forNetwork))`
49
+ * raw expressions off the loaded deployment — the
49
50
  * committed `config.ts` carries no network name and no literal rpc URL. No
50
51
  * id-resolver input needed (the values are injected, not config-derived). */
51
52
  const makeStaticCodegen = () => () => [configCodegenable(suiConfigBindings(), "static")];
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/sui/codegen.ts"],"sourcesContent":["// Sui plugin — Codegenable contribution, via the UNIFIED config-binding\n// declaration.\n//\n// Architecture §6: plugins emit typed `CodegenableDecl`s; the codegen\n// orchestrator stages files into the user's source tree WITHOUT naming the\n// plugin. Sui's contribution is the active network: the active key\n// (`network: \"localnet\"`) plus the `networks.localnet` entry (chainId, mode,\n// rpc, faucet, graphql, forkUpstream).\n//\n// ONE declaration, TWO derivations. Sui declares its `config.ts`\n// contributions ONCE as a `ConfigBindingSet`; the framework derives:\n// - the LIVE (boot) decl — bakes the resolved network entry into the\n// loadable id-config (so `assembleIdConfig` reads it back), AND\n// - the STATIC (committed-tree) decl — emits `resolveNetwork()` /\n// `resolveNetworks()` raw expressions so the committed `config.ts`\n// carries NO network name and NO literal rpc URL (both are\n// environment/live data: a dynamic local rpc port; a real deployment\n// names a different network — resolved at app build/dev time via the\n// injected `__DEVSTACK_IDS__` global).\n//\n// The decl is `aggregateOnly` — it projects directly into the combined\n// `generated/config.ts` (`config.network` + `config.networks.localnet`) and\n// emits NO standalone `sui/network.ts`.\n\nimport { LOCAL_NETWORK_NAME } from '../../api/inference-network.ts';\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\nimport { configCodegenable, type ConfigBindingSet } from '../../contracts/config-bindings.ts';\nimport type { JsonValue } from '../../orchestrators/codegen/id-config.ts';\nimport type { ResolvedSuiNetwork } from './network-resolver.ts';\n\n/** The typed shape one `networks.<key>` entry in `config.ts` exports. */\nexport interface SuiNetworkConfigEntry {\n\t/** Genesis-digest chain identifier of the running node (not the network\n\t * name, which is the `networks.<key>` key itself). */\n\treadonly chainId: string;\n\treadonly mode: 'local' | 'local-rpc' | 'live' | 'fork';\n\treadonly rpc: string;\n\treadonly faucet: string | null;\n\treadonly graphql: string | null;\n\t/** Fork-only — upstream identity for known-package lookups. */\n\treadonly forkUpstream: string | null;\n}\n\n/** The sui-plugin's config bindings, declared ONCE. Both the live boot decl\n * and the static committed-tree decl are derived from this set:\n * - `network` — sugar `resolveNetwork()` / live = `\"localnet\"`.\n * - `networks` — sugar `resolveNetworks()` / live = `{ localnet: entry }`.\n * The network NAME + connection map are environment/live data, so both are\n * RESOLVED bindings (never literals). */\nconst suiConfigBindings = (): ConfigBindingSet<ResolvedSuiNetwork> => {\n\tconst entryOf = (r: ResolvedSuiNetwork): JsonValue =>\n\t\t({\n\t\t\tchainId: r.chainId,\n\t\t\tmode: r.mode,\n\t\t\trpc: r.rpc,\n\t\t\tfaucet: r.faucet ?? null,\n\t\t\tgraphql: r.graphql ?? null,\n\t\t\tforkUpstream: r.forkUpstream ?? null,\n\t\t}) satisfies SuiNetworkConfigEntry;\n\n\treturn {\n\t\tbucket: 'config.ts',\n\t\tkind: 'sui-network',\n\t\temitterName: 'sui-network',\n\t\tbindings: [\n\t\t\t{\n\t\t\t\tvariant: 'resolved',\n\t\t\t\tconfigPath: ['network'],\n\t\t\t\tnamespace: 'sui',\n\t\t\t\tkey: 'network',\n\t\t\t\tsugar: { kind: 'network' },\n\t\t\t\tlive: () => LOCAL_NETWORK_NAME,\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: 'resolved',\n\t\t\t\tconfigPath: ['networks'],\n\t\t\t\tnamespace: 'sui',\n\t\t\t\tkey: 'networks',\n\t\t\t\tsugar: { kind: 'networks' },\n\t\t\t\tlive: (r) => ({ [LOCAL_NETWORK_NAME]: entryOf(r) }),\n\t\t\t},\n\t\t],\n\t} satisfies ConfigBindingSet<ResolvedSuiNetwork>;\n};\n\n/** The LIVE Codegenable contribution. Bakes the resolved network entry into\n * the combined `config.ts` aggregate (chainId/rpc/faucet/graphql) — boot's\n * `assembleIdConfig` slices it back into the loadable id-config. */\nexport const makeCodegenable = (resolved: ResolvedSuiNetwork): CodegenableDecl =>\n\tconfigCodegenable(suiConfigBindings(), { mode: 'live', state: resolved });\n\n/** The STATIC (stack-free) Codegenable contribution for the `codegen` verb.\n * Emits `resolveNetwork()` / `resolveNetworks()` raw expressions — the\n * committed `config.ts` carries no network name and no literal rpc URL. No\n * id-resolver input needed (the values are injected, not config-derived). */\nexport const makeStaticCodegen = (): (() => ReadonlyArray<CodegenableDecl>) => () => [\n\tconfigCodegenable(suiConfigBindings(), 'static'),\n];\n"],"mappings":";;;;;;;;;AAiDA,MAAM,0BAAgE;CACrE,MAAM,WAAW,OACf;EACA,SAAS,EAAE;EACX,MAAM,EAAE;EACR,KAAK,EAAE;EACP,QAAQ,EAAE,UAAU;EACpB,SAAS,EAAE,WAAW;EACtB,cAAc,EAAE,gBAAgB;CACjC;CAED,OAAO;EACN,QAAQ;EACR,MAAM;EACN,aAAa;EACb,UAAU,CACT;GACC,SAAS;GACT,YAAY,CAAC,SAAS;GACtB,WAAW;GACX,KAAK;GACL,OAAO,EAAE,MAAM,UAAU;GACzB,YAAY;EACb,GACA;GACC,SAAS;GACT,YAAY,CAAC,UAAU;GACvB,WAAW;GACX,KAAK;GACL,OAAO,EAAE,MAAM,WAAW;GAC1B,OAAO,OAAO,GAAG,qBAAqB,QAAQ,CAAC,EAAE;EAClD,CACD;CACD;AACD;;;;AAKA,MAAa,mBAAmB,aAC/B,kBAAkB,kBAAkB,GAAG;CAAE,MAAM;CAAQ,OAAO;AAAS,CAAC;;;;;AAMzE,MAAa,gCAAwE,CACpF,kBAAkB,kBAAkB,GAAG,QAAQ,CAChD"}
1
+ {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/sui/codegen.ts"],"sourcesContent":["// Sui plugin — Codegenable contribution, via the UNIFIED config-binding\n// declaration.\n//\n// Architecture §6: plugins emit typed `CodegenableDecl`s; the codegen\n// orchestrator stages files into the user's source tree WITHOUT naming the\n// plugin. Sui's contribution is the active network: the active key\n// (`network: \"localnet\"`) plus the `networks.localnet` entry (chainId, mode,\n// rpc, faucet, graphql, forkUpstream).\n//\n// ONE declaration, TWO derivations. Sui declares its `config.ts`\n// contributions ONCE as a `ConfigBindingSet`; the framework derives:\n// - the LIVE (boot) decl — bakes the resolved network entry into the\n// loadable deployment (so `assembleDeployment` reads it back), AND\n// - the STATIC (committed-tree) decl — emits `dep.network` /\n// `Object.fromEntries(networkNames.map(forNetwork))` raw expressions off\n// the loaded deployment so the committed `config.ts`\n// carries NO network name and NO literal rpc URL (both are\n// environment/live data: a dynamic local rpc port; a real deployment\n// names a different network — resolved at app build/dev time via the\n// injected `__DEVSTACK_DEPLOYMENT__` global).\n//\n// The decl is `aggregateOnly` — it projects directly into the combined\n// `generated/config.ts` (`config.network` + `config.networks.localnet`) and\n// emits NO standalone `sui/network.ts`.\n\nimport { LOCAL_NETWORK_NAME } from '../../api/inference-network.ts';\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\nimport { configCodegenable, type ConfigBindingSet } from '../../contracts/config-bindings.ts';\nimport type { JsonValue } from '../../orchestrators/codegen/deployment.ts';\nimport type { ResolvedSuiNetwork } from './network-resolver.ts';\n\n/** The typed shape one `networks.<key>` entry in `config.ts` exports. */\nexport interface SuiNetworkConfigEntry {\n\t/** Genesis-digest chain identifier of the running node (not the network\n\t * name, which is the `networks.<key>` key itself). */\n\treadonly chainId: string;\n\treadonly mode: 'local' | 'local-rpc' | 'live' | 'fork';\n\treadonly rpc: string;\n\treadonly faucet: string | null;\n\treadonly graphql: string | null;\n\t/** Fork-only — upstream identity for known-package lookups. */\n\treadonly forkUpstream: string | null;\n}\n\n/** The sui-plugin's config bindings, declared ONCE. Both the live boot decl\n * and the static committed-tree decl are derived from this set:\n * - `network` — sugar `dep.network` / live = `\"localnet\"`.\n * - `networks` — sugar `Object.fromEntries(networkNames.map(forNetwork))` / live = `{ localnet: entry }`.\n * The network NAME + connection map are environment/live data, so both are\n * RESOLVED bindings (never literals). */\nconst suiConfigBindings = (): ConfigBindingSet<ResolvedSuiNetwork> => {\n\tconst entryOf = (r: ResolvedSuiNetwork): JsonValue =>\n\t\t({\n\t\t\tchainId: r.chainId,\n\t\t\tmode: r.mode,\n\t\t\trpc: r.rpc,\n\t\t\tfaucet: r.faucet ?? null,\n\t\t\tgraphql: r.graphql ?? null,\n\t\t\tforkUpstream: r.forkUpstream ?? null,\n\t\t}) satisfies SuiNetworkConfigEntry;\n\n\treturn {\n\t\tbucket: 'config.ts',\n\t\tkind: 'sui-network',\n\t\temitterName: 'sui-network',\n\t\tbindings: [\n\t\t\t{\n\t\t\t\tvariant: 'resolved',\n\t\t\t\tconfigPath: ['network'],\n\t\t\t\tnamespace: 'sui',\n\t\t\t\tkey: 'network',\n\t\t\t\tsugar: { kind: 'network' },\n\t\t\t\tlive: () => LOCAL_NETWORK_NAME,\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: 'resolved',\n\t\t\t\tconfigPath: ['networks'],\n\t\t\t\tnamespace: 'sui',\n\t\t\t\tkey: 'networks',\n\t\t\t\tsugar: { kind: 'networks' },\n\t\t\t\tlive: (r) => ({ [LOCAL_NETWORK_NAME]: entryOf(r) }),\n\t\t\t},\n\t\t],\n\t} satisfies ConfigBindingSet<ResolvedSuiNetwork>;\n};\n\n/** The LIVE Codegenable contribution. Bakes the resolved network entry into\n * the combined `config.ts` aggregate (chainId/rpc/faucet/graphql) — boot's\n * `assembleDeployment` slices it back into the loadable deployment. */\nexport const makeCodegenable = (resolved: ResolvedSuiNetwork): CodegenableDecl =>\n\tconfigCodegenable(suiConfigBindings(), { mode: 'live', state: resolved });\n\n/** The STATIC (stack-free) Codegenable contribution for the `codegen` verb.\n * Emits `dep.network` / `Object.fromEntries(networkNames.map(forNetwork))`\n * raw expressions off the loaded deployment — the\n * committed `config.ts` carries no network name and no literal rpc URL. No\n * id-resolver input needed (the values are injected, not config-derived). */\nexport const makeStaticCodegen = (): (() => ReadonlyArray<CodegenableDecl>) => () => [\n\tconfigCodegenable(suiConfigBindings(), 'static'),\n];\n"],"mappings":";;;;;;;;;AAkDA,MAAM,0BAAgE;CACrE,MAAM,WAAW,OACf;EACA,SAAS,EAAE;EACX,MAAM,EAAE;EACR,KAAK,EAAE;EACP,QAAQ,EAAE,UAAU;EACpB,SAAS,EAAE,WAAW;EACtB,cAAc,EAAE,gBAAgB;CACjC;CAED,OAAO;EACN,QAAQ;EACR,MAAM;EACN,aAAa;EACb,UAAU,CACT;GACC,SAAS;GACT,YAAY,CAAC,SAAS;GACtB,WAAW;GACX,KAAK;GACL,OAAO,EAAE,MAAM,UAAU;GACzB,YAAY;EACb,GACA;GACC,SAAS;GACT,YAAY,CAAC,UAAU;GACvB,WAAW;GACX,KAAK;GACL,OAAO,EAAE,MAAM,WAAW;GAC1B,OAAO,OAAO,GAAG,qBAAqB,QAAQ,CAAC,EAAE;EAClD,CACD;CACD;AACD;;;;AAKA,MAAa,mBAAmB,aAC/B,kBAAkB,kBAAkB,GAAG;CAAE,MAAM;CAAQ,OAAO;AAAS,CAAC;;;;;;AAOzE,MAAa,gCAAwE,CACpF,kBAAkB,kBAAkB,GAAG,QAAQ,CAChD"}
@@ -20,7 +20,7 @@ import { Effect, Scope } from "effect";
20
20
  declare const sui: <const O extends SuiOptions = {
21
21
  mode: "local";
22
22
  }>(opts?: O) => Plugin<"sui", {
23
- mode: "local" | "live" | "fork" | "local-rpc";
23
+ mode: "local" | "local-rpc" | "live" | "fork";
24
24
  fundingFaucetStrategy: FaucetStrategy | null;
25
25
  sdk: SuiSdkShim;
26
26
  rpcUrl: string;
@@ -51,7 +51,7 @@ declare const sui: <const O extends SuiOptions = {
51
51
  declare const suiFor: ModeNamespace<{
52
52
  local: {
53
53
  local: <const O extends Omit<SuiLocalOptions, "mode">>(opts?: O) => Plugin<"sui", {
54
- mode: "local" | "live" | "fork" | "local-rpc";
54
+ mode: "local" | "local-rpc" | "live" | "fork";
55
55
  fundingFaucetStrategy: FaucetStrategy | null;
56
56
  sdk: SuiSdkShim;
57
57
  rpcUrl: string;
@@ -70,7 +70,7 @@ declare const suiFor: ModeNamespace<{
70
70
  buildImage: ImageRef | null;
71
71
  }, readonly []>;
72
72
  localRpc: (opts: Omit<SuiLocalRpcOptions, "mode">) => Plugin<"sui", {
73
- mode: "local" | "live" | "fork" | "local-rpc";
73
+ mode: "local" | "local-rpc" | "live" | "fork";
74
74
  fundingFaucetStrategy: FaucetStrategy | null;
75
75
  sdk: SuiSdkShim;
76
76
  rpcUrl: string;
@@ -91,7 +91,7 @@ declare const suiFor: ModeNamespace<{
91
91
  };
92
92
  live: {
93
93
  testnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
94
- mode: "local" | "live" | "fork" | "local-rpc";
94
+ mode: "local" | "local-rpc" | "live" | "fork";
95
95
  fundingFaucetStrategy: FaucetStrategy | null;
96
96
  sdk: SuiSdkShim;
97
97
  rpcUrl: string;
@@ -110,7 +110,7 @@ declare const suiFor: ModeNamespace<{
110
110
  buildImage: ImageRef | null;
111
111
  }, readonly []>;
112
112
  mainnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
113
- mode: "local" | "live" | "fork" | "local-rpc";
113
+ mode: "local" | "local-rpc" | "live" | "fork";
114
114
  fundingFaucetStrategy: FaucetStrategy | null;
115
115
  sdk: SuiSdkShim;
116
116
  rpcUrl: string;
@@ -129,7 +129,7 @@ declare const suiFor: ModeNamespace<{
129
129
  buildImage: ImageRef | null;
130
130
  }, readonly []>;
131
131
  devnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
132
- mode: "local" | "live" | "fork" | "local-rpc";
132
+ mode: "local" | "local-rpc" | "live" | "fork";
133
133
  fundingFaucetStrategy: FaucetStrategy | null;
134
134
  sdk: SuiSdkShim;
135
135
  rpcUrl: string;
@@ -148,7 +148,7 @@ declare const suiFor: ModeNamespace<{
148
148
  buildImage: ImageRef | null;
149
149
  }, readonly []>;
150
150
  custom: (opts: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
151
- mode: "local" | "live" | "fork" | "local-rpc";
151
+ mode: "local" | "local-rpc" | "live" | "fork";
152
152
  fundingFaucetStrategy: FaucetStrategy | null;
153
153
  sdk: SuiSdkShim;
154
154
  rpcUrl: string;
@@ -169,7 +169,7 @@ declare const suiFor: ModeNamespace<{
169
169
  };
170
170
  fork: {
171
171
  mainnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
172
- mode: "local" | "live" | "fork" | "local-rpc";
172
+ mode: "local" | "local-rpc" | "live" | "fork";
173
173
  fundingFaucetStrategy: FaucetStrategy | null;
174
174
  sdk: SuiSdkShim;
175
175
  rpcUrl: string;
@@ -188,7 +188,7 @@ declare const suiFor: ModeNamespace<{
188
188
  buildImage: ImageRef | null;
189
189
  }, readonly []>;
190
190
  testnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
191
- mode: "local" | "live" | "fork" | "local-rpc";
191
+ mode: "local" | "local-rpc" | "live" | "fork";
192
192
  fundingFaucetStrategy: FaucetStrategy | null;
193
193
  sdk: SuiSdkShim;
194
194
  rpcUrl: string;
@@ -207,7 +207,7 @@ declare const suiFor: ModeNamespace<{
207
207
  buildImage: ImageRef | null;
208
208
  }, readonly []>;
209
209
  devnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
210
- mode: "local" | "live" | "fork" | "local-rpc";
210
+ mode: "local" | "local-rpc" | "live" | "fork";
211
211
  fundingFaucetStrategy: FaucetStrategy | null;
212
212
  sdk: SuiSdkShim;
213
213
  rpcUrl: string;
@@ -11,7 +11,6 @@ import { chainProbeCapabilityKey } from "../../contracts/chain-probe.mjs";
11
11
  import "./move/index.mjs";
12
12
  import { makeSuiForkRoutables, makeSuiLocalRoutables } from "./routable.mjs";
13
13
  import { sanitizeAlias } from "../../substrate/runtime/managed-container.mjs";
14
- import { resolveNetworkOptions } from "../../orchestrators/network-options.mjs";
15
14
  import { defineModeNamespace } from "../../api/mode-narrowed-factory.mjs";
16
15
  import { credentialedUrl, withDatabase } from "../internal/postgres-sidecar/connection.mjs";
17
16
  import { bootPostgresSidecar } from "../internal/postgres-sidecar/service.mjs";
@@ -208,7 +207,7 @@ const bootAndEmit = (opts, indexer, prebuiltImage) => Effect.gen(function* () {
208
207
  fundingFaucetStrategy
209
208
  };
210
209
  const realChainId = value.chainId;
211
- const faucetContribution = !resolveNetworkOptions(identity.network).faucet || value.fundingFaucetStrategy === null ? [] : [{
210
+ const faucetContribution = !(identity.network !== "mainnet") || value.fundingFaucetStrategy === null ? [] : [{
212
211
  kind: "strategy-contributor",
213
212
  capabilityKey: faucetCapabilityKey(realChainId),
214
213
  strategy: value.fundingFaucetStrategy,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/sui/index.ts"],"sourcesContent":["// Sui plugin — barrel + factories.\n//\n// Architecture: Sui is the most-depended-on plugin in the stack.\n// Every consumer (Account/Coin/Wallet/Faucet/Package; Walrus/Seal/\n// Deepbook fork variants) reads its resolved `SuiClient` via the\n// `suiResource`. The factory at this file folds the four modes behind:\n//\n// - `sui(opts?)` — local shorthand. Defaults to an in-stack\n// local validator; pass a typed `opts`\n// record to select a different mode.\n// - `suiFor(network)` — mode-narrowed factory namespace (per\n// architecture Tension 11). Returns\n// `{ local: …, live: …, fork: … }`\n// narrowed to the network's mode.\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.provides` — `chain-probe:<chainId>` strategy contributor,\n// the schema-validated read surface (`makeSuiChainProbe`).\n// 2. `ctx.snapshotExtra` — mode-aware container + bind-mount capture.\n// 3. `ctx.codegen` — `sui-network` bindings (chain id, rpc, etc.).\n// 4. `ctx.provides` — faucet strategy contributor, local-coin\n// dispensing for the mode's chain id.\n//\n// `ctx.endpoint` contributions are MODE-DEPENDENT (local + fork yes;\n// local-rpc + live no — the caller fronts their own RPC). They land\n// in the per-mode builder under `mode/*.ts`; this barrel emits them\n// alongside the rest during `start`.\n\nimport { Effect, type Scope } from 'effect';\n\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { definePlugin, resource, staticInputIdentity } from '../../api/define-plugin.ts';\nimport {\n\tbootPostgresSidecar,\n\tcredentialedUrl,\n\twithDatabase,\n} from '../internal/postgres-sidecar/index.ts';\nimport type { ChainProbe } from '../../contracts/chain-probe.ts';\nimport type { StrategyContributorDecl } from '../../contracts/strategy-contributor.ts';\nimport { emitContributions, PluginContext } from '../../substrate/plugin-ctx.ts';\n\nimport { chainProbeCapabilityKey } from '../../contracts/chain-probe.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport type {\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport type { Identity } from '../../substrate/identity.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { sanitizeAlias } from '../../substrate/runtime/managed-container.ts';\nimport {\n\tLeaseBrokerService,\n\ttype LeaseBroker,\n} from '../../substrate/runtime/lease-broker/index.ts';\nimport { PortBrokerService } from '../../substrate/runtime/port-broker/index.ts';\nimport { makeCodegenable, makeStaticCodegen } from './codegen.ts';\nimport type { SuiProbeKey } from './chain-probe.ts';\nimport { makeSnapshotable } from './snapshot.ts';\nimport { bootSuiService } from './service.ts';\nimport { suiPluginError, type SuiPluginError } from './errors.ts';\nimport { makeSuiForkRoutables, makeSuiLocalRoutables } from './routable.ts';\nimport { faucetCapabilityKey, type FaucetStrategy } from '../faucet/index.ts';\nimport { resolveNetworkOptions } from '../../orchestrators/network-options.ts';\nimport { suiLocalStrategy } from './local-faucet-strategy.ts';\nimport { suiForkFaucetStrategy } from './fork-faucet-strategy.ts';\nimport { selectSufficientForkCoin } from './fork-transaction.ts';\nimport { FORK_FAUCET_WHALE_MIN_COIN_MIST, resolveForkWhale } from './mode/fork.ts';\nimport { resolveImage, SUI_INDEXER_DB_ROLE, type LocalIndexer } from './mode/local.ts';\nimport type { SuiClient } from './mode/shared.ts';\nimport type {\n\tSuiForkOptions,\n\tSuiLiveOptions,\n\tSuiLocalRpcOptions,\n\tSuiLocalOptions,\n\tSuiOptions,\n} from './mode/spec.ts';\n\n// ---------------------------------------------------------------------------\n// Resource identity\n// ---------------------------------------------------------------------------\n\ntype SuiResolved = SuiClient & {\n\treadonly mode: SuiOptions['mode'];\n};\n\n/** Internal extension of `SuiResolved` carrying the pre-built funding\n * faucet strategy. `start` owns the `LeaseBrokerService` instance for\n * serialization; building the strategy at start-time (where the broker\n * is reachable) lets the capabilities factory consume a flat value\n * without threading the broker through a side channel. Local/live wrap\n * the HTTP faucet; fork impersonates a whale; `null` on networks with\n * no faucet (live-mainnet, external-rpc-without-faucet, faucet-disabled\n * fork). */\ntype SuiResolvedRuntime = SuiResolved & {\n\treadonly fundingFaucetStrategy: FaucetStrategy | null;\n};\n\n/** The Sui plugin's resource identity. The id is `'sui'` (singular). */\nexport const suiResource = resource<'sui', SuiResolved>('sui');\n\n// ---------------------------------------------------------------------------\n// Plugin construction (internal — used by sui() + suiFor())\n// ---------------------------------------------------------------------------\n\n/** Build the funds-ready faucet strategy for the resolved network, or\n * `null` when the network has none. Local/live wrap the HTTP faucet;\n * fork mode impersonates a whale (resolved + validated here). */\nconst resolveFundingFaucetStrategy = (\n\topts: SuiOptions,\n\tclient: SuiClient,\n\tbroker: LeaseBroker,\n): Effect.Effect<FaucetStrategy | null, SuiPluginError> => {\n\tif (opts.mode === 'fork') {\n\t\treturn resolveForkFaucetStrategy(opts, client, broker);\n\t}\n\tif (client.fundingFaucetUrl === null) {\n\t\treturn Effect.succeed(null);\n\t}\n\treturn Effect.succeed(\n\t\tsuiLocalStrategy({\n\t\t\tfaucetUrl: client.fundingFaucetUrl,\n\t\t\tserialization: {\n\t\t\t\tbroker,\n\t\t\t\tkey: `sui-faucet:${client.chainId}`,\n\t\t\t\towner: `sui-faucet:${client.chainId}`,\n\t\t\t},\n\t\t}),\n\t);\n};\n\n/** Fork-mode faucet: resolve the whale, validate it holds a large enough\n * SUI coin, then build the impersonation strategy. A whale the user set\n * explicitly that fails validation hard-fails the boot; a per-upstream\n * default whale only warns and disables the faucet so the fork still\n * comes up (account funding then surfaces the \"no faucet strategy\"\n * error only if something actually needs SUI). */\nconst resolveForkFaucetStrategy = (\n\topts: SuiForkOptions,\n\tclient: SuiClient,\n\tbroker: LeaseBroker,\n): Effect.Effect<FaucetStrategy | null, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tconst resolved = resolveForkWhale(opts);\n\t\tconst fork = client.fork;\n\t\tif (resolved === null || fork === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst strategy = suiForkFaucetStrategy({\n\t\t\twhale: resolved.whale,\n\t\t\tfork,\n\t\t\tsdk: client.sdk,\n\t\t\tperRequestCapMist: resolved.perRequestCapMist,\n\t\t\tserialization: {\n\t\t\t\tbroker,\n\t\t\t\tkey: `sui-fork-faucet:${client.chainId}`,\n\t\t\t\towner: `sui-fork-faucet:${client.chainId}`,\n\t\t\t},\n\t\t});\n\t\treturn yield* selectSufficientForkCoin(\n\t\t\tclient.sdk.core,\n\t\t\tresolved.whale,\n\t\t\tFORK_FAUCET_WHALE_MIN_COIN_MIST,\n\t\t).pipe(\n\t\t\tEffect.as(strategy),\n\t\t\tEffect.catchTag('SuiPluginError', (cause) =>\n\t\t\t\tresolved.explicit\n\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t: Effect.logWarning(\n\t\t\t\t\t\t\t`sui fork mode: default faucet whale ${resolved.whale} is unusable ` +\n\t\t\t\t\t\t\t\t`(${cause.message}); disabling the fork faucet. Set faucet.whale to override.`,\n\t\t\t\t\t\t).pipe(Effect.as(null)),\n\t\t\t),\n\t\t);\n\t});\n\n/** Default name for sui's GraphQL-indexer database. */\nconst DEFAULT_INDEXER_DATABASE = 'sui_indexer';\n\n/** In-network DNS alias siblings dial the indexer-db sidecar by. */\nconst SUI_INDEXER_DB_ALIAS = 'sui-indexer-db';\n\nconst suiInputIdentity = (opts: SuiOptions): unknown => {\n\tconst { readyTimeout: _readyTimeout, ...authored } = opts;\n\tif (authored.mode !== 'local') return { plugin: 'sui', ...authored };\n\treturn {\n\t\tplugin: 'sui',\n\t\t...authored,\n\t\tindexer: authored.indexer !== false,\n\t\tindexerDb:\n\t\t\tauthored.indexerDb === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\t...authored.indexerDb,\n\t\t\t\t\t\tdatabase: authored.indexerDb.database ?? DEFAULT_INDEXER_DATABASE,\n\t\t\t\t\t},\n\t};\n};\n\n/** Compose the indexer-db sidecar's stable `configHash` from validator\n * inputs known before local mode starts. A validator image change recreates\n * the validator, so the sidecar's mount-less PGDATA must reset with it.\n *\n * Validator data-layer resets that are not config values (absent validator\n * or last exit `137`) are handled by `validatorNeedsIndexerReset`, which\n * removes the sidecar before this hash is applied. */\nexport const composeIndexerConfigHash = (imageRef: string): string =>\n\t['indexer-db', `validator-img=${imageRef}`].join('|');\n\n/** Append a database segment to a BYO DSN only when it has no path (so a\n * caller-supplied `.../mydb` is respected). Rebuilds via the URL object\n * so the db slots into `pathname` BEFORE `?search` — a naive string\n * append on a `host:5432?sslmode=require` DSN (path-less but with a\n * query) would wrongly yield `...?sslmode=require/sui_indexer`. The\n * catch fallback (non-URL-parseable DSN) splits the query off first. */\nconst appendDatabaseIfMissing = (url: string, database: string): string => {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tconst hasPath = parsed.pathname !== '' && parsed.pathname !== '/';\n\t\tif (hasPath) return url;\n\t\tparsed.pathname = `/${database}`;\n\t\treturn parsed.toString();\n\t} catch {\n\t\tconst queryAt = url.indexOf('?');\n\t\tconst base = queryAt === -1 ? url : url.slice(0, queryAt);\n\t\tconst query = queryAt === -1 ? '' : url.slice(queryAt);\n\t\tconst afterScheme = base.replace(/^postgres(ql)?:\\/\\//, '');\n\t\tif (/\\/[^/]+$/.test(afterScheme)) return url;\n\t\treturn `${base.replace(/\\/$/, '')}/${encodeURIComponent(database)}${query}`;\n\t}\n};\n\n/** Whether the Sui-owned indexer DB must be deleted before boot.\n *\n * The validator's chain identity lives in its writable layer. If the\n * validator container is absent, the next boot creates a new layer and a\n * new chain. If it last exited `137`, the runtime's `on-failure` policy\n * also recreates it. Both cases make any existing indexer DB stale. */\nexport const validatorNeedsIndexerReset = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n): Effect.Effect<boolean, ContainerRuntimeError> =>\n\truntime\n\t\t.inspectByLabels({\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t})\n\t\t.pipe(\n\t\t\tEffect.map((handles) => {\n\t\t\t\tconst validator = handles[0];\n\t\t\t\treturn validator === undefined || validator.lastExitCode === 137;\n\t\t\t}),\n\t\t);\n\n/** Provision the GraphQL-indexer DB wiring for local mode.\n *\n * Default: sui OWNS a postgres sidecar (labelled under sui) — boot it on\n * a per-stack network and compose the DSN from its in-network alias (NOT\n * the per-stack container DNS host, which isn't parallel-stack-portable).\n * The sidecar resets on the same validator inputs that can make its rows\n * stale: absent/exited-`137` validator state removes the sidecar before\n * boot, and validator image identity is folded into its `configHash`.\n *\n * `validatorImage` is the SAME `ImageRef` the barrel hands `bootLocalMode`\n * for the validator container, so the image the sidecar hashed and the image\n * the validator runs cannot drift.\n *\n * BYO: when `indexerDb` is set, no sidecar — pass the caller's DSN +\n * network straight through (appending the default db iff the DSN has no\n * path). The caller owns that DB's lifecycle. */\nexport const provisionLocalIndexer = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\topts: SuiLocalOptions,\n\tvalidatorImage: ImageRef,\n): Effect.Effect<LocalIndexer, SuiPluginError, Scope.Scope> => {\n\tconst database = opts.indexerDb?.database ?? DEFAULT_INDEXER_DATABASE;\n\tif (opts.indexerDb !== undefined) {\n\t\treturn Effect.succeed({\n\t\t\turl: appendDatabaseIfMissing(opts.indexerDb.url, database),\n\t\t\tnetwork: opts.indexerDb.network,\n\t\t});\n\t}\n\tconst network = sanitizeAlias(`devstack-${identity.app}-${identity.stack}-sui-indexer`);\n\treturn Effect.gen(function* () {\n\t\tconst resetExistingSidecar = yield* validatorNeedsIndexerReset(runtime, identity);\n\t\tif (resetExistingSidecar) {\n\t\t\tyield* runtime.removeManagedContainers({\n\t\t\t\tapp: identity.app,\n\t\t\t\tstack: identity.stack,\n\t\t\t\tplugin: 'sui',\n\t\t\t\trole: SUI_INDEXER_DB_ROLE,\n\t\t\t});\n\t\t}\n\t\tconst imageRef = validatorImage.tag ?? validatorImage.digest;\n\t\tconst { handle } = yield* bootPostgresSidecar(runtime, identity, {\n\t\t\tnetwork,\n\t\t\talias: SUI_INDEXER_DB_ALIAS,\n\t\t\trole: SUI_INDEXER_DB_ROLE,\n\t\t\tdatabase,\n\t\t\tconfigHash: composeIndexerConfigHash(imageRef),\n\t\t});\n\t\treturn {\n\t\t\turl: withDatabase(\n\t\t\t\tcredentialedUrl({\n\t\t\t\t\tuser: handle.user,\n\t\t\t\t\tpassword: handle.password,\n\t\t\t\t\thost: handle.networkAlias,\n\t\t\t\t\tport: handle.port,\n\t\t\t\t}),\n\t\t\t\tdatabase,\n\t\t\t),\n\t\t\tnetwork: handle.containerNetwork,\n\t\t} satisfies LocalIndexer;\n\t}).pipe(\n\t\t// Postgres / runtime-domain failures wrap into the sui error channel\n\t\t// — the sidecar is a sui implementation detail. Nothing in the gen\n\t\t// body produces a `SuiPluginError` directly, so we wrap every cause.\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to provision the GraphQL indexer postgres sidecar (${cause._tag})`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n};\n\n/** Shared boot + inline contribution emission, parameterised by the\n * resolved external-indexer wiring (`undefined` = no GraphQL, the\n * zero-config / non-local case) and, for local mode, the validator image\n * the barrel pre-resolved (so the sidecar's `configHash` and the validator\n * container share one `ImageRef`; `undefined` on the no-sidecar paths,\n * where `bootLocalMode` resolves it inline). */\nconst bootAndEmit = (\n\topts: SuiOptions,\n\tindexer: LocalIndexer | undefined,\n\tprebuiltImage?: ImageRef,\n) =>\n\tEffect.gen(function* () {\n\t\tconst ctx = yield* PluginContext;\n\t\t// The substrate threads `ContainerRuntime` + `IdentityContext`\n\t\t// via the plugin runtime context; the supervisor provides\n\t\t// these before this body runs.\n\t\tconst runtime = yield* ContainerRuntimeService;\n\t\tconst identity = yield* IdentityContext;\n\t\tconst paths = yield* StackPathsService;\n\t\tconst portBroker = yield* PortBrokerService;\n\t\tconst fundingFaucetLeaseBroker = yield* LeaseBrokerService;\n\t\tconst { client } = yield* bootSuiService(\n\t\t\truntime,\n\t\t\tidentity,\n\t\t\tportBroker,\n\t\t\tpaths,\n\t\t\topts,\n\t\t\tindexer,\n\t\t\tprebuiltImage,\n\t\t);\n\n\t\tconst fundingFaucetStrategy = yield* resolveFundingFaucetStrategy(\n\t\t\topts,\n\t\t\tclient,\n\t\t\tfundingFaucetLeaseBroker,\n\t\t);\n\t\tconst value = {\n\t\t\t...client,\n\t\t\tmode: opts.mode,\n\t\t\tfundingFaucetStrategy,\n\t\t} satisfies SuiResolvedRuntime;\n\t\t// Emit the resolved contributions inline, top-to-bottom: the\n\t\t// decls stamp REAL chain ids / rpc URLs / container names\n\t\t// (the genesis-digest chain id, not the network name).\n\t\t// (`value` is the just-resolved runtime; `identity` from\n\t\t// `IdentityContext`, NOT re-fetched). The shared\n\t\t// `emitContributions` routes each by `kind`. Faucet (conditional\n\t\t// on a resolved strategy) and routables (mode-dependent) are the\n\t\t// only optional members; order is load-bearing.\n\t\tconst realChainId = value.chainId;\n\t\t// Per-network faucet gate (per-network options: ON for every network\n\t\t// EXCEPT live `mainnet`, where the funding faucet must NEVER run).\n\t\t// `identity.network` is the resolved network name. The gate honours\n\t\t// ONLY the POLICY DEFAULT, NOT any author per-network override: the\n\t\t// override RECORD (`networkOptions`) is an orchestrator-level concern\n\t\t// that the name-blind substrate does not forward into plugins, and\n\t\t// this plugin only receives `IdentityContext`. So a per-network\n\t\t// `{ <network>: { faucet: false } }` override is deliberately NOT\n\t\t// applied here (unlike `devWallet`/`autoApproveSigning`, which the\n\t\t// orchestrator resolves against the forwarded `networkOptions`); see\n\t\t// `orchestrators/network-options.ts`. The policy default already\n\t\t// carries the load-bearing mainnet hard-clamp, so a resolved strategy\n\t\t// on `mainnet` (none of the live modes build one today, but a future\n\t\t// faucet-bearing mainnet config could) is suppressed and the strategy\n\t\t// registry never exposes `faucet:request:<mainnet-chain-id>`; account\n\t\t// funding then surfaces the actionable \"no faucet strategy\" error\n\t\t// rather than silently faucet-funding against a production network.\n\t\tconst faucetEnabled = resolveNetworkOptions(identity.network).faucet;\n\t\tconst faucetContribution: ReadonlyArray<StrategyContributorDecl> =\n\t\t\t!faucetEnabled || value.fundingFaucetStrategy === null\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: 'strategy-contributor',\n\t\t\t\t\t\t\tcapabilityKey: faucetCapabilityKey(realChainId),\n\t\t\t\t\t\t\tstrategy: value.fundingFaucetStrategy,\n\t\t\t\t\t\t\tautoMounted: true,\n\t\t\t\t\t\t} satisfies StrategyContributorDecl<\n\t\t\t\t\t\t\t`faucet:request:${string}`,\n\t\t\t\t\t\t\tReturnType<typeof suiLocalStrategy>\n\t\t\t\t\t\t>,\n\t\t\t\t\t];\n\t\tconst localRoutables =\n\t\t\topts.mode === 'local'\n\t\t\t\t? makeSuiLocalRoutables({\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-sui-validator`,\n\t\t\t\t\t\t// GraphQL routes only when the external indexer is wired.\n\t\t\t\t\t\tincludeGraphql: indexer !== undefined,\n\t\t\t\t\t})\n\t\t\t\t: [];\n\t\tconst forkRoutables =\n\t\t\topts.mode === 'fork'\n\t\t\t\t? makeSuiForkRoutables({\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-sui-fork`,\n\t\t\t\t\t})\n\t\t\t\t: [];\n\t\temitContributions(ctx, [\n\t\t\t// `hasIndexer` (local only) folds the sui-owned indexer-db\n\t\t\t// sidecar into the captured containers; `indexer !== undefined`\n\t\t\t// is the same gate `bootAndEmit`'s caller resolved GraphQL on.\n\t\t\tmakeSnapshotable(opts.mode, identity.app, identity.stack, realChainId, indexer !== undefined),\n\t\t\tmakeCodegenable({\n\t\t\t\tmode: opts.mode,\n\t\t\t\tchainId: realChainId,\n\t\t\t\trpc: value.rpcUrl,\n\t\t\t\tsource: 'default',\n\t\t\t\t...(value.faucetUrl !== null ? { faucet: value.faucetUrl } : {}),\n\t\t\t\t...(value.graphqlUrl !== null ? { graphql: value.graphqlUrl } : {}),\n\t\t\t}),\n\t\t\t{\n\t\t\t\tkind: 'strategy-contributor',\n\t\t\t\tcapabilityKey: chainProbeCapabilityKey(realChainId),\n\t\t\t\tstrategy: value.chainProbe,\n\t\t\t\tautoMounted: true,\n\t\t\t} satisfies StrategyContributorDecl<`chain-probe:${string}`, ChainProbe<SuiProbeKey>>,\n\t\t\t...faucetContribution,\n\t\t\t...localRoutables,\n\t\t\t...forkRoutables,\n\t\t]);\n\t\treturn value;\n\t});\n\n/** The single sui plugin builder. No sibling `dependsOn`: in local mode\n * with the indexer on (the default), `start` provisions the GraphQL\n * indexer DB itself — a sui-owned postgres sidecar — inside the boot\n * scope BEFORE the boot-time validator (so the validator can join its\n * network), then boots + emits. Resolution order:\n * - `indexerDb` present → BYO DB (no sidecar)\n * - `indexer === false` → opt out (RPC + faucet only, GraphQL off)\n * - else (local default) → sui-owned sidecar\n * Non-local modes never touch the indexer (GraphQL off). */\nconst buildSuiPlugin = (opts: SuiOptions) =>\n\tdefinePlugin({\n\t\tid: suiResource.id,\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tinputIdentity: staticInputIdentity(suiInputIdentity(opts)),\n\t\t// Stack-free codegen: the `codegen` verb derives the committed\n\t\t// `config.ts`'s `network`/`networks` from this hook. Both are\n\t\t// environment/live data (dynamic local rpc port; a real deployment\n\t\t// names a different network), so the committed tree carries\n\t\t// `resolveNetwork()`/`resolveNetworks()` raw expressions that resolve\n\t\t// at app build/dev time via the injected `__DEVSTACK_IDS__` global —\n\t\t// never literal values. No id-resolver input needed.\n\t\tstaticCodegen: makeStaticCodegen(),\n\t\t// Zero-arg `start` (no `dependsOn`); the substrate supplies the\n\t\t// container runtime + identity via the plugin runtime context.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Resolution order: BYO `indexerDb` wins; then an explicit\n\t\t\t\t// `indexer: false` opt-out; then the sui-owned sidecar default.\n\t\t\t\t// Non-local modes never wire the indexer.\n\t\t\t\tif (opts.mode !== 'local' || (opts.indexerDb === undefined && opts.indexer === false)) {\n\t\t\t\t\treturn yield* bootAndEmit(opts, undefined);\n\t\t\t\t}\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\t// Resolve the validator image ONCE, before the sidecar — single\n\t\t\t\t// source for both the sidecar's configHash (it folds the resolved\n\t\t\t\t// image ref so an image bump resets the indexer DB) and the\n\t\t\t\t// validator container `bootAndEmit` boots below. `resolveImage`\n\t\t\t\t// is deterministic (content-addressed build/pull) so this is the\n\t\t\t\t// SAME ref the validator runs; resolving it here, not twice,\n\t\t\t\t// avoids a redundant build AND any drift from `decideRunAction`.\n\t\t\t\tconst validatorImage = yield* resolveImage(runtime, identity, opts);\n\t\t\t\t// The sidecar boots first; if the validator boot below fails, the\n\t\t\t\t// sidecar's finalizer lingers on the plugin acquire scope until\n\t\t\t\t// teardown/retry. Benign and intentional — the stable name +\n\t\t\t\t// labels mean a retry ADOPTS the existing sidecar container\n\t\t\t\t// (no scope-threading machinery needed).\n\t\t\t\tconst indexer = yield* provisionLocalIndexer(runtime, identity, opts, validatorImage);\n\t\t\t\treturn yield* bootAndEmit(opts, indexer, validatorImage);\n\t\t\t}),\n\t});\n\nconst buildPlugin = <O extends SuiOptions>(opts: O) => buildSuiPlugin(opts);\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Local Sui shorthand. Network/env selection belongs to the CLI or\n * `defineDevstackWith(...)`; plain `sui()` always means an in-stack\n * local validator (GraphQL/indexer/Postgres on by default via a\n * sui-owned sidecar). */\nexport const sui = <const O extends SuiOptions = { mode: 'local' }>(\n\topts: O = { mode: 'local' } as O,\n) => buildPlugin(opts);\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const network = { mode: 'local' } as const;\n * suiFor(network).local({...}) // OK\n * suiFor(network).fork({...}) // type error: 'fork' not in 'local' branch\n *\n * The namespace MIRRORS the four mode option records: `local`,\n * `localRpc` (mapped onto the substrate `'local'` branch),\n * `live`, `fork`. */\nexport const suiFor = defineModeNamespace({\n\tlocal: {\n\t\tlocal: <const O extends Omit<SuiLocalOptions, 'mode'>>(opts: O = {} as O) =>\n\t\t\tbuildPlugin({ mode: 'local', ...opts }),\n\t\tlocalRpc: (opts: Omit<SuiLocalRpcOptions, 'mode'>) =>\n\t\t\tbuildPlugin({ mode: 'local-rpc', ...opts }),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'mainnet', ...opts }),\n\t\tdevnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'devnet', ...opts }),\n\t\tcustom: (opts: Omit<SuiLiveOptions, 'mode' | 'network'>) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'custom', ...opts }),\n\t},\n\tfork: {\n\t\tmainnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'mainnet', ...opts }),\n\t\ttestnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'testnet', ...opts }),\n\t\tdevnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'devnet', ...opts }),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Re-exports for advanced callers (Account/Coin/Wallet/etc.) and for\n// the sibling plugins (Walrus/Seal/Deepbook fork variants).\n// ---------------------------------------------------------------------------\n\nexport type { SuiClient, ForkAdminSurface, WaitForTransactionsReady } from './mode/shared.ts';\nexport type { ResolvedSuiNetwork } from './network-resolver.ts';\nexport type {\n\tNetworkConfig,\n\tNetworkMode,\n\tDevstackNetworkModeRegistry,\n\tDefaultNetwork,\n} from './network-config.ts';\nexport type {\n\tSuiOptions,\n\tSuiLocalOptions,\n\tSuiLocalRpcOptions,\n\tSuiLiveOptions,\n\tSuiForkOptions,\n\tSuiPluginMode,\n} from './mode/spec.ts';\nexport type { SuiNetworkConfigEntry } from './codegen.ts';\nexport type {\n\tSuiError,\n\tSuiPluginError,\n\tSuiCliError,\n\tSuiConfigError,\n\tForkUnsupportedError,\n} from './errors.ts';\n\n// Cross-plugin seams (consumed by Walrus/Seal/Deepbook fork variants\n// and by Account/Coin/Wallet/Package).\nexport {\n\tchainProbeCapabilityKey,\n\ttype ChainProbe,\n\ttype ChainProbeError,\n\ttype ChainProbeMode,\n} from '../../contracts/chain-probe.ts';\nexport {\n\tFORK_UNSUPPORTED_SURFACES,\n\twrapWithForkGuard,\n\ttype ForkLockHolder,\n} from './fork-orchestration.ts';\nexport type { SuiProbeKey, SuiSdkShim } from './chain-probe.ts';\nexport { SuiLogAttr } from './log-attrs.ts';\n\n/** The shape `Transaction.build({ client })` and every `sdk.core.*` call\n * accepts. Re-exported from `@mysten/sui/client` so callers cast\n * `sui.sdk.client as ClientWithCoreApi` without each having to know the\n * SDK subpath. */\nexport type { ClientWithCoreApi } from '@mysten/sui/client';\n// Cross-plugin seams: fork impersonation + chain-build container.\n// Consumed by `action` (Move-call execution against fork) and\n// `package` (publish-to-fork + Move-build orchestration). Consumer\n// plugins import these barrel entries rather than internal modules.\nexport {\n\tbuildForkImpersonationTransactionBytes,\n\tprepareForkImpersonationTransaction,\n\tverifyForkImpersonationSender,\n\tselectSufficientForkCoin,\n\tFORK_IMPERSONATION_GAS_BUDGET,\n\tFORK_IMPERSONATION_GAS_PRICE,\n\ttype ForkGasCoin,\n\ttype ForkImpersonationGasClient,\n} from './fork-transaction.ts';\nexport {\n\tsuiForkFaucetStrategy,\n\ttype SuiForkFaucetStrategyOptions,\n\ttype SuiForkFaucetSerialization,\n} from './fork-faucet-strategy.ts';\nexport {\n\tacquireChainBuildContainer,\n\tcontainerNameForApp,\n\tmoveBuildLockPathFor,\n\tMOVE_BUILD_LOCK_TIMEOUT_MS,\n\ttype ChainBuildContainer,\n\ttype ChainBuildContainerSpec,\n} from './chain-build-container.ts';\n\n// Cross-plugin seams: hoisted exec / move / ledger helpers.\n// Consumed by Account/Action/Coin/Deepbook/Package/Seal/Walrus. These\n// barrel entries route those consumers through the sibling plugin's\n// barrel per the `plugin-boundary` invariant, rather than reaching into\n// the deep `sui/exec`, `sui/move`, and `sui/ledger` internal modules.\nexport {\n\textractExecuteDigest,\n\tformatExecutedFailure,\n\texecuteSuiTx,\n\tisSuiStaleObjectVersionError,\n\ttype ResolvedSigner,\n\ttype ExecutedFailure,\n\ttype ExecutedReceipt,\n\ttype TransactionSignerScope,\n} from './exec/index.ts';\nexport { signAndDispatch } from './exec/sign-and-dispatch.ts';\nexport {\n\thashMoveSources,\n\trunMoveBuild,\n\tscrubLocksHost,\n\twithMoveBuildLock,\n\ttype BuildOutput,\n\ttype MoveBuildContainer,\n\ttype MoveBuildError,\n} from './move/index.ts';\nexport { currentLedgerObjectRef } from './ledger/object-ref.ts';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/sui/index.ts"],"sourcesContent":["// Sui plugin — barrel + factories.\n//\n// Architecture: Sui is the most-depended-on plugin in the stack.\n// Every consumer (Account/Coin/Wallet/Faucet/Package; Walrus/Seal/\n// Deepbook fork variants) reads its resolved `SuiClient` via the\n// `suiResource`. The factory at this file folds the four modes behind:\n//\n// - `sui(opts?)` — local shorthand. Defaults to an in-stack\n// local validator; pass a typed `opts`\n// record to select a different mode.\n// - `suiFor(network)` — mode-narrowed factory namespace (per\n// architecture Tension 11). Returns\n// `{ local: …, live: …, fork: … }`\n// narrowed to the network's mode.\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.provides` — `chain-probe:<chainId>` strategy contributor,\n// the schema-validated read surface (`makeSuiChainProbe`).\n// 2. `ctx.snapshotExtra` — mode-aware container + bind-mount capture.\n// 3. `ctx.codegen` — `sui-network` bindings (chain id, rpc, etc.).\n// 4. `ctx.provides` — faucet strategy contributor, local-coin\n// dispensing for the mode's chain id.\n//\n// `ctx.endpoint` contributions are MODE-DEPENDENT (local + fork yes;\n// local-rpc + live no — the caller fronts their own RPC). They land\n// in the per-mode builder under `mode/*.ts`; this barrel emits them\n// alongside the rest during `start`.\n\nimport { Effect, type Scope } from 'effect';\n\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { definePlugin, resource, staticInputIdentity } from '../../api/define-plugin.ts';\nimport {\n\tbootPostgresSidecar,\n\tcredentialedUrl,\n\twithDatabase,\n} from '../internal/postgres-sidecar/index.ts';\nimport type { ChainProbe } from '../../contracts/chain-probe.ts';\nimport type { StrategyContributorDecl } from '../../contracts/strategy-contributor.ts';\nimport { emitContributions, PluginContext } from '../../substrate/plugin-ctx.ts';\n\nimport { chainProbeCapabilityKey } from '../../contracts/chain-probe.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport type {\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport type { Identity } from '../../substrate/identity.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { sanitizeAlias } from '../../substrate/runtime/managed-container.ts';\nimport {\n\tLeaseBrokerService,\n\ttype LeaseBroker,\n} from '../../substrate/runtime/lease-broker/index.ts';\nimport { PortBrokerService } from '../../substrate/runtime/port-broker/index.ts';\nimport { makeCodegenable, makeStaticCodegen } from './codegen.ts';\nimport type { SuiProbeKey } from './chain-probe.ts';\nimport { makeSnapshotable } from './snapshot.ts';\nimport { bootSuiService } from './service.ts';\nimport { suiPluginError, type SuiPluginError } from './errors.ts';\nimport { makeSuiForkRoutables, makeSuiLocalRoutables } from './routable.ts';\nimport { faucetCapabilityKey, type FaucetStrategy } from '../faucet/index.ts';\nimport { suiLocalStrategy } from './local-faucet-strategy.ts';\nimport { suiForkFaucetStrategy } from './fork-faucet-strategy.ts';\nimport { selectSufficientForkCoin } from './fork-transaction.ts';\nimport { FORK_FAUCET_WHALE_MIN_COIN_MIST, resolveForkWhale } from './mode/fork.ts';\nimport { resolveImage, SUI_INDEXER_DB_ROLE, type LocalIndexer } from './mode/local.ts';\nimport type { SuiClient } from './mode/shared.ts';\nimport type {\n\tSuiForkOptions,\n\tSuiLiveOptions,\n\tSuiLocalRpcOptions,\n\tSuiLocalOptions,\n\tSuiOptions,\n} from './mode/spec.ts';\n\n// ---------------------------------------------------------------------------\n// Resource identity\n// ---------------------------------------------------------------------------\n\ntype SuiResolved = SuiClient & {\n\treadonly mode: SuiOptions['mode'];\n};\n\n/** Internal extension of `SuiResolved` carrying the pre-built funding\n * faucet strategy. `start` owns the `LeaseBrokerService` instance for\n * serialization; building the strategy at start-time (where the broker\n * is reachable) lets the capabilities factory consume a flat value\n * without threading the broker through a side channel. Local/live wrap\n * the HTTP faucet; fork impersonates a whale; `null` on networks with\n * no faucet (live-mainnet, external-rpc-without-faucet, faucet-disabled\n * fork). */\ntype SuiResolvedRuntime = SuiResolved & {\n\treadonly fundingFaucetStrategy: FaucetStrategy | null;\n};\n\n/** The Sui plugin's resource identity. The id is `'sui'` (singular). */\nexport const suiResource = resource<'sui', SuiResolved>('sui');\n\n// ---------------------------------------------------------------------------\n// Plugin construction (internal — used by sui() + suiFor())\n// ---------------------------------------------------------------------------\n\n/** Build the funds-ready faucet strategy for the resolved network, or\n * `null` when the network has none. Local/live wrap the HTTP faucet;\n * fork mode impersonates a whale (resolved + validated here). */\nconst resolveFundingFaucetStrategy = (\n\topts: SuiOptions,\n\tclient: SuiClient,\n\tbroker: LeaseBroker,\n): Effect.Effect<FaucetStrategy | null, SuiPluginError> => {\n\tif (opts.mode === 'fork') {\n\t\treturn resolveForkFaucetStrategy(opts, client, broker);\n\t}\n\tif (client.fundingFaucetUrl === null) {\n\t\treturn Effect.succeed(null);\n\t}\n\treturn Effect.succeed(\n\t\tsuiLocalStrategy({\n\t\t\tfaucetUrl: client.fundingFaucetUrl,\n\t\t\tserialization: {\n\t\t\t\tbroker,\n\t\t\t\tkey: `sui-faucet:${client.chainId}`,\n\t\t\t\towner: `sui-faucet:${client.chainId}`,\n\t\t\t},\n\t\t}),\n\t);\n};\n\n/** Fork-mode faucet: resolve the whale, validate it holds a large enough\n * SUI coin, then build the impersonation strategy. A whale the user set\n * explicitly that fails validation hard-fails the boot; a per-upstream\n * default whale only warns and disables the faucet so the fork still\n * comes up (account funding then surfaces the \"no faucet strategy\"\n * error only if something actually needs SUI). */\nconst resolveForkFaucetStrategy = (\n\topts: SuiForkOptions,\n\tclient: SuiClient,\n\tbroker: LeaseBroker,\n): Effect.Effect<FaucetStrategy | null, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tconst resolved = resolveForkWhale(opts);\n\t\tconst fork = client.fork;\n\t\tif (resolved === null || fork === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst strategy = suiForkFaucetStrategy({\n\t\t\twhale: resolved.whale,\n\t\t\tfork,\n\t\t\tsdk: client.sdk,\n\t\t\tperRequestCapMist: resolved.perRequestCapMist,\n\t\t\tserialization: {\n\t\t\t\tbroker,\n\t\t\t\tkey: `sui-fork-faucet:${client.chainId}`,\n\t\t\t\towner: `sui-fork-faucet:${client.chainId}`,\n\t\t\t},\n\t\t});\n\t\treturn yield* selectSufficientForkCoin(\n\t\t\tclient.sdk.core,\n\t\t\tresolved.whale,\n\t\t\tFORK_FAUCET_WHALE_MIN_COIN_MIST,\n\t\t).pipe(\n\t\t\tEffect.as(strategy),\n\t\t\tEffect.catchTag('SuiPluginError', (cause) =>\n\t\t\t\tresolved.explicit\n\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t: Effect.logWarning(\n\t\t\t\t\t\t\t`sui fork mode: default faucet whale ${resolved.whale} is unusable ` +\n\t\t\t\t\t\t\t\t`(${cause.message}); disabling the fork faucet. Set faucet.whale to override.`,\n\t\t\t\t\t\t).pipe(Effect.as(null)),\n\t\t\t),\n\t\t);\n\t});\n\n/** Default name for sui's GraphQL-indexer database. */\nconst DEFAULT_INDEXER_DATABASE = 'sui_indexer';\n\n/** In-network DNS alias siblings dial the indexer-db sidecar by. */\nconst SUI_INDEXER_DB_ALIAS = 'sui-indexer-db';\n\nconst suiInputIdentity = (opts: SuiOptions): unknown => {\n\tconst { readyTimeout: _readyTimeout, ...authored } = opts;\n\tif (authored.mode !== 'local') return { plugin: 'sui', ...authored };\n\treturn {\n\t\tplugin: 'sui',\n\t\t...authored,\n\t\tindexer: authored.indexer !== false,\n\t\tindexerDb:\n\t\t\tauthored.indexerDb === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\t...authored.indexerDb,\n\t\t\t\t\t\tdatabase: authored.indexerDb.database ?? DEFAULT_INDEXER_DATABASE,\n\t\t\t\t\t},\n\t};\n};\n\n/** Compose the indexer-db sidecar's stable `configHash` from validator\n * inputs known before local mode starts. A validator image change recreates\n * the validator, so the sidecar's mount-less PGDATA must reset with it.\n *\n * Validator data-layer resets that are not config values (absent validator\n * or last exit `137`) are handled by `validatorNeedsIndexerReset`, which\n * removes the sidecar before this hash is applied. */\nexport const composeIndexerConfigHash = (imageRef: string): string =>\n\t['indexer-db', `validator-img=${imageRef}`].join('|');\n\n/** Append a database segment to a BYO DSN only when it has no path (so a\n * caller-supplied `.../mydb` is respected). Rebuilds via the URL object\n * so the db slots into `pathname` BEFORE `?search` — a naive string\n * append on a `host:5432?sslmode=require` DSN (path-less but with a\n * query) would wrongly yield `...?sslmode=require/sui_indexer`. The\n * catch fallback (non-URL-parseable DSN) splits the query off first. */\nconst appendDatabaseIfMissing = (url: string, database: string): string => {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tconst hasPath = parsed.pathname !== '' && parsed.pathname !== '/';\n\t\tif (hasPath) return url;\n\t\tparsed.pathname = `/${database}`;\n\t\treturn parsed.toString();\n\t} catch {\n\t\tconst queryAt = url.indexOf('?');\n\t\tconst base = queryAt === -1 ? url : url.slice(0, queryAt);\n\t\tconst query = queryAt === -1 ? '' : url.slice(queryAt);\n\t\tconst afterScheme = base.replace(/^postgres(ql)?:\\/\\//, '');\n\t\tif (/\\/[^/]+$/.test(afterScheme)) return url;\n\t\treturn `${base.replace(/\\/$/, '')}/${encodeURIComponent(database)}${query}`;\n\t}\n};\n\n/** Whether the Sui-owned indexer DB must be deleted before boot.\n *\n * The validator's chain identity lives in its writable layer. If the\n * validator container is absent, the next boot creates a new layer and a\n * new chain. If it last exited `137`, the runtime's `on-failure` policy\n * also recreates it. Both cases make any existing indexer DB stale. */\nexport const validatorNeedsIndexerReset = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n): Effect.Effect<boolean, ContainerRuntimeError> =>\n\truntime\n\t\t.inspectByLabels({\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t})\n\t\t.pipe(\n\t\t\tEffect.map((handles) => {\n\t\t\t\tconst validator = handles[0];\n\t\t\t\treturn validator === undefined || validator.lastExitCode === 137;\n\t\t\t}),\n\t\t);\n\n/** Provision the GraphQL-indexer DB wiring for local mode.\n *\n * Default: sui OWNS a postgres sidecar (labelled under sui) — boot it on\n * a per-stack network and compose the DSN from its in-network alias (NOT\n * the per-stack container DNS host, which isn't parallel-stack-portable).\n * The sidecar resets on the same validator inputs that can make its rows\n * stale: absent/exited-`137` validator state removes the sidecar before\n * boot, and validator image identity is folded into its `configHash`.\n *\n * `validatorImage` is the SAME `ImageRef` the barrel hands `bootLocalMode`\n * for the validator container, so the image the sidecar hashed and the image\n * the validator runs cannot drift.\n *\n * BYO: when `indexerDb` is set, no sidecar — pass the caller's DSN +\n * network straight through (appending the default db iff the DSN has no\n * path). The caller owns that DB's lifecycle. */\nexport const provisionLocalIndexer = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\topts: SuiLocalOptions,\n\tvalidatorImage: ImageRef,\n): Effect.Effect<LocalIndexer, SuiPluginError, Scope.Scope> => {\n\tconst database = opts.indexerDb?.database ?? DEFAULT_INDEXER_DATABASE;\n\tif (opts.indexerDb !== undefined) {\n\t\treturn Effect.succeed({\n\t\t\turl: appendDatabaseIfMissing(opts.indexerDb.url, database),\n\t\t\tnetwork: opts.indexerDb.network,\n\t\t});\n\t}\n\tconst network = sanitizeAlias(`devstack-${identity.app}-${identity.stack}-sui-indexer`);\n\treturn Effect.gen(function* () {\n\t\tconst resetExistingSidecar = yield* validatorNeedsIndexerReset(runtime, identity);\n\t\tif (resetExistingSidecar) {\n\t\t\tyield* runtime.removeManagedContainers({\n\t\t\t\tapp: identity.app,\n\t\t\t\tstack: identity.stack,\n\t\t\t\tplugin: 'sui',\n\t\t\t\trole: SUI_INDEXER_DB_ROLE,\n\t\t\t});\n\t\t}\n\t\tconst imageRef = validatorImage.tag ?? validatorImage.digest;\n\t\tconst { handle } = yield* bootPostgresSidecar(runtime, identity, {\n\t\t\tnetwork,\n\t\t\talias: SUI_INDEXER_DB_ALIAS,\n\t\t\trole: SUI_INDEXER_DB_ROLE,\n\t\t\tdatabase,\n\t\t\tconfigHash: composeIndexerConfigHash(imageRef),\n\t\t});\n\t\treturn {\n\t\t\turl: withDatabase(\n\t\t\t\tcredentialedUrl({\n\t\t\t\t\tuser: handle.user,\n\t\t\t\t\tpassword: handle.password,\n\t\t\t\t\thost: handle.networkAlias,\n\t\t\t\t\tport: handle.port,\n\t\t\t\t}),\n\t\t\t\tdatabase,\n\t\t\t),\n\t\t\tnetwork: handle.containerNetwork,\n\t\t} satisfies LocalIndexer;\n\t}).pipe(\n\t\t// Postgres / runtime-domain failures wrap into the sui error channel\n\t\t// — the sidecar is a sui implementation detail. Nothing in the gen\n\t\t// body produces a `SuiPluginError` directly, so we wrap every cause.\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to provision the GraphQL indexer postgres sidecar (${cause._tag})`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n};\n\n/** Shared boot + inline contribution emission, parameterised by the\n * resolved external-indexer wiring (`undefined` = no GraphQL, the\n * zero-config / non-local case) and, for local mode, the validator image\n * the barrel pre-resolved (so the sidecar's `configHash` and the validator\n * container share one `ImageRef`; `undefined` on the no-sidecar paths,\n * where `bootLocalMode` resolves it inline). */\nconst bootAndEmit = (\n\topts: SuiOptions,\n\tindexer: LocalIndexer | undefined,\n\tprebuiltImage?: ImageRef,\n) =>\n\tEffect.gen(function* () {\n\t\tconst ctx = yield* PluginContext;\n\t\t// The substrate threads `ContainerRuntime` + `IdentityContext`\n\t\t// via the plugin runtime context; the supervisor provides\n\t\t// these before this body runs.\n\t\tconst runtime = yield* ContainerRuntimeService;\n\t\tconst identity = yield* IdentityContext;\n\t\tconst paths = yield* StackPathsService;\n\t\tconst portBroker = yield* PortBrokerService;\n\t\tconst fundingFaucetLeaseBroker = yield* LeaseBrokerService;\n\t\tconst { client } = yield* bootSuiService(\n\t\t\truntime,\n\t\t\tidentity,\n\t\t\tportBroker,\n\t\t\tpaths,\n\t\t\topts,\n\t\t\tindexer,\n\t\t\tprebuiltImage,\n\t\t);\n\n\t\tconst fundingFaucetStrategy = yield* resolveFundingFaucetStrategy(\n\t\t\topts,\n\t\t\tclient,\n\t\t\tfundingFaucetLeaseBroker,\n\t\t);\n\t\tconst value = {\n\t\t\t...client,\n\t\t\tmode: opts.mode,\n\t\t\tfundingFaucetStrategy,\n\t\t} satisfies SuiResolvedRuntime;\n\t\t// Emit the resolved contributions inline, top-to-bottom: the\n\t\t// decls stamp REAL chain ids / rpc URLs / container names\n\t\t// (the genesis-digest chain id, not the network name).\n\t\t// (`value` is the just-resolved runtime; `identity` from\n\t\t// `IdentityContext`, NOT re-fetched). The shared\n\t\t// `emitContributions` routes each by `kind`. Faucet (conditional\n\t\t// on a resolved strategy) and routables (mode-dependent) are the\n\t\t// only optional members; order is load-bearing.\n\t\tconst realChainId = value.chainId;\n\t\t// Funding-faucet gate: a FIXED policy — ON for every network EXCEPT\n\t\t// live `mainnet`, where the funding faucet must NEVER run.\n\t\t// `identity.network` is the resolved network name. There is NO\n\t\t// per-network override surface for this gate: the override RECORD\n\t\t// (`networkOptions`) is an orchestrator-level concern that the\n\t\t// name-blind substrate does not forward into plugins (this plugin\n\t\t// only receives the closed `IdentityContext` tuple), so a per-network\n\t\t// `{ <network>: { faucet: false } }` toggle could never reach here —\n\t\t// `NetworkScopedOptions` therefore deliberately omits a `faucet`\n\t\t// field rather than advertise a silent no-op (see\n\t\t// `orchestrators/network-options.ts`). The mainnet exclusion is\n\t\t// load-bearing: a resolved strategy on `mainnet` (none of the live\n\t\t// modes build one today, but a future faucet-bearing mainnet config\n\t\t// could) is suppressed and the strategy registry never exposes\n\t\t// `faucet:request:<mainnet-chain-id>`; account funding then surfaces\n\t\t// the actionable \"no faucet strategy\" error rather than silently\n\t\t// faucet-funding against a production network.\n\t\tconst faucetEnabled = identity.network !== 'mainnet';\n\t\tconst faucetContribution: ReadonlyArray<StrategyContributorDecl> =\n\t\t\t!faucetEnabled || value.fundingFaucetStrategy === null\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: 'strategy-contributor',\n\t\t\t\t\t\t\tcapabilityKey: faucetCapabilityKey(realChainId),\n\t\t\t\t\t\t\tstrategy: value.fundingFaucetStrategy,\n\t\t\t\t\t\t\tautoMounted: true,\n\t\t\t\t\t\t} satisfies StrategyContributorDecl<\n\t\t\t\t\t\t\t`faucet:request:${string}`,\n\t\t\t\t\t\t\tReturnType<typeof suiLocalStrategy>\n\t\t\t\t\t\t>,\n\t\t\t\t\t];\n\t\tconst localRoutables =\n\t\t\topts.mode === 'local'\n\t\t\t\t? makeSuiLocalRoutables({\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-sui-validator`,\n\t\t\t\t\t\t// GraphQL routes only when the external indexer is wired.\n\t\t\t\t\t\tincludeGraphql: indexer !== undefined,\n\t\t\t\t\t})\n\t\t\t\t: [];\n\t\tconst forkRoutables =\n\t\t\topts.mode === 'fork'\n\t\t\t\t? makeSuiForkRoutables({\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-sui-fork`,\n\t\t\t\t\t})\n\t\t\t\t: [];\n\t\temitContributions(ctx, [\n\t\t\t// `hasIndexer` (local only) folds the sui-owned indexer-db\n\t\t\t// sidecar into the captured containers; `indexer !== undefined`\n\t\t\t// is the same gate `bootAndEmit`'s caller resolved GraphQL on.\n\t\t\tmakeSnapshotable(opts.mode, identity.app, identity.stack, realChainId, indexer !== undefined),\n\t\t\tmakeCodegenable({\n\t\t\t\tmode: opts.mode,\n\t\t\t\tchainId: realChainId,\n\t\t\t\trpc: value.rpcUrl,\n\t\t\t\tsource: 'default',\n\t\t\t\t...(value.faucetUrl !== null ? { faucet: value.faucetUrl } : {}),\n\t\t\t\t...(value.graphqlUrl !== null ? { graphql: value.graphqlUrl } : {}),\n\t\t\t}),\n\t\t\t{\n\t\t\t\tkind: 'strategy-contributor',\n\t\t\t\tcapabilityKey: chainProbeCapabilityKey(realChainId),\n\t\t\t\tstrategy: value.chainProbe,\n\t\t\t\tautoMounted: true,\n\t\t\t} satisfies StrategyContributorDecl<`chain-probe:${string}`, ChainProbe<SuiProbeKey>>,\n\t\t\t...faucetContribution,\n\t\t\t...localRoutables,\n\t\t\t...forkRoutables,\n\t\t]);\n\t\treturn value;\n\t});\n\n/** The single sui plugin builder. No sibling `dependsOn`: in local mode\n * with the indexer on (the default), `start` provisions the GraphQL\n * indexer DB itself — a sui-owned postgres sidecar — inside the boot\n * scope BEFORE the boot-time validator (so the validator can join its\n * network), then boots + emits. Resolution order:\n * - `indexerDb` present → BYO DB (no sidecar)\n * - `indexer === false` → opt out (RPC + faucet only, GraphQL off)\n * - else (local default) → sui-owned sidecar\n * Non-local modes never touch the indexer (GraphQL off). */\nconst buildSuiPlugin = (opts: SuiOptions) =>\n\tdefinePlugin({\n\t\tid: suiResource.id,\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tinputIdentity: staticInputIdentity(suiInputIdentity(opts)),\n\t\t// Stack-free codegen: the `codegen` verb derives the committed\n\t\t// `config.ts`'s `network`/`networks` from this hook. Both are\n\t\t// environment/live data (dynamic local rpc port; a real deployment\n\t\t// names a different network), so the committed tree carries\n\t\t// `dep.network`/`Object.fromEntries(networkNames.map(forNetwork))` raw\n\t\t// expressions off the loaded deployment that resolve\n\t\t// at app build/dev time via the injected `__DEVSTACK_DEPLOYMENT__` global —\n\t\t// never literal values. No id-resolver input needed.\n\t\tstaticCodegen: makeStaticCodegen(),\n\t\t// Zero-arg `start` (no `dependsOn`); the substrate supplies the\n\t\t// container runtime + identity via the plugin runtime context.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Resolution order: BYO `indexerDb` wins; then an explicit\n\t\t\t\t// `indexer: false` opt-out; then the sui-owned sidecar default.\n\t\t\t\t// Non-local modes never wire the indexer.\n\t\t\t\tif (opts.mode !== 'local' || (opts.indexerDb === undefined && opts.indexer === false)) {\n\t\t\t\t\treturn yield* bootAndEmit(opts, undefined);\n\t\t\t\t}\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\t// Resolve the validator image ONCE, before the sidecar — single\n\t\t\t\t// source for both the sidecar's configHash (it folds the resolved\n\t\t\t\t// image ref so an image bump resets the indexer DB) and the\n\t\t\t\t// validator container `bootAndEmit` boots below. `resolveImage`\n\t\t\t\t// is deterministic (content-addressed build/pull) so this is the\n\t\t\t\t// SAME ref the validator runs; resolving it here, not twice,\n\t\t\t\t// avoids a redundant build AND any drift from `decideRunAction`.\n\t\t\t\tconst validatorImage = yield* resolveImage(runtime, identity, opts);\n\t\t\t\t// The sidecar boots first; if the validator boot below fails, the\n\t\t\t\t// sidecar's finalizer lingers on the plugin acquire scope until\n\t\t\t\t// teardown/retry. Benign and intentional — the stable name +\n\t\t\t\t// labels mean a retry ADOPTS the existing sidecar container\n\t\t\t\t// (no scope-threading machinery needed).\n\t\t\t\tconst indexer = yield* provisionLocalIndexer(runtime, identity, opts, validatorImage);\n\t\t\t\treturn yield* bootAndEmit(opts, indexer, validatorImage);\n\t\t\t}),\n\t});\n\nconst buildPlugin = <O extends SuiOptions>(opts: O) => buildSuiPlugin(opts);\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Local Sui shorthand. Network/env selection belongs to the CLI or\n * `defineDevstackWith(...)`; plain `sui()` always means an in-stack\n * local validator (GraphQL/indexer/Postgres on by default via a\n * sui-owned sidecar). */\nexport const sui = <const O extends SuiOptions = { mode: 'local' }>(\n\topts: O = { mode: 'local' } as O,\n) => buildPlugin(opts);\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const network = { mode: 'local' } as const;\n * suiFor(network).local({...}) // OK\n * suiFor(network).fork({...}) // type error: 'fork' not in 'local' branch\n *\n * The namespace MIRRORS the four mode option records: `local`,\n * `localRpc` (mapped onto the substrate `'local'` branch),\n * `live`, `fork`. */\nexport const suiFor = defineModeNamespace({\n\tlocal: {\n\t\tlocal: <const O extends Omit<SuiLocalOptions, 'mode'>>(opts: O = {} as O) =>\n\t\t\tbuildPlugin({ mode: 'local', ...opts }),\n\t\tlocalRpc: (opts: Omit<SuiLocalRpcOptions, 'mode'>) =>\n\t\t\tbuildPlugin({ mode: 'local-rpc', ...opts }),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'mainnet', ...opts }),\n\t\tdevnet: (opts: Omit<SuiLiveOptions, 'mode' | 'network'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'devnet', ...opts }),\n\t\tcustom: (opts: Omit<SuiLiveOptions, 'mode' | 'network'>) =>\n\t\t\tbuildPlugin({ mode: 'live', network: 'custom', ...opts }),\n\t},\n\tfork: {\n\t\tmainnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'mainnet', ...opts }),\n\t\ttestnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'testnet', ...opts }),\n\t\tdevnet: (opts: Omit<SuiForkOptions, 'mode' | 'upstream'> = {}) =>\n\t\t\tbuildPlugin({ mode: 'fork', upstream: 'devnet', ...opts }),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Re-exports for advanced callers (Account/Coin/Wallet/etc.) and for\n// the sibling plugins (Walrus/Seal/Deepbook fork variants).\n// ---------------------------------------------------------------------------\n\nexport type { SuiClient, ForkAdminSurface, WaitForTransactionsReady } from './mode/shared.ts';\nexport type { ResolvedSuiNetwork } from './network-resolver.ts';\nexport type {\n\tNetworkConfig,\n\tNetworkMode,\n\tDevstackNetworkModeRegistry,\n\tDefaultNetwork,\n} from './network-config.ts';\nexport type {\n\tSuiOptions,\n\tSuiLocalOptions,\n\tSuiLocalRpcOptions,\n\tSuiLiveOptions,\n\tSuiForkOptions,\n\tSuiPluginMode,\n} from './mode/spec.ts';\nexport type { SuiNetworkConfigEntry } from './codegen.ts';\nexport type {\n\tSuiError,\n\tSuiPluginError,\n\tSuiCliError,\n\tSuiConfigError,\n\tForkUnsupportedError,\n} from './errors.ts';\n\n// Cross-plugin seams (consumed by Walrus/Seal/Deepbook fork variants\n// and by Account/Coin/Wallet/Package).\nexport {\n\tchainProbeCapabilityKey,\n\ttype ChainProbe,\n\ttype ChainProbeError,\n\ttype ChainProbeMode,\n} from '../../contracts/chain-probe.ts';\nexport {\n\tFORK_UNSUPPORTED_SURFACES,\n\twrapWithForkGuard,\n\ttype ForkLockHolder,\n} from './fork-orchestration.ts';\nexport type { SuiProbeKey, SuiSdkShim } from './chain-probe.ts';\nexport { SuiLogAttr } from './log-attrs.ts';\n\n/** The shape `Transaction.build({ client })` and every `sdk.core.*` call\n * accepts. Re-exported from `@mysten/sui/client` so callers cast\n * `sui.sdk.client as ClientWithCoreApi` without each having to know the\n * SDK subpath. */\nexport type { ClientWithCoreApi } from '@mysten/sui/client';\n// Cross-plugin seams: fork impersonation + chain-build container.\n// Consumed by `action` (Move-call execution against fork) and\n// `package` (publish-to-fork + Move-build orchestration). Consumer\n// plugins import these barrel entries rather than internal modules.\nexport {\n\tbuildForkImpersonationTransactionBytes,\n\tprepareForkImpersonationTransaction,\n\tverifyForkImpersonationSender,\n\tselectSufficientForkCoin,\n\tFORK_IMPERSONATION_GAS_BUDGET,\n\tFORK_IMPERSONATION_GAS_PRICE,\n\ttype ForkGasCoin,\n\ttype ForkImpersonationGasClient,\n} from './fork-transaction.ts';\nexport {\n\tsuiForkFaucetStrategy,\n\ttype SuiForkFaucetStrategyOptions,\n\ttype SuiForkFaucetSerialization,\n} from './fork-faucet-strategy.ts';\nexport {\n\tacquireChainBuildContainer,\n\tcontainerNameForApp,\n\tmoveBuildLockPathFor,\n\tMOVE_BUILD_LOCK_TIMEOUT_MS,\n\ttype ChainBuildContainer,\n\ttype ChainBuildContainerSpec,\n} from './chain-build-container.ts';\n\n// Cross-plugin seams: hoisted exec / move / ledger helpers.\n// Consumed by Account/Action/Coin/Deepbook/Package/Seal/Walrus. These\n// barrel entries route those consumers through the sibling plugin's\n// barrel per the `plugin-boundary` invariant, rather than reaching into\n// the deep `sui/exec`, `sui/move`, and `sui/ledger` internal modules.\nexport {\n\textractExecuteDigest,\n\tformatExecutedFailure,\n\texecuteSuiTx,\n\tisSuiStaleObjectVersionError,\n\ttype ResolvedSigner,\n\ttype ExecutedFailure,\n\ttype ExecutedReceipt,\n\ttype TransactionSignerScope,\n} from './exec/index.ts';\nexport { signAndDispatch } from './exec/sign-and-dispatch.ts';\nexport {\n\thashMoveSources,\n\trunMoveBuild,\n\tscrubLocksHost,\n\twithMoveBuildLock,\n\ttype BuildOutput,\n\ttype MoveBuildContainer,\n\ttype MoveBuildError,\n} from './move/index.ts';\nexport { currentLedgerObjectRef } from './ledger/object-ref.ts';\n"],"mappings":"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"}
@@ -7,12 +7,31 @@ import { Effect, Layer } from "effect";
7
7
  import { basename, dirname, join } from "node:path";
8
8
  import { homedir, tmpdir } from "node:os";
9
9
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
10
- import { cp, mkdir, mkdtemp, rm } from "node:fs/promises";
10
+ import { cp, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
11
11
  //#region src/plugins/sui/move-summary-runner.ts
12
12
  const layerSuiMoveSummaryRunnerDocker = Layer.effect(MoveSummaryRunnerService, Effect.gen(function* () {
13
13
  const runtime = yield* ContainerRuntimeService;
14
14
  return MoveSummaryRunnerService.of({ runSummary: (input) => runSummaryViaDocker(runtime, input) });
15
15
  }));
16
+ /** A minimal, DISPOSABLE sui client config. `sui move summary` initialises a
17
+ * client config on first use and PROMPTS ("No sui config found, create one
18
+ * [Y/n]?") when none exists — which blocks forever on a non-interactive stdin
19
+ * (e.g. CI), hanging codegen. Pointing `SUI_CONFIG_DIR` at a pre-seeded config
20
+ * inside the per-run scratch dir sidesteps the prompt without touching the
21
+ * developer's real `~/.sui`. The summary is an OFFLINE build (framework deps
22
+ * are embedded in the CLI), so we write the SMALLEST config the CLI parser
23
+ * accepts: a keystore path and an EMPTY env list. No network env at all — the
24
+ * `keystore` + `envs` fields are required by the parser, but no `rpc` is ever
25
+ * contacted. */
26
+ const disposableSuiClientConfig = (configDir) => [
27
+ "---",
28
+ "keystore:",
29
+ ` File: ${join(configDir, "sui.keystore")}`,
30
+ "envs: []",
31
+ "active_env: ~",
32
+ "active_address: ~",
33
+ ""
34
+ ].join("\n");
16
35
  const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Effect.gen(function* () {
17
36
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
18
37
  return MoveSummaryRunnerService.of({ runSummary: ({ packageName, sourcePath }) => Effect.gen(function* () {
@@ -28,6 +47,7 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
28
47
  });
29
48
  const summaryPath = join(scratchDir, "package");
30
49
  const stagedPkg = join(scratchDir, "src");
50
+ const suiConfigDir = join(scratchDir, "sui-config");
31
51
  const cleanupScratch = Effect.promise(() => rm(scratchDir, {
32
52
  recursive: true,
33
53
  force: true
@@ -44,6 +64,9 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
44
64
  await cp(sourcePath, stagedPkg, { recursive: true });
45
65
  await copyLocalMoveDeps(sourcePath, stagedPkg, dirname(stagedPkg));
46
66
  await cp(join(sourcePath, "Move.toml"), join(summaryPath, "Move.toml")).catch(() => {});
67
+ await mkdir(suiConfigDir, { recursive: true });
68
+ await writeFile(join(suiConfigDir, "sui.keystore"), "[]");
69
+ await writeFile(join(suiConfigDir, "client.yaml"), disposableSuiClientConfig(suiConfigDir));
47
70
  },
48
71
  catch: (cause) => new CodegenBindingsFailed({
49
72
  package: packageName,
@@ -62,7 +85,11 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
62
85
  join(scratchDir, "install"),
63
86
  "--output-directory",
64
87
  join(summaryPath, "package_summaries")
65
- ], { cwd: stagedPkg }), {
88
+ ], {
89
+ cwd: stagedPkg,
90
+ env: { SUI_CONFIG_DIR: suiConfigDir },
91
+ extendEnv: true
92
+ }), {
66
93
  op: `sui move summary (${sourcePath})`,
67
94
  nonZeroIsFailure: true,
68
95
  stdoutTruncate: Infinity,