@mysten-incubation/devstack 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dashboard-ui/assets/{grpc-Clz0oOtc.js → grpc-CpkDu4SA.js} +1 -1
  3. package/dashboard-ui/assets/{index-Cmqv9kiU.js → index-jLPRmjst.js} +2 -2
  4. package/dashboard-ui/index.html +1 -1
  5. package/dist/api/inference-network.d.mts +5 -5
  6. package/dist/api/inference-network.mjs +5 -5
  7. package/dist/api/inference-network.mjs.map +1 -1
  8. package/dist/api/run-stack-internal.mjs +1 -3
  9. package/dist/api/run-stack-internal.mjs.map +1 -1
  10. package/dist/build-integrations/dapp-kit/index.d.mts +12 -0
  11. package/dist/build-integrations/dapp-kit/index.mjs +14 -1
  12. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -1
  13. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  14. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  15. package/dist/build-integrations/playwright/index.d.mts +2 -2
  16. package/dist/build-integrations/playwright/index.mjs +2 -2
  17. package/dist/build-integrations/playwright/wallet-context.d.mts +2 -1
  18. package/dist/build-integrations/playwright/wallet-context.mjs +141 -41
  19. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  20. package/dist/build-integrations/runtime/dapp-kit-slot.mjs +1 -1
  21. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  22. package/dist/build-integrations/vite/index.d.mts +54 -42
  23. package/dist/build-integrations/vite/index.mjs +239 -106
  24. package/dist/build-integrations/vite/index.mjs.map +1 -1
  25. package/dist/build-integrations/vitest/global-setup.mjs +8 -8
  26. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -1
  27. package/dist/cli/main.mjs +3 -2
  28. package/dist/cli/main.mjs.map +1 -1
  29. package/dist/cli/wirings/apply.mjs +0 -1
  30. package/dist/cli/wirings/apply.mjs.map +1 -1
  31. package/dist/cli/wirings/codegen.mjs +2 -3
  32. package/dist/cli/wirings/codegen.mjs.map +1 -1
  33. package/dist/cli/wirings/dump-deployment.mjs +141 -0
  34. package/dist/cli/wirings/dump-deployment.mjs.map +1 -0
  35. package/dist/cli/wirings/snapshot.mjs +0 -1
  36. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  37. package/dist/contracts/codegenable.d.mts +22 -25
  38. package/dist/contracts/codegenable.mjs +35 -4
  39. package/dist/contracts/codegenable.mjs.map +1 -1
  40. package/dist/contracts/config-bindings.mjs +43 -18
  41. package/dist/contracts/config-bindings.mjs.map +1 -1
  42. package/dist/index.mjs +1 -1
  43. package/dist/orchestrators/boot.d.mts +0 -10
  44. package/dist/orchestrators/boot.mjs +19 -59
  45. package/dist/orchestrators/boot.mjs.map +1 -1
  46. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  47. package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
  48. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
  49. package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
  50. package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
  51. package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
  52. package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
  53. package/dist/orchestrators/codegen/deployment.d.mts +63 -0
  54. package/dist/orchestrators/codegen/deployment.mjs +153 -0
  55. package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
  56. package/dist/orchestrators/codegen/errors.mjs +7 -9
  57. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  58. package/dist/orchestrators/codegen/format.mjs +20 -1
  59. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  60. package/dist/orchestrators/codegen/paths.mjs +1 -8
  61. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  62. package/dist/orchestrators/codegen/service.mjs +354 -141
  63. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  64. package/dist/orchestrators/layers.mjs +0 -1
  65. package/dist/orchestrators/layers.mjs.map +1 -1
  66. package/dist/orchestrators/network-options.d.mts +37 -35
  67. package/dist/orchestrators/network-options.mjs +13 -10
  68. package/dist/orchestrators/network-options.mjs.map +1 -1
  69. package/dist/plugins/account/codegen.d.mts +3 -4
  70. package/dist/plugins/account/codegen.mjs +5 -7
  71. package/dist/plugins/account/codegen.mjs.map +1 -1
  72. package/dist/plugins/account/index.mjs +1 -3
  73. package/dist/plugins/account/index.mjs.map +1 -1
  74. package/dist/plugins/coin/codegen.mjs +5 -5
  75. package/dist/plugins/coin/codegen.mjs.map +1 -1
  76. package/dist/plugins/coin/index.mjs.map +1 -1
  77. package/dist/plugins/dashboard/schema/root.mjs +3 -1
  78. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  79. package/dist/plugins/deepbook/codegen.mjs +4 -4
  80. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  81. package/dist/plugins/deepbook/index.mjs.map +1 -1
  82. package/dist/plugins/internal/codegen-helpers.mjs +0 -1
  83. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  84. package/dist/plugins/package/codegen.d.mts +1 -12
  85. package/dist/plugins/package/codegen.mjs +43 -25
  86. package/dist/plugins/package/codegen.mjs.map +1 -1
  87. package/dist/plugins/package/dep-resolution.mjs +1 -1
  88. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  89. package/dist/plugins/package/index.d.mts +14 -11
  90. package/dist/plugins/package/index.mjs +6 -7
  91. package/dist/plugins/package/index.mjs.map +1 -1
  92. package/dist/plugins/seal/codegen.mjs +3 -3
  93. package/dist/plugins/seal/codegen.mjs.map +1 -1
  94. package/dist/plugins/seal/index.mjs.map +1 -1
  95. package/dist/plugins/sui/codegen.mjs +5 -4
  96. package/dist/plugins/sui/codegen.mjs.map +1 -1
  97. package/dist/plugins/sui/index.mjs +1 -2
  98. package/dist/plugins/sui/index.mjs.map +1 -1
  99. package/dist/plugins/wallet/codegen.d.mts +8 -12
  100. package/dist/plugins/wallet/codegen.mjs +22 -15
  101. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  102. package/dist/plugins/wallet/index.d.mts +4 -3
  103. package/dist/plugins/wallet/index.mjs +1 -1
  104. package/dist/plugins/wallet/index.mjs.map +1 -1
  105. package/dist/plugins/wallet/service.d.mts +2 -2
  106. package/dist/plugins/wallet/service.mjs +2 -3
  107. package/dist/plugins/wallet/service.mjs.map +1 -1
  108. package/dist/plugins/walrus/codegen.mjs +4 -4
  109. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  110. package/dist/plugins/walrus/index.mjs +1 -1
  111. package/dist/plugins/walrus/index.mjs.map +1 -1
  112. package/dist/substrate/manifest.d.mts +17 -22
  113. package/dist/substrate/manifest.mjs +4 -6
  114. package/dist/substrate/manifest.mjs.map +1 -1
  115. package/dist/substrate/plugin-ctx.d.mts +6 -6
  116. package/dist/substrate/plugin-ctx.mjs.map +1 -1
  117. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  118. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  119. package/dist/substrate/runtime/paths.mjs +1 -1
  120. package/dist/surfaces/cli/command-tree.mjs +6 -6
  121. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  122. package/dist/surfaces/cli/index.mjs +6 -4
  123. package/dist/surfaces/cli/index.mjs.map +1 -1
  124. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  125. package/package.json +1 -1
  126. package/dist/cli/wirings/dump-ids.mjs +0 -86
  127. package/dist/cli/wirings/dump-ids.mjs.map +0 -1
  128. package/dist/orchestrators/codegen/id-config.d.mts +0 -1
  129. package/dist/orchestrators/codegen/id-config.mjs +0 -107
  130. package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
  131. package/dist/orchestrators/codegen/output-location.mjs +0 -32
  132. package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
@@ -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"}
@@ -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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"}
@@ -1,26 +1,22 @@
1
1
  //#region src/plugins/wallet/codegen.d.ts
2
- /** The typed shape `dapp-kit/config.ts` exports. Downstream consumers
3
- * (the user-app's dapp-kit boot code) import and consume this.
4
- *
5
- * Field shape mirrors what `DevstackSignerAdapter` needs:
2
+ /** The NON-secret dev-wallet connection metadata the adapter needs to
3
+ * reach the in-process wallet HTTP server. Routed through the deployment
4
+ * envelope's `values['dev-wallet']` channel — NEVER a generated file, and
5
+ * NEVER the secret token (that stays in the `0o600` side-channel).
6
6
  *
7
7
  * - `walletUrl` : the wallet HTTP server's URL (router-fronted
8
8
  * host form when available, direct-loopback
9
9
  * fallback otherwise).
10
- * - `pairUrl` : `walletUrl` + `/#token=<32-hex>` (single
11
- * source of truth for the token).
12
- * - `protocolPaths` : path constants the adapter reads. Mirrored
13
- * here so the adapter doesn't depend on a
14
- * separate import.
15
10
  * - `network` : the network name the wallet's accounts are
16
11
  * scoped to (e.g. `localnet`). The dev wallet
17
12
  * derives the wallet-standard chain (`sui:<network>`)
18
13
  * from it at the wallet-standard boundary; devstack
19
14
  * itself never carries the `sui:`-prefixed form.
15
+ * - `protocolPaths` : path constants the adapter reads. Mirrored here
16
+ * so the adapter doesn't depend on a separate import.
20
17
  */
21
- interface DevWalletConfig {
18
+ interface DevWalletConnection {
22
19
  readonly walletUrl: string;
23
- readonly pairUrl: string;
24
20
  readonly network: string;
25
21
  readonly protocolPaths: {
26
22
  readonly health: string;
@@ -30,5 +26,5 @@ interface DevWalletConfig {
30
26
  };
31
27
  }
32
28
  //#endregion
33
- export { DevWalletConfig };
29
+ export { DevWalletConnection };
34
30
  //# sourceMappingURL=codegen.d.mts.map
@@ -1,27 +1,34 @@
1
1
  import { defineSimpleConstExport } from "../internal/codegen-helpers.mjs";
2
2
  //#region src/plugins/wallet/codegen.ts
3
+ /** The deployment-values namespace + key the dev-wallet connection rides.
4
+ * Shared between the producer (this decl's `idConfigValues`) and the
5
+ * Vite plugin's `optionalValue(dep, DEV_WALLET_VALUES_NAMESPACE,
6
+ * DEV_WALLET_VALUES_KEY)` reader so the two can never drift. */
7
+ const DEV_WALLET_VALUES_NAMESPACE = "dev-wallet";
8
+ const DEV_WALLET_VALUES_KEY = "connection";
3
9
  /**
4
10
  * Construct the Codegenable contribution.
5
11
  *
6
- * Emits `dapp-kit/config.ts` with `sensitive: true` the orchestrator
7
- * writes the file with `0o600` and gitignores it. The emitted shape
8
- * carries the unredacted pair URL; the side-channel token file is
9
- * also `0o600`.
10
- *
11
- * The `resolved` arg is supplied AFTER acquire (the substrate's
12
- * "resolve-once" memo). At factory time the barrel passes a
13
- * placeholder so the type plumbing works; at codegen time the
14
- * substrate re-evaluates with the resolved values.
12
+ * Values-only: emits NO standalone file. It carries the non-secret
13
+ * dev-wallet connection metadata through `aggregate.idConfigValues`, which
14
+ * boot's `assembleDeployment` folds into the deployment envelope's
15
+ * `values['dev-wallet'].connection`. The secret token is never routed here
16
+ * — it stays in the `0o600` side-channel file (`pairing.ts:tokenPath`).
15
17
  */
16
- const makeWalletCodegen = (resolved) => defineSimpleConstExport({
17
- emitterName: "dapp-kit-config",
18
+ const makeWalletCodegen = (connection) => defineSimpleConstExport({
19
+ emitterName: "dev-wallet-connection",
18
20
  outputPath: "dev-wallet.ts",
19
21
  exportName: "devWallet",
20
- value: resolved,
21
- outputLocation: "generated-extras",
22
- sensitive: true
22
+ value: connection,
23
+ aggregateOnly: true,
24
+ aggregate: {
25
+ bucket: "dev-wallet.ts",
26
+ kind: "dev-wallet",
27
+ project: () => null,
28
+ idConfigValues: { [DEV_WALLET_VALUES_NAMESPACE]: { [DEV_WALLET_VALUES_KEY]: connection } }
29
+ }
23
30
  });
24
31
  //#endregion
25
- export { makeWalletCodegen };
32
+ export { DEV_WALLET_VALUES_KEY, DEV_WALLET_VALUES_NAMESPACE, makeWalletCodegen };
26
33
 
27
34
  //# sourceMappingURL=codegen.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/wallet/codegen.ts"],"sourcesContent":["// Wallet plugin — Codegenable contribution.\n//\n// Architecture (15-wallet.md §\"Capabilities PRODUCED\" + §\"Codegen\n// emits a `dapp-kit-config.ts`\"):\n//\n// - The browser-side dev-wallet adapter is the cross-boundary\n// consumer. It reads a typed `dapp-kit-config` value at startup,\n// constructs a `DevstackSignerAdapter`, and registers it with\n// `@mysten/dapp-kit`'s wallet-standard surface (in user-app\n// bundle code — devstack itself NEVER imports dapp-kit).\n//\n// - The emitted file lives at `dapp-kit/config.ts` under the staging\n// dir. The generated module owns the exported config value's type.\n//\n// SENSITIVE FLAG (manifest-vs-token threat surface):\n//\n// - The emitted file carries the unredacted pair URL (incl. the\n// `#token=<32-hex>` fragment) so the dev-wallet adapter can wire\n// itself up without a side-channel read.\n// - Therefore `sensitive: true`. The codegen orchestrator tightens\n// the file mode to `0o600` on emit AND injects the file path into\n// `.gitignore`.\n// - The token lives in a `0o600` side-channel file (see\n// `pairing.ts:tokenPath`) AND the codegen emit is `0o600` via the\n// sensitive flag. The unredacted pair URL is never written to a\n// world-readable manifest only the tightened codegen file carries\n// it.\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\n\nimport { defineSimpleConstExport } from '../internal/codegen-helpers.ts';\n\n// ----------------------------------------------------------------------\n// Emitted shape\n// ----------------------------------------------------------------------\n\n/** The typed shape `dapp-kit/config.ts` exports. Downstream consumers\n * (the user-app's dapp-kit boot code) import and consume this.\n *\n * Field shape mirrors what `DevstackSignerAdapter` needs:\n *\n * - `walletUrl` : the wallet HTTP server's URL (router-fronted\n * host form when available, direct-loopback\n * fallback otherwise).\n * - `pairUrl` : `walletUrl` + `/#token=<32-hex>` (single\n * source of truth for the token).\n * - `protocolPaths` : path constants the adapter reads. Mirrored\n * here so the adapter doesn't depend on a\n * separate import.\n * - `network` : the network name the wallet's accounts are\n * scoped to (e.g. `localnet`). The dev wallet\n * derives the wallet-standard chain (`sui:<network>`)\n * from it at the wallet-standard boundary; devstack\n * itself never carries the `sui:`-prefixed form.\n */\nexport interface DevWalletConfig {\n\treadonly walletUrl: string;\n\treadonly pairUrl: string;\n\treadonly network: string;\n\treadonly protocolPaths: {\n\t\treadonly health: string;\n\t\treadonly accounts: string;\n\t\treadonly signTransaction: string;\n\t\treadonly signPersonalMessage: string;\n\t};\n}\n\n// ----------------------------------------------------------------------\n// Decl construction\n// ----------------------------------------------------------------------\n\n/**\n * Construct the Codegenable contribution.\n *\n * Emits `dapp-kit/config.ts` with `sensitive: true` the orchestrator\n * writes the file with `0o600` and gitignores it. The emitted shape\n * carries the unredacted pair URL; the side-channel token file is\n * also `0o600`.\n *\n * The `resolved` arg is supplied AFTER acquire (the substrate's\n * \"resolve-once\" memo). At factory time the barrel passes a\n * placeholder so the type plumbing works; at codegen time the\n * substrate re-evaluates with the resolved values.\n */\nexport const makeWalletCodegen = (resolved: DevWalletConfig): CodegenableDecl<'dapp-kit-config'> =>\n\tdefineSimpleConstExport({\n\t\temitterName: 'dapp-kit-config',\n\t\toutputPath: 'dev-wallet.ts',\n\t\texportName: 'devWallet',\n\t\tvalue: resolved,\n\t\t// Dev-only + secret-bearing: lands in the gitignored\n\t\t// `generated-extras` tree (reached via `@devstack-dev`). The\n\t\t// token never enters the runtime `src/generated/` tree.\n\t\toutputLocation: 'generated-extras',\n\t\t// SENSITIVE: drives 0o600. The architecture has this hook\n\t\t// (`SnapshotableDecl` mirrors it for the snapshot subtree).\n\t\t// `generated-extras` is already gitignored at the `.devstack`\n\t\t// level, so the codegen `.gitignore` does not list it.\n\t\tsensitive: true,\n\t});\n"],"mappings":";;;;;;;;;;;;;;;AAoFA,MAAa,qBAAqB,aACjC,wBAAwB;CACvB,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,OAAO;CAIP,gBAAgB;CAKhB,WAAW;AACZ,CAAC"}
1
+ {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/wallet/codegen.ts"],"sourcesContent":["// Wallet plugin — Codegenable contribution.\n//\n// Architecture (15-wallet.md §\"Capabilities PRODUCED\"):\n//\n// - The browser-side dev-wallet adapter is the cross-boundary\n// consumer. It reads the dev-wallet CONNECTION metadata (server\n// URL, network, protocol paths) at startup, constructs a\n// `DevstackSignerAdapter`, and registers it with `@mysten/dapp-kit`'s\n// wallet-standard surface (in user-app bundle code — devstack itself\n// NEVER imports dapp-kit).\n//\n// - The connection metadata rides the deployment ENVELOPE's generic\n// `values['dev-wallet']` channel (NOT a generated file): boot's\n// `assembleDeployment` folds this decl's `idConfigValues` into\n// `deployment.networks[net].values['dev-wallet']`, which the Vite\n// plugin reads (`optionalValue(dep, 'dev-wallet', …)`) to assemble\n// the dev-wallet injection. The decl emits NO standalone file — it\n// is a values-only contribution.\n//\n// SECRET TOKEN (manifest-vs-token threat surface):\n//\n// - The pairing token is NEVER routed through `values` (which lands in\n// the world-readable `deployment.json`). It stays in its `0o600`\n// side-channel file (see `pairing.ts:tokenPath`); the Vite `load`\n// hook runs in Node and reads it by path. Only the NON-secret\n// connection fields (`walletUrl`, `network`, `protocolPaths`) ride\n// `values`.\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\n\nimport { defineSimpleConstExport } from '../internal/codegen-helpers.ts';\n\n// ----------------------------------------------------------------------\n// Connection metadata shape\n// ----------------------------------------------------------------------\n\n/** The NON-secret dev-wallet connection metadata the adapter needs to\n * reach the in-process wallet HTTP server. Routed through the deployment\n * envelope's `values['dev-wallet']` channel NEVER a generated file, and\n * NEVER the secret token (that stays in the `0o600` side-channel).\n *\n * - `walletUrl` : the wallet HTTP server's URL (router-fronted\n * host form when available, direct-loopback\n * fallback otherwise).\n * - `network` : the network name the wallet's accounts are\n * scoped to (e.g. `localnet`). The dev wallet\n * derives the wallet-standard chain (`sui:<network>`)\n * from it at the wallet-standard boundary; devstack\n * itself never carries the `sui:`-prefixed form.\n * - `protocolPaths` : path constants the adapter reads. Mirrored here\n * so the adapter doesn't depend on a separate import.\n */\nexport interface DevWalletConnection {\n\treadonly walletUrl: string;\n\treadonly network: string;\n\treadonly protocolPaths: {\n\t\treadonly health: string;\n\t\treadonly accounts: string;\n\t\treadonly signTransaction: string;\n\t\treadonly signPersonalMessage: string;\n\t};\n}\n\n/** The deployment-values namespace + key the dev-wallet connection rides.\n * Shared between the producer (this decl's `idConfigValues`) and the\n * Vite plugin's `optionalValue(dep, DEV_WALLET_VALUES_NAMESPACE,\n * DEV_WALLET_VALUES_KEY)` reader so the two can never drift. */\nexport const DEV_WALLET_VALUES_NAMESPACE = 'dev-wallet' as const;\nexport const DEV_WALLET_VALUES_KEY = 'connection' as const;\n\n// ----------------------------------------------------------------------\n// Decl construction\n// ----------------------------------------------------------------------\n\n/**\n * Construct the Codegenable contribution.\n *\n * Values-only: emits NO standalone file. It carries the non-secret\n * dev-wallet connection metadata through `aggregate.idConfigValues`, which\n * boot's `assembleDeployment` folds into the deployment envelope's\n * `values['dev-wallet'].connection`. The secret token is never routed here\n * it stays in the `0o600` side-channel file (`pairing.ts:tokenPath`).\n */\nexport const makeWalletCodegen = (\n\tconnection: DevWalletConnection,\n): CodegenableDecl<'dev-wallet-connection'> =>\n\tdefineSimpleConstExport({\n\t\temitterName: 'dev-wallet-connection',\n\t\t// Never written: `aggregateOnly` skips the standalone file, and the\n\t\t// aggregate carries ONLY `idConfigValues` (no `bucket` file emit at\n\t\t// `assembleDeployment`, which special-cases `config.ts` / `accounts.ts`).\n\t\toutputPath: 'dev-wallet.ts',\n\t\texportName: 'devWallet',\n\t\tvalue: connection,\n\t\taggregateOnly: true,\n\t\taggregate: {\n\t\t\t// A neutral bucket name: `assembleDeployment` only PROJECTS the\n\t\t\t// `config.ts` / `accounts.ts` buckets into the typed deployment\n\t\t\t// fields; every other bucket contributes via `idConfigValues` only.\n\t\t\t// The committed-tree emit cycle never sees this decl (boot emits\n\t\t\t// only the STATIC id-free contributions + the deployment file).\n\t\t\tbucket: 'dev-wallet.ts',\n\t\t\tkind: 'dev-wallet',\n\t\t\t// Pass-through: the connection rides `idConfigValues`, so the\n\t\t\t// projection contributes nothing to a file bucket.\n\t\t\tproject: () => null,\n\t\t\t// The non-secret connection metadata folded into the deployment\n\t\t\t// envelope's `values['dev-wallet'].connection` by `assembleDeployment`.\n\t\t\tidConfigValues: {\n\t\t\t\t[DEV_WALLET_VALUES_NAMESPACE]: {\n\t\t\t\t\t[DEV_WALLET_VALUES_KEY]: connection,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t});\n"],"mappings":";;;;;;AAmEA,MAAa,8BAA8B;AAC3C,MAAa,wBAAwB;;;;;;;;;;AAerC,MAAa,qBACZ,eAEA,wBAAwB;CACvB,aAAa;CAIb,YAAY;CACZ,YAAY;CACZ,OAAO;CACP,eAAe;CACf,WAAW;EAMV,QAAQ;EACR,MAAM;EAGN,eAAe;EAGf,gBAAgB,GACd,8BAA8B,GAC7B,wBAAwB,WAC1B,EACD;CACD;AACD,CAAC"}
@@ -2,7 +2,7 @@ import { WALLET_AUTH_HEADER, WALLET_BEARER_PREFIX, WALLET_ENDPOINT_KEY, WALLET_E
2
2
  import { Plugin, ResourceRef } from "../../substrate/plugin.mjs";
3
3
  import { SuiOptions } from "../sui/mode/spec.mjs";
4
4
  import { SuiClient } from "../sui/mode/shared.mjs";
5
- import { DevWalletConfig } from "./codegen.mjs";
5
+ import { DevWalletConnection } from "./codegen.mjs";
6
6
  import { WalletBootError, WalletBootPhase, WalletError, WalletRequestError, WalletRequestPhase } from "./errors.mjs";
7
7
  import { PairingToken } from "./pairing.mjs";
8
8
  import { WalletServerHandle } from "./server.mjs";
@@ -40,8 +40,9 @@ import { WALLET_ACCOUNTS_ALL, WalletAccountMember, WalletOptions, WalletValue }
40
40
  *
41
41
  * - Constant-time bearer compare on every request.
42
42
  *
43
- * - Token file `0o600`. Codegen output (`dapp-kit/config.ts`)
44
- * `0o600` + gitignored via `sensitive: true`.
43
+ * - Token file `0o600`. The connection metadata rides the deployment
44
+ * envelope's `values['dev-wallet']`; the token NEVER leaves the
45
+ * `0o600` side-channel file.
45
46
  */
46
47
  declare function wallet<const Accounts extends ReadonlyArray<WalletAccountMember>>(opts: Omit<WalletOptions, 'accounts'> & {
47
48
  readonly accounts: Accounts;
@@ -116,7 +116,7 @@ function makeWalletMember(opts, accounts) {
116
116
  routedAppOrigin
117
117
  });
118
118
  ctx.snapshotExtra(makeWalletSnapshotable());
119
- ctx.codegen(makeWalletCodegen(resolved.bindings));
119
+ ctx.codegen(makeWalletCodegen(resolved.connection));
120
120
  ctx.endpoint(makeWalletRoutable({
121
121
  app: identity.app,
122
122
  stack: identity.stack,