@mysten-incubation/devstack 0.2.0 → 0.3.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.
- package/dashboard-ui/assets/{grpc-a4usE3Nk.js → grpc-Clz0oOtc.js} +1 -1
- package/dashboard-ui/assets/{index-CRYJ4pru.js → index-Cmqv9kiU.js} +39 -33
- package/dashboard-ui/index.html +1 -1
- package/dist/api/run-stack-internal.mjs +1 -0
- package/dist/api/run-stack-internal.mjs.map +1 -1
- package/dist/build-integrations/playwright/config.d.mts +2 -1
- package/dist/build-integrations/playwright/config.mjs +1 -1
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/vite/index.d.mts +39 -9
- package/dist/build-integrations/vite/index.mjs +47 -11
- package/dist/build-integrations/vite/index.mjs.map +1 -1
- package/dist/build-integrations/vitest/config.mjs +3 -4
- package/dist/build-integrations/vitest/config.mjs.map +1 -1
- package/dist/cli/doctor-probes.mjs +7 -2
- package/dist/cli/doctor-probes.mjs.map +1 -1
- package/dist/cli/main.mjs +2 -2
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/wirings/codegen.mjs +35 -35
- package/dist/cli/wirings/codegen.mjs.map +1 -1
- package/dist/cli/wirings/up.mjs +7 -0
- package/dist/cli/wirings/up.mjs.map +1 -1
- package/dist/orchestrators/boot.mjs +12 -2
- package/dist/orchestrators/boot.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +23 -8
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/plugins/dashboard/domain.mjs +18 -1
- package/dist/plugins/dashboard/domain.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/root.mjs +2 -2
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/types.mjs +15 -2
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
- package/dist/plugins/deepbook/index.d.mts +7 -3
- package/dist/plugins/deepbook/index.mjs +3 -3
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +10 -10
- package/dist/plugins/sui/move-summary-runner.mjs +29 -2
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
- package/dist/substrate/runtime/index.mjs +1 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.mjs +54 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.mjs +1 -0
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +76 -6
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +2 -6
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["coinFromPackage","builtinCoin","localOpts"],"sources":["../../../src/plugins/deepbook/index.ts"],"sourcesContent":["// Deepbook plugin — barrel + factories.\n//\n// Architecture: Deepbook is a task plugin that resolves a managed\n// local deployment, a known deployment, or explicit caller-supplied\n// override ids, then emits bindings.\n//\n// Mode discipline:\n//\n// - `deepbook(opts)` — explicit mode selection.\n// Localnet can default to local when\n// passed local options.\n// - `deepbookFor(network).local` — local-branch managed deployment.\n// - `deepbookFor(network).override` — local-branch override for\n// caller-supplied deployment ids.\n// - `deepbookFor(network).known` — known-deployment branch (live +\n// fork networks; wraps an already-\n// deployed canonical instance).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// Local mode:\n// 1. `ctx.snapshotExtra` — `deepbook/<name>` subtree.\n// 2. `ctx.codegen` — `deepbook-network` bindings.\n//\n// Override mode:\n// 1. `ctx.snapshotExtra` — identity guard only.\n// 2. `ctx.codegen` — `deepbook-network` bindings.\n//\n// Known mode:\n// 1. `ctx.snapshotExtra` — identity guard only.\n// 2. `ctx.codegen` — `deepbook-network` bindings (mode='known').\n//\n// Resource id: `deepbook/<name>`. Plugin key: `deepbook:<name>`.\n\nimport { Effect } from 'effect';\n\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { definePlugin, resource, type ResourceValueOf } from '../../api/define-plugin.ts';\nimport type { SnapshotableDecl } from '../../contracts/snapshotable.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { setCurrentPluginPhase } from '../../substrate/runtime/current-plugin.ts';\nimport { passthroughOrWrap } from '../../substrate/runtime/passthrough-or-wrap.ts';\nimport { IdentityContext } from '../../substrate/runtime/paths.ts';\nimport { suiResource } from '../sui/index.ts';\nimport type { AccountValue } from '../account/index.ts';\nimport {\n\tbuiltin as builtinCoin,\n\tfromPackage as coinFromPackage,\n\ttype CoinValue,\n} from '../coin/index.ts';\nimport type { LocalPackageResolved } from '../package/index.ts';\n\nimport { deepbookPluginKey } from './plugin-key.ts';\nimport {\n\tDEEPBOOK_ERROR_TAGS,\n\tdeepbookConfigError,\n\tdeepbookPluginError,\n\ttype DeepbookConfigError,\n\ttype DeepbookError,\n\ttype DeepbookPluginError,\n} from './errors.ts';\nimport {\n\tmakeDeepbookCodegenable,\n\tmakeDeepbookStaticCodegen,\n\ttype DeepbookBindings,\n} from './codegen.ts';\nimport { LOCAL_NETWORK_NAME } from '../../api/inference-network.ts';\nimport {\n\tmakeDeepbookDeepFundingContribution,\n\tmakeDeepbookDeepFundingStrategy,\n\ttype DeepbookDeepFundingStrategy,\n} from './faucet-strategy.ts';\nimport { makeKnownSnapshotable, makeLocalSnapshotable } from './snapshot.ts';\nimport {\n\tcreateDeepbookPools,\n\tseedDeepbookPools,\n\ttype DeepbookDeployment,\n\ttype ResolvedDeepbookPoolSpec,\n} from './deploy.ts';\nimport { initLocalPythFeeds } from './pyth/index.ts';\nimport type {\n\tAccountMemberAlias,\n\tDeepbookPackageMember,\n\tDeepbookPool,\n\tDeepbookPoolSpec,\n\tPythHandle,\n\tPythOptions,\n} from './types.ts';\n\n// ---------------------------------------------------------------------------\n// Resource — the resolved value all consumers read\n// ---------------------------------------------------------------------------\n\nexport type DeepbookResourceId<Name extends string> = `deepbook/${Name}`;\n\nconst makeDeepbookResource = <Name extends string>(name: Name) =>\n\tresource<DeepbookResourceId<Name>, DeepbookResolved>(\n\t\t`deepbook/${name}` as DeepbookResourceId<Name>,\n\t);\n\n/** The deepbook resolved value. Mode-asymmetric:\n *\n * - `adminCapId` is `null` for known-deployment mode.\n * - `margin` / `serverUrl` / `indexerUrl` / `marketMakerRunning`\n * are `null` when the corresponding sub-feature is not enabled. */\nexport interface DeepbookResolved {\n\treadonly mode: 'local' | 'override' | 'known';\n\treadonly network: string;\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly adminCapId: string | null;\n\treadonly deepTreasuryId: string | null;\n\treadonly pools: ReadonlyArray<DeepbookPool>;\n\treadonly pyth: PythHandle | null;\n\treadonly margin: {\n\t\treadonly packageId: string;\n\t\treadonly registryId: string;\n\t} | null;\n\treadonly serverUrl: string | null;\n\treadonly indexerUrl: string | null;\n\treadonly marketMakerRunning: boolean;\n\treadonly deepFundingStrategy: DeepbookDeepFundingStrategy | null;\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface DeepbookCommonOptions {\n\treadonly name?: string;\n}\n\n/** Override mode wraps an explicitly supplied deployment. It does not\n * publish or manage DeepBook locally. */\nexport interface DeepbookOverrideOptions extends DeepbookCommonOptions {\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly adminCapId: string;\n\treadonly network?: string;\n}\n\n/** Local mode wraps an explicitly supplied local DeepBook package.\n *\n * Explicit-config discipline: `publisher`, `package`, and `pools` are all\n * REQUIRED — the caller publishes the DeepBook Move tree, funds a publisher,\n * and declares the pools. There is no zero-arg auto-synthesis; an\n * under-specified `deepbook({ mode: 'local' })` fails fast with a tagged\n * config error (see the guard in `resolveLocalOptions`). `pyth` stays\n * optional — pass it to seed local mock price feeds, omit it for a\n * feed-less DeX. */\nexport interface DeepbookLocalOptions<\n\tPublisher extends AccountMemberAlias = AccountMemberAlias,\n\tPackage extends DeepbookPackageMember = DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tPyth extends PythOptions | undefined = undefined,\n> extends DeepbookCommonOptions {\n\t/** Publisher account — Direct Member Ref (locked API decision). Required. */\n\treadonly publisher: Publisher;\n\t/** Published DeepBook package member. The package must capture the\n\t * `registry::Registry` and `registry::DeepbookAdminCap` object ids.\n\t * Required. */\n\treadonly package: Package;\n\t/** Optional local mock-Pyth package + feed setup. Omit for a feed-less\n\t * local DeX. */\n\treadonly pyth?: Pyth;\n\t/** Capture key for the package-created `registry::Registry`. */\n\treadonly registryIdKey?: string;\n\t/** Capture key for the package-created `registry::DeepbookAdminCap`. */\n\treadonly adminCapIdKey?: string;\n\t/** Optional capture key for a DEEP treasury object used by SDK bindings. */\n\treadonly deepTreasuryIdKey?: string;\n\t/** Pools to create after the DeepBook package publishes. OPTIONAL: when\n\t * omitted, a single unseeded (empty-book) `DEEP/SUI` pool is synthesized\n\t * (the DEEP coin comes from `package`, SUI is built-in — no extra package\n\t * needed), so a minimal `deepbook({ mode:'local', publisher, package })`\n\t * boots a usable DeX. Pass `[]` explicitly for a known-empty deployment, or your own\n\t * pools for full control. */\n\treadonly pools?: Pools;\n}\n\nexport type DeepbookKnownNetwork = 'mainnet' | 'testnet';\n\ninterface DeepbookKnownCommonOptions extends DeepbookCommonOptions {\n\t/** Optional network override (defaults to the configured network). */\n\treadonly network?: string;\n}\n\ninterface DeepbookKnownNetworkOptions extends DeepbookKnownCommonOptions {\n\treadonly network: DeepbookKnownNetwork;\n\treadonly packageId?: string;\n\treadonly registryId?: string;\n}\n\ninterface DeepbookKnownExplicitOptions extends DeepbookKnownCommonOptions {\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly network?: DeepbookKnownNetwork;\n}\n\nexport type DeepbookKnownOptions = DeepbookKnownNetworkOptions | DeepbookKnownExplicitOptions;\n\nexport type DeepbookOptions<\n\tPublisher extends AccountMemberAlias = AccountMemberAlias,\n\tPyth extends PythOptions | undefined = PythOptions | undefined,\n> =\n\t| ({\n\t\t\treadonly mode: 'local';\n\t } & DeepbookLocalOptions<\n\t\t\tPublisher,\n\t\t\tDeepbookPackageMember,\n\t\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\t\tPyth\n\t >)\n\t| ({ readonly mode: 'override' } & DeepbookOverrideOptions)\n\t| ({ readonly mode: 'known' } & DeepbookKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction — override\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_NAME = 'deepbook';\n\nconst KNOWN_DEEPBOOK_DEPLOYMENTS: Record<\n\tDeepbookKnownNetwork,\n\t{\n\t\treadonly network: string;\n\t\treadonly packageId: string;\n\t\treadonly registryId: string;\n\t\treadonly deepTreasuryId: string;\n\t\treadonly pyth: PythHandle;\n\t}\n> = {\n\ttestnet: {\n\t\tnetwork: 'testnet',\n\t\tpackageId: '0x22be4cade64bf2d02412c7e8d0e8beea2f78828b948118d46735315409371a3c',\n\t\tregistryId: '0x7c256edbda983a2cd6f946655f4bf3f00a41043993781f8674a7046e8c0e11d1',\n\t\tdeepTreasuryId: '0x69fffdae0075f8f71f4fa793549c11079266910e8905169845af1f5d00e09dcb',\n\t\tpyth: {\n\t\t\tpackageId: null,\n\t\t\tstateId: '0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c',\n\t\t\twormholeStateId: '0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790',\n\t\t\tfeeds: [],\n\t\t},\n\t},\n\tmainnet: {\n\t\tnetwork: 'mainnet',\n\t\tpackageId: '0xf48222c4e057fa468baf136bff8e12504209d43850c5778f76159292a96f621e',\n\t\tregistryId: '0xaf16199a2dff736e9f07a845f23c5da6df6f756eddb631aed9d24a93efc4549d',\n\t\tdeepTreasuryId: '0x032abf8948dda67a271bcc18e776dbbcfb0d58c8d288a700ff0d5521e57a1ffe',\n\t\tpyth: {\n\t\t\tpackageId: null,\n\t\t\tstateId: '0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8',\n\t\t\twormholeStateId: '0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c',\n\t\t\tfeeds: [],\n\t\t},\n\t},\n};\n\ntype PoolCoinRefs<Pools extends ReadonlyArray<DeepbookPoolSpec>> =\n\tPools[number] extends DeepbookPoolSpec<infer Base, infer Quote> ? Base | Quote : never;\ntype PoolCoinRefTuple<Pools extends ReadonlyArray<DeepbookPoolSpec>> = Pools extends readonly []\n\t? readonly []\n\t: readonly PoolCoinRefs<Pools>[];\n\ntype PythRefs<Pyth extends PythOptions | undefined> =\n\tPyth extends PythOptions<infer Package, infer Pusher> ? readonly [Pusher, Package] : readonly [];\n\ntype LocalDependsOn<\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined,\n> = readonly [\n\ttypeof suiResource,\n\tPublisher,\n\tPackage,\n\t...PythRefs<Pyth>,\n\t...PoolCoinRefTuple<Pools>,\n];\n\nconst poolCoinRefs = <Pools extends ReadonlyArray<DeepbookPoolSpec>>(\n\tpools: Pools,\n): ReadonlyArray<PoolCoinRefs<Pools>> =>\n\tpools.flatMap((pool) => [pool.base.coin, pool.quote.coin]) as unknown as ReadonlyArray<\n\t\tPoolCoinRefs<Pools>\n\t>;\n\nconst pythRefs = <Pyth extends PythOptions | undefined>(pyth: Pyth): PythRefs<Pyth> =>\n\t(pyth === undefined ? [] : [pyth.pusher, pyth.package]) as unknown as PythRefs<Pyth>;\n\nconst localDependsOn = <\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): LocalDependsOn<Publisher, Package, Pools, Pyth> =>\n\t[\n\t\tsuiResource,\n\t\topts.publisher,\n\t\topts.package,\n\t\t...pythRefs(opts.pyth),\n\t\t...poolCoinRefs((opts.pools ?? []) as Pools),\n\t] as unknown as LocalDependsOn<Publisher, Package, Pools, Pyth>;\n\nconst requireCapturedId = (\n\tpkg: LocalPackageResolved,\n\tkey: string,\n\tkind: 'registryId' | 'adminCapId',\n): Effect.Effect<string, DeepbookPluginError> => {\n\tconst value = pkg.captured[key];\n\tif (typeof value === 'string' && value.length > 0) {\n\t\treturn Effect.succeed(value);\n\t}\n\treturn Effect.fail(\n\t\tdeepbookPluginError(\n\t\t\t'publish',\n\t\t\t`deepbook local package '${pkg.name}' is missing captured ${kind} '${key}'.`,\n\t\t),\n\t);\n};\n\nconst requirePoolCoinValue = (\n\tcoinValuesByRefId: ReadonlyMap<string, CoinValue>,\n\tpoolName: string,\n\tside: 'base' | 'quote',\n\tcoinRefId: string,\n): Effect.Effect<CoinValue, DeepbookConfigError> => {\n\tconst value = coinValuesByRefId.get(coinRefId);\n\tif (value === undefined) {\n\t\t// Compose-time bug — `dependsOn`/`poolCoinRefs` dropped this coin.\n\t\t// Surface a typed config error naming the missing coin id rather\n\t\t// than letting a double-cast `undefined` slip into the resolved\n\t\t// pool spec. Lands on the typed E channel (not a sync throw, which\n\t\t// inside Effect.gen would become an uncaught DEFECT that\n\t\t// `passthroughOrWrap` could not see); `DeepbookConfigError` is in\n\t\t// `DEEPBOOK_ERROR_TAGS`, so the outer pipeline passes it through\n\t\t// untouched.\n\t\treturn Effect.fail(\n\t\t\tdeepbookConfigError(\n\t\t\t\t'pools',\n\t\t\t\t`deepbook: pool '${poolName}' ${side} coin '${coinRefId}' was not resolved by the dependency tuple.`,\n\t\t\t\t'This is a compose-time bug — ensure the coin member is included in `dependsOn`/`poolCoinRefs`.',\n\t\t\t),\n\t\t);\n\t}\n\treturn Effect.succeed(value);\n};\n\nconst resolvePoolSpecs = (\n\tpools: ReadonlyArray<DeepbookPoolSpec>,\n\tcoinValuesByRefId: ReadonlyMap<string, CoinValue>,\n): Effect.Effect<ReadonlyArray<ResolvedDeepbookPoolSpec>, DeepbookConfigError> =>\n\tEffect.forEach(pools, (pool) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst base = yield* requirePoolCoinValue(\n\t\t\t\tcoinValuesByRefId,\n\t\t\t\tpool.name,\n\t\t\t\t'base',\n\t\t\t\tpool.base.coin.id,\n\t\t\t);\n\t\t\tconst quote = yield* requirePoolCoinValue(\n\t\t\t\tcoinValuesByRefId,\n\t\t\t\tpool.name,\n\t\t\t\t'quote',\n\t\t\t\tpool.quote.coin.id,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tname: pool.name,\n\t\t\t\tbase: pool.base.key,\n\t\t\t\tquote: pool.quote.key,\n\t\t\t\tbaseCoinType: base.fullCoinType,\n\t\t\t\tquoteCoinType: quote.fullCoinType,\n\t\t\t\t...(base.fundingStrategy === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { baseFundingStrategy: base.fundingStrategy }),\n\t\t\t\t...(quote.fundingStrategy === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { quoteFundingStrategy: quote.fundingStrategy }),\n\t\t\t\ttickSize: pool.tickSize,\n\t\t\t\tlotSize: pool.lotSize,\n\t\t\t\tminSize: pool.minSize,\n\t\t\t\twhitelisted: pool.whitelisted ?? true,\n\t\t\t\tstablePool: pool.stablePool ?? false,\n\t\t\t\t...(pool.seed === undefined ? {} : { seed: pool.seed }),\n\t\t\t};\n\t\t}),\n\t);\n\nconst assertUniquePoolNames = (name: string, pools: ReadonlyArray<DeepbookPoolSpec>) => {\n\tconst seen = new Set<string>();\n\tfor (const pool of pools) {\n\t\tif (seen.has(pool.name)) {\n\t\t\tthrow deepbookConfigError(\n\t\t\t\t'pools',\n\t\t\t\t`deepbook({mode:'local', name:'${name}'}) has duplicate pool '${pool.name}'.`,\n\t\t\t\t'Give each local DeepBook pool a unique SDK key.',\n\t\t\t);\n\t\t}\n\t\tseen.add(pool.name);\n\t\tfor (const order of pool.seed?.orders ?? []) {\n\t\t\tif (order.quantity < pool.minSize) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is below minSize.`,\n\t\t\t\t\t'Use a seed order quantity greater than or equal to the pool minSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (order.quantity % pool.lotSize !== 0n) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is not lot-aligned.`,\n\t\t\t\t\t'Use a seed order quantity divisible by the pool lotSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (order.price % pool.tickSize !== 0n) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is not tick-aligned.`,\n\t\t\t\t\t'Use a seed order price divisible by the pool tickSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst buildOverridePlugin = (opts: DeepbookOverrideOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tif (!opts.packageId || !opts.registryId || !opts.adminCapId) {\n\t\tthrow deepbookConfigError(\n\t\t\t'packageId',\n\t\t\t`deepbook({mode:'override', name:'${name}'}) requires packageId, registryId, and adminCapId.`,\n\t\t\t`Pass explicit deployment ids or use deepbook({mode:'known', network:'testnet'}).`,\n\t\t);\n\t}\n\tconst deepbookResource = makeDeepbookResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn: [suiResource] as const,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Override mode's deployment ids are DECLARED config — bake them as\n\t\t// literals in the committed tree (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeDeepbookStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tnetwork: opts.network ?? LOCAL_NETWORK_NAME,\n\t\t\t\tknown: {\n\t\t\t\t\tpackageId: opts.packageId,\n\t\t\t\t\tregistryId: opts.registryId,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// `deps` auto-infers the resolved `[sui]` tuple from the\n\t\t// `[suiResource] as const` dependency. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst network = opts.network ?? identity.network;\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'override',\n\t\t\t\t\tnetwork,\n\t\t\t\t\tpackageId: opts.packageId,\n\t\t\t\t\tregistryId: opts.registryId,\n\t\t\t\t\tadminCapId: opts.adminCapId,\n\t\t\t\t\tdeepTreasuryId: null,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\tmarketMakerRunning: false,\n\t\t\t\t\tdeepFundingStrategy: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen. `resolved` is\n\t\t\t\t// the just-computed value; `snap` is the override-mode\n\t\t\t\t// identity-guard snapshotable in scope. No DEEP funding.\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: resolved.adminCapId,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\treturn resolved;\n\t\t\t}),\n\t});\n};\n\n/** Concrete local options after the explicit-config guard: `publisher`,\n * `package`, and `pools` are guaranteed present. */\ntype ResolvedLocalOptions = DeepbookLocalOptions<\n\tAccountMemberAlias,\n\tDeepbookPackageMember,\n\tReadonlyArray<DeepbookPoolSpec>,\n\tPythOptions | undefined\n> & {\n\treadonly publisher: AccountMemberAlias;\n\treadonly package: DeepbookPackageMember;\n\treadonly pools: ReadonlyArray<DeepbookPoolSpec>;\n};\n\n/** Default local pool synthesized when `pools` is omitted: a single whitelisted\n * `DEEP/SUI` pool. DEEP is the deepbook package's own coin (no extra package to\n * publish), SUI is built-in, so this needs nothing beyond the `package` the\n * caller already passes — and NO seed, so it requires no DEEP minting (i.e. no\n * `deepTreasuryIdKey`) and works for a bare `deepbook({ publisher, package })`.\n * The pool is created with an empty book; pass explicit `pools` with a `seed`\n * (see `examples/deepbook-trader`) for pre-populated liquidity. */\nconst defaultLocalPools = (pkg: DeepbookPackageMember): ReadonlyArray<DeepbookPoolSpec> => [\n\t{\n\t\tname: 'DEEP_SUI',\n\t\tbase: { key: 'DEEP', coin: coinFromPackage(pkg, 'DEEP') },\n\t\tquote: { key: 'SUI', coin: builtinCoin('sui') },\n\t\ttickSize: 1_000_000n,\n\t\tlotSize: 1_000_000n,\n\t\tminSize: 10_000_000n,\n\t\twhitelisted: true,\n\t\tstablePool: false,\n\t},\n];\n\n/** Fail-fast guard for local mode: `publisher` and `package` are REQUIRED — a\n * publish tx needs a signer and the DeepBook Move package must be published\n * (capturing `registry::Registry` + `registry::DeepbookAdminCap`). `pools` is\n * OPTIONAL: omit it for a default unseeded (empty-book) `DEEP/SUI` pool (a\n * minimal usable DeX), pass `[]` for a pool-less deployment, or declare your own. `pyth`\n * stays optional (omit for a feed-less DeX). Missing a required field raises a\n * tagged `DeepbookConfigError` naming what to pass. */\nconst resolveLocalOptions = (\n\topts: DeepbookLocalOptions<\n\t\tAccountMemberAlias,\n\t\tDeepbookPackageMember,\n\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\tPythOptions | undefined\n\t>,\n): ResolvedLocalOptions => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst missing: string[] = [];\n\tif (!opts.publisher) {\n\t\tmissing.push('publisher');\n\t}\n\tif (!opts.package) {\n\t\tmissing.push('package');\n\t}\n\tif (missing.length > 0) {\n\t\tthrow deepbookConfigError(\n\t\t\tmissing[0] as string,\n\t\t\t`deepbook({mode:'local', name:'${name}'}) requires explicit ${missing.join(', ')}.`,\n\t\t\t`Publish the DeepBook Move package and pass at least { publisher, package } ` +\n\t\t\t\t`(see examples/deepbook-trader). Pools default to an unseeded (empty-book) DEEP/SUI pool.`,\n\t\t);\n\t}\n\t// Default to a single unseeded (empty-book) DEEP/SUI pool when none are declared.\n\tconst pools = opts.pools ?? defaultLocalPools(opts.package);\n\treturn { ...opts, pools } as ResolvedLocalOptions;\n};\n\nconst buildLocalPlugin = <\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\trawOpts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n) => {\n\tconst opts = resolveLocalOptions(\n\t\trawOpts as DeepbookLocalOptions<\n\t\t\tAccountMemberAlias,\n\t\t\tDeepbookPackageMember,\n\t\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\t\tPythOptions | undefined\n\t\t>,\n\t);\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tassertUniquePoolNames(name, opts.pools);\n\n\tconst deepbookResource = makeDeepbookResource(name);\n\t// Runtime `dependsOn` carries the caller's explicit member refs so\n\t// `defineDevstack`'s dependency-closure expander pulls the publisher /\n\t// package / coin / pyth members into the stack. The STATIC type stays keyed\n\t// to the caller's narrow generics so explicit callers keep their exact\n\t// closure (no generic `coin:`/`package:` provider demands).\n\tconst dependsOn = localDependsOn(opts) as unknown as LocalDependsOn<\n\t\tPublisher,\n\t\tPackage,\n\t\tPools,\n\t\tPyth\n\t>;\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Stack-free codegen: a local deployment's ids / pools / pyth feeds\n\t\t// are LOADED CONFIG DATA -- the committed `deepbook.ts` stub emits\n\t\t// `resolveValue('deepbook:<name>', '<key>')`, never a baked id.\n\t\tstaticCodegen: () => [makeDeepbookStaticCodegen({ name, network: LOCAL_NETWORK_NAME })],\n\t\t// `deps` auto-infers from the runtime-built `dependsOn`; it\n\t\t// resolves to a heterogeneous tuple the body re-narrows via the\n\t\t// `as unknown as` cast below. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst [sui, publisher, deepbookPackage, ...extraValues] = deps as unknown as readonly [\n\t\t\t\t\tResourceValueOf<typeof suiResource>,\n\t\t\t\t\tAccountValue,\n\t\t\t\t\tLocalPackageResolved,\n\t\t\t\t\t...(AccountValue | LocalPackageResolved | CoinValue)[],\n\t\t\t\t];\n\t\t\t\tconst pythValueCount = opts.pyth === undefined ? 0 : 2;\n\t\t\t\tconst pythValues = extraValues.slice(0, pythValueCount);\n\t\t\t\tconst coinValues = extraValues.slice(pythValueCount) as CoinValue[];\n\n\t\t\t\tyield* setCurrentPluginPhase('reading deployment captures');\n\n\t\t\t\tconst registryId = yield* requireCapturedId(\n\t\t\t\t\tdeepbookPackage,\n\t\t\t\t\topts.registryIdKey ?? 'registryId',\n\t\t\t\t\t'registryId',\n\t\t\t\t);\n\t\t\t\tconst adminCapId = yield* requireCapturedId(\n\t\t\t\t\tdeepbookPackage,\n\t\t\t\t\topts.adminCapIdKey ?? 'adminCapId',\n\t\t\t\t\t'adminCapId',\n\t\t\t\t);\n\t\t\t\tconst deepTreasuryId =\n\t\t\t\t\topts.deepTreasuryIdKey === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: (deepbookPackage.captured[opts.deepTreasuryIdKey] ?? null);\n\t\t\t\tconst deployment: DeepbookDeployment = {\n\t\t\t\t\tpackageId: deepbookPackage.packageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tadminCapId,\n\t\t\t\t\tdeepTreasuryId,\n\t\t\t\t};\n\t\t\t\tconst poolRefs = poolCoinRefs(opts.pools);\n\t\t\t\tconst coinValuesByRefId = new Map<string, CoinValue>();\n\t\t\t\tfor (let i = 0; i < poolRefs.length; i += 1) {\n\t\t\t\t\tconst ref = poolRefs[i];\n\t\t\t\t\tconst value = coinValues[i];\n\t\t\t\t\tif (ref !== undefined && value !== undefined) {\n\t\t\t\t\t\tcoinValuesByRefId.set(ref.id, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst poolSpecs = yield* resolvePoolSpecs(opts.pools, coinValuesByRefId);\n\t\t\t\tconst artifactPublisher = yield* CacheService;\n\t\t\t\tyield* setCurrentPluginPhase(\n\t\t\t\t\topts.pyth === undefined ? 'creating pools' : 'initializing Pyth feeds',\n\t\t\t\t);\n\t\t\t\tconst pyth =\n\t\t\t\t\topts.pyth === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: yield* initLocalPythFeeds(\n\t\t\t\t\t\t\t\tartifactPublisher,\n\t\t\t\t\t\t\t\tsui.sdk,\n\t\t\t\t\t\t\t\tsui.chainId,\n\t\t\t\t\t\t\t\tpythValues[0] as AccountValue,\n\t\t\t\t\t\t\t\t{ packageId: (pythValues[1] as LocalPackageResolved).packageId },\n\t\t\t\t\t\t\t\topts.pyth.feeds,\n\t\t\t\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase('creating pools');\n\t\t\t\tconst poolResult = yield* createDeepbookPools(\n\t\t\t\t\tartifactPublisher,\n\t\t\t\t\tsui.sdk,\n\t\t\t\t\tsui.chainId,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tdeployment,\n\t\t\t\t\tpoolSpecs,\n\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase('seeding pools');\n\t\t\t\tconst seedResults = yield* seedDeepbookPools(\n\t\t\t\t\tartifactPublisher,\n\t\t\t\t\tsui.sdk,\n\t\t\t\t\tsui.chainId,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tdeployment,\n\t\t\t\t\tpoolSpecs,\n\t\t\t\t\tpoolResult.pools,\n\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase(null);\n\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'local',\n\t\t\t\t\tnetwork: identity.network,\n\t\t\t\t\tpackageId: deployment.packageId,\n\t\t\t\t\tregistryId: deployment.registryId,\n\t\t\t\t\tadminCapId: deployment.adminCapId,\n\t\t\t\t\tdeepTreasuryId,\n\t\t\t\t\tpools: poolResult.pools,\n\t\t\t\t\tpyth,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\tmarketMakerRunning: seedResults.length > 0,\n\t\t\t\t\tdeepFundingStrategy: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen. `resolved` is\n\t\t\t\t// the just-computed value; the snapshotable is the local-mode\n\t\t\t\t// `deepbook/<name>` subtree. No DEEP funding (null in local).\n\t\t\t\tconst snap: SnapshotableDecl = makeLocalSnapshotable({ name });\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: resolved.adminCapId,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: resolved.pools.map((p) => ({\n\t\t\t\t\t\tname: p.name,\n\t\t\t\t\t\tpoolId: p.poolId,\n\t\t\t\t\t\tbase: p.base,\n\t\t\t\t\t\tquote: p.quote,\n\t\t\t\t\t\tbaseCoinType: p.baseCoinType,\n\t\t\t\t\t\tquoteCoinType: p.quoteCoinType,\n\t\t\t\t\t})),\n\t\t\t\t\tpyth: resolved.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: resolved.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: resolved.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: resolved.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: resolved.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tmargin: resolved.margin,\n\t\t\t\t\tserverUrl: resolved.serverUrl,\n\t\t\t\t\tindexerUrl: resolved.indexerUrl,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\treturn resolved;\n\t\t\t}).pipe(\n\t\t\t\t// The body's aggregate E channel includes substrate Effects\n\t\t\t\t// whose error shape is unknown to TS (ArtifactPublisher\n\t\t\t\t// produce bodies, dependency reads). `Effect.catchTags`\n\t\t\t\t// would need a statically-known tagged union; the\n\t\t\t\t// substrate's `passthroughOrWrap` runtime-checks the `_tag`\n\t\t\t\t// against `DEEPBOOK_ERROR_TAGS`, passing typed deepbook\n\t\t\t\t// errors through untouched and wrapping everything else\n\t\t\t\t// under `'publish'` so cascade attribution stays with the\n\t\t\t\t// plugin.\n\t\t\t\tpassthroughOrWrap.for<DeepbookError>()(DEEPBOOK_ERROR_TAGS, (err) =>\n\t\t\t\t\tdeepbookPluginError('publish', `deepbook acquire failed: ${String(err)}`, {\n\t\t\t\t\t\tcause: err,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t});\n};\n\nfunction buildLocalPluginPublic<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec>,\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nfunction buildLocalPluginPublic<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec>,\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(opts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>) {\n\treturn buildLocalPlugin(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Plugin construction — known\n// ---------------------------------------------------------------------------\n\nconst buildKnownPlugin = (opts: DeepbookKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst known = opts.network ? KNOWN_DEEPBOOK_DEPLOYMENTS[opts.network] : null;\n\tconst packageId = opts.packageId ?? known?.packageId;\n\tconst registryId = opts.registryId ?? known?.registryId;\n\tif (!packageId || !registryId) {\n\t\tthrow deepbookConfigError(\n\t\t\t'packageId',\n\t\t\t`deepbook({mode:'known', name:'${name}'}) requires packageId and registryId, or network:'mainnet'|'testnet'.`,\n\t\t\t`Pass explicit ids or use deepbook({mode:'known', network:'testnet'}).`,\n\t\t);\n\t}\n\tconst deepbookResource = makeDeepbookResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn: [suiResource] as const,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Known mode's deployment ids (package / registry / deep-treasury) and\n\t\t// its declared testnet/mainnet Pyth ids are DECLARED config — bake them\n\t\t// as literals in the committed tree (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeDeepbookStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tnetwork: opts.network ?? known?.network ?? LOCAL_NETWORK_NAME,\n\t\t\t\tknown: {\n\t\t\t\t\tpackageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tdeepTreasuryId: known?.deepTreasuryId ?? null,\n\t\t\t\t\tpyth: known?.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: known.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: known.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: known.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: known.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// `deps` auto-infers the resolved `[sui]` tuple from the\n\t\t// `[suiResource] as const` dependency. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst [sui] = deps;\n\t\t\t\tconst network = opts.network ?? known?.network ?? identity.network;\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'known',\n\t\t\t\t\tnetwork,\n\t\t\t\t\tpackageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tadminCapId: null,\n\t\t\t\t\tdeepTreasuryId: known?.deepTreasuryId ?? null,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: known?.pyth ?? null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\tmarketMakerRunning: false,\n\t\t\t\t\t// DEEP funding is a testnet-deepbook concern — gate on the\n\t\t\t\t\t// network name alone. (The old `&& String(chain) === 'sui:testnet'`\n\t\t\t\t\t// conjunct compared a genesis-digest chainId against a network\n\t\t\t\t\t// literal and was dead for every non-literal `chain` value.)\n\t\t\t\t\tdeepFundingStrategy:\n\t\t\t\t\t\topts.network === 'testnet'\n\t\t\t\t\t\t\t? makeDeepbookDeepFundingStrategy({ suiSdk: sui.sdk })\n\t\t\t\t\t\t\t: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen -> (optional\n\t\t\t\t// DEEP funding strategy). `resolved` is the just-computed value;\n\t\t\t\t// `snap` is the known-mode identity-guard snapshotable in scope.\n\t\t\t\t// The DEEP funding contributor is emitted only when\n\t\t\t\t// `resolved.deepFundingStrategy` is non-null.\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: null,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: resolved.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: resolved.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: resolved.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: resolved.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: resolved.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\tif (resolved.deepFundingStrategy != null) {\n\t\t\t\t\tctx.provides(makeDeepbookDeepFundingContribution(resolved.deepFundingStrategy));\n\t\t\t\t}\n\t\t\t\treturn resolved;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// Default option resolution (env-driven)\n// ---------------------------------------------------------------------------\n\nconst resolveDefaultMode = <\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts?: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookOptions<Publisher, Pyth> => {\n\tconst env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process\n\t\t?.env?.DEVSTACK_NETWORK;\n\tif (env === undefined || env === 'localnet') {\n\t\t// Local DeepBook: default to local mode on localnet. The caller must\n\t\t// supply explicit `{ publisher, package, pools }`; `resolveLocalOptions`\n\t\t// fails fast otherwise (no auto-synthesis).\n\t\treturn { mode: 'local', ...opts } as DeepbookOptions<Publisher, Pyth>;\n\t}\n\t// Non-local default: refuse — known mode requires explicit\n\t// packageId/registryId. The user passes them via\n\t// `deepbookFor(network).known({...})` or `deepbook({mode:'known',...})`.\n\tthrow deepbookConfigError(\n\t\t'mode',\n\t\t`deepbook(): cannot auto-default to known mode on network='${env}'.`,\n\t\t`Use deepbookFor(network).known({packageId, registryId, ...}).`,\n\t);\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Env-driven factory. Defaults to local mode on localnet when passed local\n * options. Explicit `override` and `known` modes bypass env inference. */\ntype DeepbookLocalMember<\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined = undefined,\n> = ReturnType<typeof buildLocalPlugin<Publisher, Package, Pools, Pyth>>;\ntype DeepbookOverrideMember = ReturnType<typeof buildOverridePlugin>;\ntype DeepbookKnownMember = ReturnType<typeof buildKnownPlugin>;\n\n// Local DeepBook requires explicit `{ publisher, package, pools }`. There is\n// no zero-arg/synthesized overload — an under-specified call fails fast (see\n// `resolveLocalOptions`).\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: { readonly mode: 'local' } & DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nexport function deepbookCore(\n\topts: { readonly mode: 'override' } & DeepbookOverrideOptions,\n): DeepbookOverrideMember;\nexport function deepbookCore(\n\topts: { readonly mode: 'known' } & DeepbookKnownOptions,\n): DeepbookKnownMember;\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts?: DeepbookLocalOptions<Publisher, Package, Pools, Pyth> | DeepbookOptions<Publisher, Pyth>,\n):\n\t| DeepbookLocalMember<Publisher, Package, Pools, Pyth>\n\t| DeepbookOverrideMember\n\t| DeepbookKnownMember {\n\tconst resolved: DeepbookOptions<Publisher, Pyth> =\n\t\topts !== undefined && 'mode' in opts\n\t\t\t? (opts as DeepbookOptions<Publisher, Pyth>)\n\t\t\t: resolveDefaultMode(\n\t\t\t\t\topts as DeepbookLocalOptions<Publisher, Package, Pools, Pyth> | undefined,\n\t\t\t\t);\n\tswitch (resolved.mode) {\n\t\tcase 'local': {\n\t\t\tconst localOpts = resolved as { readonly mode: 'local' } & DeepbookLocalOptions<\n\t\t\t\tPublisher,\n\t\t\t\tPackage,\n\t\t\t\tPools,\n\t\t\t\tPyth\n\t\t\t>;\n\t\t\t// Explicit-config path only; `buildLocalPlugin` -> `resolveLocalOptions`\n\t\t\t// fails fast when `publisher`/`package`/`pools` are missing.\n\t\t\treturn buildLocalPluginPublic(localOpts) as DeepbookLocalMember<\n\t\t\t\tPublisher,\n\t\t\t\tPackage,\n\t\t\t\tPools,\n\t\t\t\tPyth\n\t\t\t>;\n\t\t}\n\t\tcase 'override':\n\t\t\treturn buildOverridePlugin(resolved);\n\t\tcase 'known':\n\t\t\treturn buildKnownPlugin(resolved);\n\t}\n}\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local', network: 'localnet' } as const;\n * deepbookFor(local).local({publisher, package, pools}) // OK\n * deepbookFor(local).override({packageId, registryId, adminCapId}) // OK\n * deepbookFor(local).known({...}) // OK\n *\n * const fork = { mode: 'fork', network: 'mainnet-fork', upstream: 'mainnet' } as const;\n * deepbookFor(fork).local({...}) // COMPILE ERROR\n * deepbookFor(fork).override({...}) // COMPILE ERROR\n *\n * The fork branch has NO `.local` or `.override` entry — `deepbookFor(forkNetwork).local`\n * is a compile-time refusal. */\nexport const deepbookFor = defineModeNamespace({\n\tlocal: {\n\t\tlocal: <\n\t\t\tconst Publisher extends AccountMemberAlias,\n\t\t\tconst Package extends DeepbookPackageMember,\n\t\t\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\t\t\tconst Pyth extends PythOptions | undefined = undefined,\n\t\t>(\n\t\t\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n\t\t) => buildLocalPluginPublic(opts),\n\t\toverride: (opts: DeepbookOverrideOptions) => buildOverridePlugin(opts),\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n\tlive: {\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n\tfork: {\n\t\t// `.override` intentionally absent — compile-time refusal.\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n});\n\nexport { deepbookCore as deepbook };\n\n// ---------------------------------------------------------------------------\n// Re-exports for advanced callers\n// ---------------------------------------------------------------------------\n\nexport {\n\tDEEPBOOK_DEEP_FAUCET_STRATEGY_KEY,\n\tDEEPBOOK_TESTNET_DEEP_COIN_TYPE,\n} from './faucet-strategy.ts';\nexport {\n\ttype DeepbookError,\n\ttype DeepbookPluginError,\n\ttype DeepbookConfigError,\n\ttype DeepbookPhase,\n} from './errors.ts';\nexport type { DeepbookBindings } from './codegen.ts';\nexport type {\n\tAccountMemberAlias,\n\tCoinMemberAlias,\n\tDeepbookPackageMember,\n\tDeepbookPool,\n\tDeepbookPoolCoin,\n\tDeepbookPoolSeedLiquidity,\n\tDeepbookPoolSeedOrder,\n\tDeepbookPoolSpec,\n} from './types.ts';\nexport {\n\tDEEP_PRICE_FEED_ID,\n\tpythPriceFeedId,\n\tSUI_PRICE_FEED_ID,\n\tUSDC_PRICE_FEED_ID,\n} from './types.ts';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["coinFromPackage","builtinCoin","localOpts"],"sources":["../../../src/plugins/deepbook/index.ts"],"sourcesContent":["// Deepbook plugin — barrel + factories.\n//\n// Architecture: Deepbook is a task plugin that resolves a managed\n// local deployment, a known deployment, or explicit caller-supplied\n// override ids, then emits bindings.\n//\n// Mode discipline:\n//\n// - `deepbook(opts)` — explicit mode selection.\n// Localnet can default to local when\n// passed local options.\n// - `deepbookFor(network).local` — local-branch managed deployment.\n// - `deepbookFor(network).override` — local-branch override for\n// caller-supplied deployment ids.\n// - `deepbookFor(network).known` — known-deployment branch (live +\n// fork networks; wraps an already-\n// deployed canonical instance).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// Local mode:\n// 1. `ctx.snapshotExtra` — `deepbook/<name>` subtree.\n// 2. `ctx.codegen` — `deepbook-network` bindings.\n//\n// Override mode:\n// 1. `ctx.snapshotExtra` — identity guard only.\n// 2. `ctx.codegen` — `deepbook-network` bindings.\n//\n// Known mode:\n// 1. `ctx.snapshotExtra` — identity guard only.\n// 2. `ctx.codegen` — `deepbook-network` bindings (mode='known').\n//\n// Resource id: `deepbook/<name>`. Plugin key: `deepbook:<name>`.\n\nimport { Effect } from 'effect';\n\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { definePlugin, resource, type ResourceValueOf } from '../../api/define-plugin.ts';\nimport type { SnapshotableDecl } from '../../contracts/snapshotable.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { setCurrentPluginPhase } from '../../substrate/runtime/current-plugin.ts';\nimport { passthroughOrWrap } from '../../substrate/runtime/passthrough-or-wrap.ts';\nimport { IdentityContext } from '../../substrate/runtime/paths.ts';\nimport { suiResource } from '../sui/index.ts';\nimport type { AccountValue } from '../account/index.ts';\nimport {\n\tbuiltin as builtinCoin,\n\tfromPackage as coinFromPackage,\n\ttype CoinValue,\n} from '../coin/index.ts';\nimport type { LocalPackageResolved } from '../package/index.ts';\n\nimport { deepbookPluginKey } from './plugin-key.ts';\nimport {\n\tDEEPBOOK_ERROR_TAGS,\n\tdeepbookConfigError,\n\tdeepbookPluginError,\n\ttype DeepbookConfigError,\n\ttype DeepbookError,\n\ttype DeepbookPluginError,\n} from './errors.ts';\nimport {\n\tmakeDeepbookCodegenable,\n\tmakeDeepbookStaticCodegen,\n\ttype DeepbookBindings,\n} from './codegen.ts';\nimport { LOCAL_NETWORK_NAME } from '../../api/inference-network.ts';\nimport {\n\tmakeDeepbookDeepFundingContribution,\n\tmakeDeepbookDeepFundingStrategy,\n\ttype DeepbookDeepFundingStrategy,\n} from './faucet-strategy.ts';\nimport { makeKnownSnapshotable, makeLocalSnapshotable } from './snapshot.ts';\nimport {\n\tcreateDeepbookPools,\n\tseedDeepbookPools,\n\ttype DeepbookDeployment,\n\ttype ResolvedDeepbookPoolSpec,\n} from './deploy.ts';\nimport { initLocalPythFeeds } from './pyth/index.ts';\nimport type {\n\tAccountMemberAlias,\n\tDeepbookPackageMember,\n\tDeepbookPool,\n\tDeepbookPoolSpec,\n\tPythHandle,\n\tPythOptions,\n} from './types.ts';\n\n// ---------------------------------------------------------------------------\n// Resource — the resolved value all consumers read\n// ---------------------------------------------------------------------------\n\nexport type DeepbookResourceId<Name extends string> = `deepbook/${Name}`;\n\nconst makeDeepbookResource = <Name extends string>(name: Name) =>\n\tresource<DeepbookResourceId<Name>, DeepbookResolved>(\n\t\t`deepbook/${name}` as DeepbookResourceId<Name>,\n\t);\n\n/** The deepbook resolved value. Mode-asymmetric:\n *\n * - `adminCapId` is `null` for known-deployment mode.\n * - `margin` / `serverUrl` / `indexerUrl` are `null` when the\n * corresponding sub-feature is not enabled.\n * - `hasSeedLiquidity` is `true` when one or more pools placed seed\n * orders at boot (it is NOT a market-maker process state). */\nexport interface DeepbookResolved {\n\treadonly mode: 'local' | 'override' | 'known';\n\treadonly network: string;\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly adminCapId: string | null;\n\treadonly deepTreasuryId: string | null;\n\treadonly pools: ReadonlyArray<DeepbookPool>;\n\treadonly pyth: PythHandle | null;\n\treadonly margin: {\n\t\treadonly packageId: string;\n\t\treadonly registryId: string;\n\t} | null;\n\treadonly serverUrl: string | null;\n\treadonly indexerUrl: string | null;\n\t/** `true` when one or more pools placed seed orders at boot. This reflects\n\t * \"a pool was seeded with liquidity\", NOT a running market-maker process. */\n\treadonly hasSeedLiquidity: boolean;\n\treadonly deepFundingStrategy: DeepbookDeepFundingStrategy | null;\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface DeepbookCommonOptions {\n\treadonly name?: string;\n}\n\n/** Override mode wraps an explicitly supplied deployment. It does not\n * publish or manage DeepBook locally. */\nexport interface DeepbookOverrideOptions extends DeepbookCommonOptions {\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly adminCapId: string;\n\treadonly network?: string;\n}\n\n/** Local mode wraps an explicitly supplied local DeepBook package.\n *\n * Explicit-config discipline: `publisher`, `package`, and `pools` are all\n * REQUIRED — the caller publishes the DeepBook Move tree, funds a publisher,\n * and declares the pools. There is no zero-arg auto-synthesis; an\n * under-specified `deepbook({ mode: 'local' })` fails fast with a tagged\n * config error (see the guard in `resolveLocalOptions`). `pyth` stays\n * optional — pass it to seed local mock price feeds, omit it for a\n * feed-less DeX. */\nexport interface DeepbookLocalOptions<\n\tPublisher extends AccountMemberAlias = AccountMemberAlias,\n\tPackage extends DeepbookPackageMember = DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tPyth extends PythOptions | undefined = undefined,\n> extends DeepbookCommonOptions {\n\t/** Publisher account — Direct Member Ref (locked API decision). Required. */\n\treadonly publisher: Publisher;\n\t/** Published DeepBook package member. The package must capture the\n\t * `registry::Registry` and `registry::DeepbookAdminCap` object ids.\n\t * Required. */\n\treadonly package: Package;\n\t/** Optional local mock-Pyth package + feed setup. Omit for a feed-less\n\t * local DeX. */\n\treadonly pyth?: Pyth;\n\t/** Capture key for the package-created `registry::Registry`. */\n\treadonly registryIdKey?: string;\n\t/** Capture key for the package-created `registry::DeepbookAdminCap`. */\n\treadonly adminCapIdKey?: string;\n\t/** Optional capture key for a DEEP treasury object used by SDK bindings. */\n\treadonly deepTreasuryIdKey?: string;\n\t/** Pools to create after the DeepBook package publishes. OPTIONAL: when\n\t * omitted, a single unseeded (empty-book) `DEEP/SUI` pool is synthesized\n\t * (the DEEP coin comes from `package`, SUI is built-in — no extra package\n\t * needed), so a minimal `deepbook({ mode:'local', publisher, package })`\n\t * boots a usable DeX. Pass `[]` explicitly for a known-empty deployment, or your own\n\t * pools for full control. */\n\treadonly pools?: Pools;\n}\n\nexport type DeepbookKnownNetwork = 'mainnet' | 'testnet';\n\ninterface DeepbookKnownCommonOptions extends DeepbookCommonOptions {\n\t/** Optional network override (defaults to the configured network). */\n\treadonly network?: string;\n}\n\ninterface DeepbookKnownNetworkOptions extends DeepbookKnownCommonOptions {\n\treadonly network: DeepbookKnownNetwork;\n\treadonly packageId?: string;\n\treadonly registryId?: string;\n}\n\ninterface DeepbookKnownExplicitOptions extends DeepbookKnownCommonOptions {\n\treadonly packageId: string;\n\treadonly registryId: string;\n\treadonly network?: DeepbookKnownNetwork;\n}\n\nexport type DeepbookKnownOptions = DeepbookKnownNetworkOptions | DeepbookKnownExplicitOptions;\n\nexport type DeepbookOptions<\n\tPublisher extends AccountMemberAlias = AccountMemberAlias,\n\tPyth extends PythOptions | undefined = PythOptions | undefined,\n> =\n\t| ({\n\t\t\treadonly mode: 'local';\n\t } & DeepbookLocalOptions<\n\t\t\tPublisher,\n\t\t\tDeepbookPackageMember,\n\t\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\t\tPyth\n\t >)\n\t| ({ readonly mode: 'override' } & DeepbookOverrideOptions)\n\t| ({ readonly mode: 'known' } & DeepbookKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction — override\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_NAME = 'deepbook';\n\nconst KNOWN_DEEPBOOK_DEPLOYMENTS: Record<\n\tDeepbookKnownNetwork,\n\t{\n\t\treadonly network: string;\n\t\treadonly packageId: string;\n\t\treadonly registryId: string;\n\t\treadonly deepTreasuryId: string;\n\t\treadonly pyth: PythHandle;\n\t}\n> = {\n\ttestnet: {\n\t\tnetwork: 'testnet',\n\t\tpackageId: '0x22be4cade64bf2d02412c7e8d0e8beea2f78828b948118d46735315409371a3c',\n\t\tregistryId: '0x7c256edbda983a2cd6f946655f4bf3f00a41043993781f8674a7046e8c0e11d1',\n\t\tdeepTreasuryId: '0x69fffdae0075f8f71f4fa793549c11079266910e8905169845af1f5d00e09dcb',\n\t\tpyth: {\n\t\t\tpackageId: null,\n\t\t\tstateId: '0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c',\n\t\t\twormholeStateId: '0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790',\n\t\t\tfeeds: [],\n\t\t},\n\t},\n\tmainnet: {\n\t\tnetwork: 'mainnet',\n\t\tpackageId: '0xf48222c4e057fa468baf136bff8e12504209d43850c5778f76159292a96f621e',\n\t\tregistryId: '0xaf16199a2dff736e9f07a845f23c5da6df6f756eddb631aed9d24a93efc4549d',\n\t\tdeepTreasuryId: '0x032abf8948dda67a271bcc18e776dbbcfb0d58c8d288a700ff0d5521e57a1ffe',\n\t\tpyth: {\n\t\t\tpackageId: null,\n\t\t\tstateId: '0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8',\n\t\t\twormholeStateId: '0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c',\n\t\t\tfeeds: [],\n\t\t},\n\t},\n};\n\ntype PoolCoinRefs<Pools extends ReadonlyArray<DeepbookPoolSpec>> =\n\tPools[number] extends DeepbookPoolSpec<infer Base, infer Quote> ? Base | Quote : never;\ntype PoolCoinRefTuple<Pools extends ReadonlyArray<DeepbookPoolSpec>> = Pools extends readonly []\n\t? readonly []\n\t: readonly PoolCoinRefs<Pools>[];\n\ntype PythRefs<Pyth extends PythOptions | undefined> =\n\tPyth extends PythOptions<infer Package, infer Pusher> ? readonly [Pusher, Package] : readonly [];\n\ntype LocalDependsOn<\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined,\n> = readonly [\n\ttypeof suiResource,\n\tPublisher,\n\tPackage,\n\t...PythRefs<Pyth>,\n\t...PoolCoinRefTuple<Pools>,\n];\n\nconst poolCoinRefs = <Pools extends ReadonlyArray<DeepbookPoolSpec>>(\n\tpools: Pools,\n): ReadonlyArray<PoolCoinRefs<Pools>> =>\n\tpools.flatMap((pool) => [pool.base.coin, pool.quote.coin]) as unknown as ReadonlyArray<\n\t\tPoolCoinRefs<Pools>\n\t>;\n\nconst pythRefs = <Pyth extends PythOptions | undefined>(pyth: Pyth): PythRefs<Pyth> =>\n\t(pyth === undefined ? [] : [pyth.pusher, pyth.package]) as unknown as PythRefs<Pyth>;\n\nconst localDependsOn = <\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): LocalDependsOn<Publisher, Package, Pools, Pyth> =>\n\t[\n\t\tsuiResource,\n\t\topts.publisher,\n\t\topts.package,\n\t\t...pythRefs(opts.pyth),\n\t\t...poolCoinRefs((opts.pools ?? []) as Pools),\n\t] as unknown as LocalDependsOn<Publisher, Package, Pools, Pyth>;\n\nconst requireCapturedId = (\n\tpkg: LocalPackageResolved,\n\tkey: string,\n\tkind: 'registryId' | 'adminCapId',\n): Effect.Effect<string, DeepbookPluginError> => {\n\tconst value = pkg.captured[key];\n\tif (typeof value === 'string' && value.length > 0) {\n\t\treturn Effect.succeed(value);\n\t}\n\treturn Effect.fail(\n\t\tdeepbookPluginError(\n\t\t\t'publish',\n\t\t\t`deepbook local package '${pkg.name}' is missing captured ${kind} '${key}'.`,\n\t\t),\n\t);\n};\n\nconst requirePoolCoinValue = (\n\tcoinValuesByRefId: ReadonlyMap<string, CoinValue>,\n\tpoolName: string,\n\tside: 'base' | 'quote',\n\tcoinRefId: string,\n): Effect.Effect<CoinValue, DeepbookConfigError> => {\n\tconst value = coinValuesByRefId.get(coinRefId);\n\tif (value === undefined) {\n\t\t// Compose-time bug — `dependsOn`/`poolCoinRefs` dropped this coin.\n\t\t// Surface a typed config error naming the missing coin id rather\n\t\t// than letting a double-cast `undefined` slip into the resolved\n\t\t// pool spec. Lands on the typed E channel (not a sync throw, which\n\t\t// inside Effect.gen would become an uncaught DEFECT that\n\t\t// `passthroughOrWrap` could not see); `DeepbookConfigError` is in\n\t\t// `DEEPBOOK_ERROR_TAGS`, so the outer pipeline passes it through\n\t\t// untouched.\n\t\treturn Effect.fail(\n\t\t\tdeepbookConfigError(\n\t\t\t\t'pools',\n\t\t\t\t`deepbook: pool '${poolName}' ${side} coin '${coinRefId}' was not resolved by the dependency tuple.`,\n\t\t\t\t'This is a compose-time bug — ensure the coin member is included in `dependsOn`/`poolCoinRefs`.',\n\t\t\t),\n\t\t);\n\t}\n\treturn Effect.succeed(value);\n};\n\nconst resolvePoolSpecs = (\n\tpools: ReadonlyArray<DeepbookPoolSpec>,\n\tcoinValuesByRefId: ReadonlyMap<string, CoinValue>,\n): Effect.Effect<ReadonlyArray<ResolvedDeepbookPoolSpec>, DeepbookConfigError> =>\n\tEffect.forEach(pools, (pool) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst base = yield* requirePoolCoinValue(\n\t\t\t\tcoinValuesByRefId,\n\t\t\t\tpool.name,\n\t\t\t\t'base',\n\t\t\t\tpool.base.coin.id,\n\t\t\t);\n\t\t\tconst quote = yield* requirePoolCoinValue(\n\t\t\t\tcoinValuesByRefId,\n\t\t\t\tpool.name,\n\t\t\t\t'quote',\n\t\t\t\tpool.quote.coin.id,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tname: pool.name,\n\t\t\t\tbase: pool.base.key,\n\t\t\t\tquote: pool.quote.key,\n\t\t\t\tbaseCoinType: base.fullCoinType,\n\t\t\t\tquoteCoinType: quote.fullCoinType,\n\t\t\t\t...(base.fundingStrategy === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { baseFundingStrategy: base.fundingStrategy }),\n\t\t\t\t...(quote.fundingStrategy === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { quoteFundingStrategy: quote.fundingStrategy }),\n\t\t\t\ttickSize: pool.tickSize,\n\t\t\t\tlotSize: pool.lotSize,\n\t\t\t\tminSize: pool.minSize,\n\t\t\t\twhitelisted: pool.whitelisted ?? true,\n\t\t\t\tstablePool: pool.stablePool ?? false,\n\t\t\t\t...(pool.seed === undefined ? {} : { seed: pool.seed }),\n\t\t\t};\n\t\t}),\n\t);\n\nconst assertUniquePoolNames = (name: string, pools: ReadonlyArray<DeepbookPoolSpec>) => {\n\tconst seen = new Set<string>();\n\tfor (const pool of pools) {\n\t\tif (seen.has(pool.name)) {\n\t\t\tthrow deepbookConfigError(\n\t\t\t\t'pools',\n\t\t\t\t`deepbook({mode:'local', name:'${name}'}) has duplicate pool '${pool.name}'.`,\n\t\t\t\t'Give each local DeepBook pool a unique SDK key.',\n\t\t\t);\n\t\t}\n\t\tseen.add(pool.name);\n\t\tfor (const order of pool.seed?.orders ?? []) {\n\t\t\tif (order.quantity < pool.minSize) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is below minSize.`,\n\t\t\t\t\t'Use a seed order quantity greater than or equal to the pool minSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (order.quantity % pool.lotSize !== 0n) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is not lot-aligned.`,\n\t\t\t\t\t'Use a seed order quantity divisible by the pool lotSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (order.price % pool.tickSize !== 0n) {\n\t\t\t\tthrow deepbookConfigError(\n\t\t\t\t\t'pools',\n\t\t\t\t\t`deepbook({mode:'local', name:'${name}'}) seed order for pool '${pool.name}' is not tick-aligned.`,\n\t\t\t\t\t'Use a seed order price divisible by the pool tickSize.',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst buildOverridePlugin = (opts: DeepbookOverrideOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tif (!opts.packageId || !opts.registryId || !opts.adminCapId) {\n\t\tthrow deepbookConfigError(\n\t\t\t'packageId',\n\t\t\t`deepbook({mode:'override', name:'${name}'}) requires packageId, registryId, and adminCapId.`,\n\t\t\t`Pass explicit deployment ids or use deepbook({mode:'known', network:'testnet'}).`,\n\t\t);\n\t}\n\tconst deepbookResource = makeDeepbookResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn: [suiResource] as const,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Override mode's deployment ids are DECLARED config — bake them as\n\t\t// literals in the committed tree (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeDeepbookStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tnetwork: opts.network ?? LOCAL_NETWORK_NAME,\n\t\t\t\tknown: {\n\t\t\t\t\tpackageId: opts.packageId,\n\t\t\t\t\tregistryId: opts.registryId,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// `deps` auto-infers the resolved `[sui]` tuple from the\n\t\t// `[suiResource] as const` dependency. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst network = opts.network ?? identity.network;\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'override',\n\t\t\t\t\tnetwork,\n\t\t\t\t\tpackageId: opts.packageId,\n\t\t\t\t\tregistryId: opts.registryId,\n\t\t\t\t\tadminCapId: opts.adminCapId,\n\t\t\t\t\tdeepTreasuryId: null,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\thasSeedLiquidity: false,\n\t\t\t\t\tdeepFundingStrategy: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen. `resolved` is\n\t\t\t\t// the just-computed value; `snap` is the override-mode\n\t\t\t\t// identity-guard snapshotable in scope. No DEEP funding.\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: resolved.adminCapId,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\treturn resolved;\n\t\t\t}),\n\t});\n};\n\n/** Concrete local options after the explicit-config guard: `publisher`,\n * `package`, and `pools` are guaranteed present. */\ntype ResolvedLocalOptions = DeepbookLocalOptions<\n\tAccountMemberAlias,\n\tDeepbookPackageMember,\n\tReadonlyArray<DeepbookPoolSpec>,\n\tPythOptions | undefined\n> & {\n\treadonly publisher: AccountMemberAlias;\n\treadonly package: DeepbookPackageMember;\n\treadonly pools: ReadonlyArray<DeepbookPoolSpec>;\n};\n\n/** Default local pool synthesized when `pools` is omitted: a single whitelisted\n * `DEEP/SUI` pool. DEEP is the deepbook package's own coin (no extra package to\n * publish), SUI is built-in, so this needs nothing beyond the `package` the\n * caller already passes — and NO seed, so it requires no DEEP minting (i.e. no\n * `deepTreasuryIdKey`) and works for a bare `deepbook({ publisher, package })`.\n * The pool is created with an empty book; pass explicit `pools` with a `seed`\n * (see `examples/deepbook-trader`) for pre-populated liquidity. */\nconst defaultLocalPools = (pkg: DeepbookPackageMember): ReadonlyArray<DeepbookPoolSpec> => [\n\t{\n\t\tname: 'DEEP_SUI',\n\t\tbase: { key: 'DEEP', coin: coinFromPackage(pkg, 'DEEP') },\n\t\tquote: { key: 'SUI', coin: builtinCoin('sui') },\n\t\ttickSize: 1_000_000n,\n\t\tlotSize: 1_000_000n,\n\t\tminSize: 10_000_000n,\n\t\twhitelisted: true,\n\t\tstablePool: false,\n\t},\n];\n\n/** Fail-fast guard for local mode: `publisher` and `package` are REQUIRED — a\n * publish tx needs a signer and the DeepBook Move package must be published\n * (capturing `registry::Registry` + `registry::DeepbookAdminCap`). `pools` is\n * OPTIONAL: omit it for a default unseeded (empty-book) `DEEP/SUI` pool (a\n * minimal usable DeX), pass `[]` for a pool-less deployment, or declare your own. `pyth`\n * stays optional (omit for a feed-less DeX). Missing a required field raises a\n * tagged `DeepbookConfigError` naming what to pass. */\nconst resolveLocalOptions = (\n\topts: DeepbookLocalOptions<\n\t\tAccountMemberAlias,\n\t\tDeepbookPackageMember,\n\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\tPythOptions | undefined\n\t>,\n): ResolvedLocalOptions => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst missing: string[] = [];\n\tif (!opts.publisher) {\n\t\tmissing.push('publisher');\n\t}\n\tif (!opts.package) {\n\t\tmissing.push('package');\n\t}\n\tif (missing.length > 0) {\n\t\tthrow deepbookConfigError(\n\t\t\tmissing[0] as string,\n\t\t\t`deepbook({mode:'local', name:'${name}'}) requires explicit ${missing.join(', ')}.`,\n\t\t\t`Publish the DeepBook Move package and pass at least { publisher, package } ` +\n\t\t\t\t`(see examples/deepbook-trader). Pools default to an unseeded (empty-book) DEEP/SUI pool.`,\n\t\t);\n\t}\n\t// Default to a single unseeded (empty-book) DEEP/SUI pool when none are declared.\n\tconst pools = opts.pools ?? defaultLocalPools(opts.package);\n\treturn { ...opts, pools } as ResolvedLocalOptions;\n};\n\nconst buildLocalPlugin = <\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\trawOpts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n) => {\n\tconst opts = resolveLocalOptions(\n\t\trawOpts as DeepbookLocalOptions<\n\t\t\tAccountMemberAlias,\n\t\t\tDeepbookPackageMember,\n\t\t\tReadonlyArray<DeepbookPoolSpec>,\n\t\t\tPythOptions | undefined\n\t\t>,\n\t);\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tassertUniquePoolNames(name, opts.pools);\n\n\tconst deepbookResource = makeDeepbookResource(name);\n\t// Runtime `dependsOn` carries the caller's explicit member refs so\n\t// `defineDevstack`'s dependency-closure expander pulls the publisher /\n\t// package / coin / pyth members into the stack. The STATIC type stays keyed\n\t// to the caller's narrow generics so explicit callers keep their exact\n\t// closure (no generic `coin:`/`package:` provider demands).\n\tconst dependsOn = localDependsOn(opts) as unknown as LocalDependsOn<\n\t\tPublisher,\n\t\tPackage,\n\t\tPools,\n\t\tPyth\n\t>;\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Stack-free codegen: a local deployment's ids / pools / pyth feeds\n\t\t// are LOADED CONFIG DATA -- the committed `deepbook.ts` stub emits\n\t\t// `resolveValue('deepbook:<name>', '<key>')`, never a baked id.\n\t\tstaticCodegen: () => [makeDeepbookStaticCodegen({ name, network: LOCAL_NETWORK_NAME })],\n\t\t// `deps` auto-infers from the runtime-built `dependsOn`; it\n\t\t// resolves to a heterogeneous tuple the body re-narrows via the\n\t\t// `as unknown as` cast below. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst [sui, publisher, deepbookPackage, ...extraValues] = deps as unknown as readonly [\n\t\t\t\t\tResourceValueOf<typeof suiResource>,\n\t\t\t\t\tAccountValue,\n\t\t\t\t\tLocalPackageResolved,\n\t\t\t\t\t...(AccountValue | LocalPackageResolved | CoinValue)[],\n\t\t\t\t];\n\t\t\t\tconst pythValueCount = opts.pyth === undefined ? 0 : 2;\n\t\t\t\tconst pythValues = extraValues.slice(0, pythValueCount);\n\t\t\t\tconst coinValues = extraValues.slice(pythValueCount) as CoinValue[];\n\n\t\t\t\tyield* setCurrentPluginPhase('reading deployment captures');\n\n\t\t\t\tconst registryId = yield* requireCapturedId(\n\t\t\t\t\tdeepbookPackage,\n\t\t\t\t\topts.registryIdKey ?? 'registryId',\n\t\t\t\t\t'registryId',\n\t\t\t\t);\n\t\t\t\tconst adminCapId = yield* requireCapturedId(\n\t\t\t\t\tdeepbookPackage,\n\t\t\t\t\topts.adminCapIdKey ?? 'adminCapId',\n\t\t\t\t\t'adminCapId',\n\t\t\t\t);\n\t\t\t\tconst deepTreasuryId =\n\t\t\t\t\topts.deepTreasuryIdKey === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: (deepbookPackage.captured[opts.deepTreasuryIdKey] ?? null);\n\t\t\t\tconst deployment: DeepbookDeployment = {\n\t\t\t\t\tpackageId: deepbookPackage.packageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tadminCapId,\n\t\t\t\t\tdeepTreasuryId,\n\t\t\t\t};\n\t\t\t\tconst poolRefs = poolCoinRefs(opts.pools);\n\t\t\t\tconst coinValuesByRefId = new Map<string, CoinValue>();\n\t\t\t\tfor (let i = 0; i < poolRefs.length; i += 1) {\n\t\t\t\t\tconst ref = poolRefs[i];\n\t\t\t\t\tconst value = coinValues[i];\n\t\t\t\t\tif (ref !== undefined && value !== undefined) {\n\t\t\t\t\t\tcoinValuesByRefId.set(ref.id, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst poolSpecs = yield* resolvePoolSpecs(opts.pools, coinValuesByRefId);\n\t\t\t\tconst artifactPublisher = yield* CacheService;\n\t\t\t\tyield* setCurrentPluginPhase(\n\t\t\t\t\topts.pyth === undefined ? 'creating pools' : 'initializing Pyth feeds',\n\t\t\t\t);\n\t\t\t\tconst pyth =\n\t\t\t\t\topts.pyth === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: yield* initLocalPythFeeds(\n\t\t\t\t\t\t\t\tartifactPublisher,\n\t\t\t\t\t\t\t\tsui.sdk,\n\t\t\t\t\t\t\t\tsui.chainId,\n\t\t\t\t\t\t\t\tpythValues[0] as AccountValue,\n\t\t\t\t\t\t\t\t{ packageId: (pythValues[1] as LocalPackageResolved).packageId },\n\t\t\t\t\t\t\t\topts.pyth.feeds,\n\t\t\t\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase('creating pools');\n\t\t\t\tconst poolResult = yield* createDeepbookPools(\n\t\t\t\t\tartifactPublisher,\n\t\t\t\t\tsui.sdk,\n\t\t\t\t\tsui.chainId,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tdeployment,\n\t\t\t\t\tpoolSpecs,\n\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase('seeding pools');\n\t\t\t\tconst seedResults = yield* seedDeepbookPools(\n\t\t\t\t\tartifactPublisher,\n\t\t\t\t\tsui.sdk,\n\t\t\t\t\tsui.chainId,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tdeployment,\n\t\t\t\t\tpoolSpecs,\n\t\t\t\t\tpoolResult.pools,\n\t\t\t\t);\n\t\t\t\tyield* setCurrentPluginPhase(null);\n\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'local',\n\t\t\t\t\tnetwork: identity.network,\n\t\t\t\t\tpackageId: deployment.packageId,\n\t\t\t\t\tregistryId: deployment.registryId,\n\t\t\t\t\tadminCapId: deployment.adminCapId,\n\t\t\t\t\tdeepTreasuryId,\n\t\t\t\t\tpools: poolResult.pools,\n\t\t\t\t\tpyth,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\thasSeedLiquidity: seedResults.length > 0,\n\t\t\t\t\tdeepFundingStrategy: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen. `resolved` is\n\t\t\t\t// the just-computed value; the snapshotable is the local-mode\n\t\t\t\t// `deepbook/<name>` subtree. No DEEP funding (null in local).\n\t\t\t\tconst snap: SnapshotableDecl = makeLocalSnapshotable({ name });\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: resolved.adminCapId,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: resolved.pools.map((p) => ({\n\t\t\t\t\t\tname: p.name,\n\t\t\t\t\t\tpoolId: p.poolId,\n\t\t\t\t\t\tbase: p.base,\n\t\t\t\t\t\tquote: p.quote,\n\t\t\t\t\t\tbaseCoinType: p.baseCoinType,\n\t\t\t\t\t\tquoteCoinType: p.quoteCoinType,\n\t\t\t\t\t})),\n\t\t\t\t\tpyth: resolved.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: resolved.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: resolved.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: resolved.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: resolved.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tmargin: resolved.margin,\n\t\t\t\t\tserverUrl: resolved.serverUrl,\n\t\t\t\t\tindexerUrl: resolved.indexerUrl,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\treturn resolved;\n\t\t\t}).pipe(\n\t\t\t\t// The body's aggregate E channel includes substrate Effects\n\t\t\t\t// whose error shape is unknown to TS (ArtifactPublisher\n\t\t\t\t// produce bodies, dependency reads). `Effect.catchTags`\n\t\t\t\t// would need a statically-known tagged union; the\n\t\t\t\t// substrate's `passthroughOrWrap` runtime-checks the `_tag`\n\t\t\t\t// against `DEEPBOOK_ERROR_TAGS`, passing typed deepbook\n\t\t\t\t// errors through untouched and wrapping everything else\n\t\t\t\t// under `'publish'` so cascade attribution stays with the\n\t\t\t\t// plugin.\n\t\t\t\tpassthroughOrWrap.for<DeepbookError>()(DEEPBOOK_ERROR_TAGS, (err) =>\n\t\t\t\t\tdeepbookPluginError('publish', `deepbook acquire failed: ${String(err)}`, {\n\t\t\t\t\t\tcause: err,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t});\n};\n\nfunction buildLocalPluginPublic<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec>,\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nfunction buildLocalPluginPublic<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec>,\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(opts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>) {\n\treturn buildLocalPlugin(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Plugin construction — known\n// ---------------------------------------------------------------------------\n\nconst buildKnownPlugin = (opts: DeepbookKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst known = opts.network ? KNOWN_DEEPBOOK_DEPLOYMENTS[opts.network] : null;\n\tconst packageId = opts.packageId ?? known?.packageId;\n\tconst registryId = opts.registryId ?? known?.registryId;\n\tif (!packageId || !registryId) {\n\t\tthrow deepbookConfigError(\n\t\t\t'packageId',\n\t\t\t`deepbook({mode:'known', name:'${name}'}) requires packageId and registryId, or network:'mainnet'|'testnet'.`,\n\t\t\t`Pass explicit ids or use deepbook({mode:'known', network:'testnet'}).`,\n\t\t);\n\t}\n\tconst deepbookResource = makeDeepbookResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: deepbookResource.id,\n\t\tdependsOn: [suiResource] as const,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tpluginKey: deepbookPluginKey(name),\n\t\t// Known mode's deployment ids (package / registry / deep-treasury) and\n\t\t// its declared testnet/mainnet Pyth ids are DECLARED config — bake them\n\t\t// as literals in the committed tree (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeDeepbookStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tnetwork: opts.network ?? known?.network ?? LOCAL_NETWORK_NAME,\n\t\t\t\tknown: {\n\t\t\t\t\tpackageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tdeepTreasuryId: known?.deepTreasuryId ?? null,\n\t\t\t\t\tpyth: known?.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: known.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: known.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: known.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: known.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// `deps` auto-infers the resolved `[sui]` tuple from the\n\t\t// `[suiResource] as const` dependency. `ctx` 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 identity = yield* IdentityContext;\n\t\t\t\tconst [sui] = deps;\n\t\t\t\tconst network = opts.network ?? known?.network ?? identity.network;\n\t\t\t\tconst resolved: DeepbookResolved = {\n\t\t\t\t\tmode: 'known',\n\t\t\t\t\tnetwork,\n\t\t\t\t\tpackageId,\n\t\t\t\t\tregistryId,\n\t\t\t\t\tadminCapId: null,\n\t\t\t\t\tdeepTreasuryId: known?.deepTreasuryId ?? null,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: known?.pyth ?? null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t\thasSeedLiquidity: false,\n\t\t\t\t\t// DEEP funding is a testnet-deepbook concern — gate on the\n\t\t\t\t\t// network name alone. (The old `&& String(chain) === 'sui:testnet'`\n\t\t\t\t\t// conjunct compared a genesis-digest chainId against a network\n\t\t\t\t\t// literal and was dead for every non-literal `chain` value.)\n\t\t\t\t\tdeepFundingStrategy:\n\t\t\t\t\t\topts.network === 'testnet'\n\t\t\t\t\t\t\t? makeDeepbookDeepFundingStrategy({ suiSdk: sui.sdk })\n\t\t\t\t\t\t\t: null,\n\t\t\t\t};\n\t\t\t\t// Emit contributions inline: snapshot -> codegen -> (optional\n\t\t\t\t// DEEP funding strategy). `resolved` is the just-computed value;\n\t\t\t\t// `snap` is the known-mode identity-guard snapshotable in scope.\n\t\t\t\t// The DEEP funding contributor is emitted only when\n\t\t\t\t// `resolved.deepFundingStrategy` is non-null.\n\t\t\t\tconst bindings: DeepbookBindings = {\n\t\t\t\t\tname,\n\t\t\t\t\tnetwork: resolved.network,\n\t\t\t\t\tpackageId: resolved.packageId,\n\t\t\t\t\tregistryId: resolved.registryId,\n\t\t\t\t\tadminCapId: null,\n\t\t\t\t\tdeepTreasuryId: resolved.deepTreasuryId,\n\t\t\t\t\tpools: [],\n\t\t\t\t\tpyth: resolved.pyth\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tpackageId: resolved.pyth.packageId,\n\t\t\t\t\t\t\t\tstateId: resolved.pyth.stateId,\n\t\t\t\t\t\t\t\twormholeStateId: resolved.pyth.wormholeStateId,\n\t\t\t\t\t\t\t\tfeeds: resolved.pyth.feeds.map((feed) => ({\n\t\t\t\t\t\t\t\t\tsymbol: feed.symbol,\n\t\t\t\t\t\t\t\t\tfeedId: feed.feedId,\n\t\t\t\t\t\t\t\t\tpriceInfoObjectId: feed.priceInfoObjectId,\n\t\t\t\t\t\t\t\t\tprice: feed.price.toString(),\n\t\t\t\t\t\t\t\t\texpo: feed.expo,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tmargin: null,\n\t\t\t\t\tserverUrl: null,\n\t\t\t\t\tindexerUrl: null,\n\t\t\t\t};\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeDeepbookCodegenable(bindings));\n\t\t\t\tif (resolved.deepFundingStrategy != null) {\n\t\t\t\t\tctx.provides(makeDeepbookDeepFundingContribution(resolved.deepFundingStrategy));\n\t\t\t\t}\n\t\t\t\treturn resolved;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// Default option resolution (env-driven)\n// ---------------------------------------------------------------------------\n\nconst resolveDefaultMode = <\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts?: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookOptions<Publisher, Pyth> => {\n\tconst env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process\n\t\t?.env?.DEVSTACK_NETWORK;\n\tif (env === undefined || env === 'localnet') {\n\t\t// Local DeepBook: default to local mode on localnet. The caller must\n\t\t// supply explicit `{ publisher, package, pools }`; `resolveLocalOptions`\n\t\t// fails fast otherwise (no auto-synthesis).\n\t\treturn { mode: 'local', ...opts } as DeepbookOptions<Publisher, Pyth>;\n\t}\n\t// Non-local default: refuse — known mode requires explicit\n\t// packageId/registryId. The user passes them via\n\t// `deepbookFor(network).known({...})` or `deepbook({mode:'known',...})`.\n\tthrow deepbookConfigError(\n\t\t'mode',\n\t\t`deepbook(): cannot auto-default to known mode on network='${env}'.`,\n\t\t`Use deepbookFor(network).known({packageId, registryId, ...}).`,\n\t);\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Env-driven factory. Defaults to local mode on localnet when passed local\n * options. Explicit `override` and `known` modes bypass env inference. */\ntype DeepbookLocalMember<\n\tPublisher extends AccountMemberAlias,\n\tPackage extends DeepbookPackageMember,\n\tPools extends ReadonlyArray<DeepbookPoolSpec>,\n\tPyth extends PythOptions | undefined = undefined,\n> = ReturnType<typeof buildLocalPlugin<Publisher, Package, Pools, Pyth>>;\ntype DeepbookOverrideMember = ReturnType<typeof buildOverridePlugin>;\ntype DeepbookKnownMember = ReturnType<typeof buildKnownPlugin>;\n\n// Local DeepBook requires explicit `{ publisher, package, pools }`. There is\n// no zero-arg/synthesized overload — an under-specified call fails fast (see\n// `resolveLocalOptions`).\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: { readonly mode: 'local' } & DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nexport function deepbookCore(\n\topts: { readonly mode: 'override' } & DeepbookOverrideOptions,\n): DeepbookOverrideMember;\nexport function deepbookCore(\n\topts: { readonly mode: 'known' } & DeepbookKnownOptions,\n): DeepbookKnownMember;\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n): DeepbookLocalMember<Publisher, Package, Pools, Pyth>;\nexport function deepbookCore<\n\tconst Publisher extends AccountMemberAlias,\n\tconst Package extends DeepbookPackageMember,\n\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\tconst Pyth extends PythOptions | undefined = undefined,\n>(\n\topts?: DeepbookLocalOptions<Publisher, Package, Pools, Pyth> | DeepbookOptions<Publisher, Pyth>,\n):\n\t| DeepbookLocalMember<Publisher, Package, Pools, Pyth>\n\t| DeepbookOverrideMember\n\t| DeepbookKnownMember {\n\tconst resolved: DeepbookOptions<Publisher, Pyth> =\n\t\topts !== undefined && 'mode' in opts\n\t\t\t? (opts as DeepbookOptions<Publisher, Pyth>)\n\t\t\t: resolveDefaultMode(\n\t\t\t\t\topts as DeepbookLocalOptions<Publisher, Package, Pools, Pyth> | undefined,\n\t\t\t\t);\n\tswitch (resolved.mode) {\n\t\tcase 'local': {\n\t\t\tconst localOpts = resolved as { readonly mode: 'local' } & DeepbookLocalOptions<\n\t\t\t\tPublisher,\n\t\t\t\tPackage,\n\t\t\t\tPools,\n\t\t\t\tPyth\n\t\t\t>;\n\t\t\t// Explicit-config path only; `buildLocalPlugin` -> `resolveLocalOptions`\n\t\t\t// fails fast when `publisher`/`package`/`pools` are missing.\n\t\t\treturn buildLocalPluginPublic(localOpts) as DeepbookLocalMember<\n\t\t\t\tPublisher,\n\t\t\t\tPackage,\n\t\t\t\tPools,\n\t\t\t\tPyth\n\t\t\t>;\n\t\t}\n\t\tcase 'override':\n\t\t\treturn buildOverridePlugin(resolved);\n\t\tcase 'known':\n\t\t\treturn buildKnownPlugin(resolved);\n\t}\n}\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local', network: 'localnet' } as const;\n * deepbookFor(local).local({publisher, package, pools}) // OK\n * deepbookFor(local).override({packageId, registryId, adminCapId}) // OK\n * deepbookFor(local).known({...}) // OK\n *\n * const fork = { mode: 'fork', network: 'mainnet-fork', upstream: 'mainnet' } as const;\n * deepbookFor(fork).local({...}) // COMPILE ERROR\n * deepbookFor(fork).override({...}) // COMPILE ERROR\n *\n * The fork branch has NO `.local` or `.override` entry — `deepbookFor(forkNetwork).local`\n * is a compile-time refusal. */\nexport const deepbookFor = defineModeNamespace({\n\tlocal: {\n\t\tlocal: <\n\t\t\tconst Publisher extends AccountMemberAlias,\n\t\t\tconst Package extends DeepbookPackageMember,\n\t\t\tconst Pools extends ReadonlyArray<DeepbookPoolSpec> = readonly [],\n\t\t\tconst Pyth extends PythOptions | undefined = undefined,\n\t\t>(\n\t\t\topts: DeepbookLocalOptions<Publisher, Package, Pools, Pyth>,\n\t\t) => buildLocalPluginPublic(opts),\n\t\toverride: (opts: DeepbookOverrideOptions) => buildOverridePlugin(opts),\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n\tlive: {\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n\tfork: {\n\t\t// `.override` intentionally absent — compile-time refusal.\n\t\tknown: (opts: DeepbookKnownOptions) => buildKnownPlugin(opts),\n\t},\n});\n\nexport { deepbookCore as deepbook };\n\n// ---------------------------------------------------------------------------\n// Re-exports for advanced callers\n// ---------------------------------------------------------------------------\n\nexport {\n\tDEEPBOOK_DEEP_FAUCET_STRATEGY_KEY,\n\tDEEPBOOK_TESTNET_DEEP_COIN_TYPE,\n} from './faucet-strategy.ts';\nexport {\n\ttype DeepbookError,\n\ttype DeepbookPluginError,\n\ttype DeepbookConfigError,\n\ttype DeepbookPhase,\n} from './errors.ts';\nexport type { DeepbookBindings } from './codegen.ts';\nexport type {\n\tAccountMemberAlias,\n\tCoinMemberAlias,\n\tDeepbookPackageMember,\n\tDeepbookPool,\n\tDeepbookPoolCoin,\n\tDeepbookPoolSeedLiquidity,\n\tDeepbookPoolSeedOrder,\n\tDeepbookPoolSpec,\n} from './types.ts';\nexport {\n\tDEEP_PRICE_FEED_ID,\n\tpythPriceFeedId,\n\tSUI_PRICE_FEED_ID,\n\tUSDC_PRICE_FEED_ID,\n} from './types.ts';\n"],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ import { Effect, Scope } from "effect";
|
|
|
20
20
|
declare const sui: <const O extends SuiOptions = {
|
|
21
21
|
mode: "local";
|
|
22
22
|
}>(opts?: O) => Plugin<"sui", {
|
|
23
|
-
mode: "local" | "
|
|
23
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
24
24
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
25
25
|
sdk: SuiSdkShim;
|
|
26
26
|
rpcUrl: string;
|
|
@@ -51,7 +51,7 @@ declare const sui: <const O extends SuiOptions = {
|
|
|
51
51
|
declare const suiFor: ModeNamespace<{
|
|
52
52
|
local: {
|
|
53
53
|
local: <const O extends Omit<SuiLocalOptions, "mode">>(opts?: O) => Plugin<"sui", {
|
|
54
|
-
mode: "local" | "
|
|
54
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
55
55
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
56
56
|
sdk: SuiSdkShim;
|
|
57
57
|
rpcUrl: string;
|
|
@@ -70,7 +70,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
70
70
|
buildImage: ImageRef | null;
|
|
71
71
|
}, readonly []>;
|
|
72
72
|
localRpc: (opts: Omit<SuiLocalRpcOptions, "mode">) => Plugin<"sui", {
|
|
73
|
-
mode: "local" | "
|
|
73
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
74
74
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
75
75
|
sdk: SuiSdkShim;
|
|
76
76
|
rpcUrl: string;
|
|
@@ -91,7 +91,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
91
91
|
};
|
|
92
92
|
live: {
|
|
93
93
|
testnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
|
|
94
|
-
mode: "local" | "
|
|
94
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
95
95
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
96
96
|
sdk: SuiSdkShim;
|
|
97
97
|
rpcUrl: string;
|
|
@@ -110,7 +110,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
110
110
|
buildImage: ImageRef | null;
|
|
111
111
|
}, readonly []>;
|
|
112
112
|
mainnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
|
|
113
|
-
mode: "local" | "
|
|
113
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
114
114
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
115
115
|
sdk: SuiSdkShim;
|
|
116
116
|
rpcUrl: string;
|
|
@@ -129,7 +129,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
129
129
|
buildImage: ImageRef | null;
|
|
130
130
|
}, readonly []>;
|
|
131
131
|
devnet: (opts?: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
|
|
132
|
-
mode: "local" | "
|
|
132
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
133
133
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
134
134
|
sdk: SuiSdkShim;
|
|
135
135
|
rpcUrl: string;
|
|
@@ -148,7 +148,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
148
148
|
buildImage: ImageRef | null;
|
|
149
149
|
}, readonly []>;
|
|
150
150
|
custom: (opts: Omit<SuiLiveOptions, "mode" | "network">) => Plugin<"sui", {
|
|
151
|
-
mode: "local" | "
|
|
151
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
152
152
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
153
153
|
sdk: SuiSdkShim;
|
|
154
154
|
rpcUrl: string;
|
|
@@ -169,7 +169,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
169
169
|
};
|
|
170
170
|
fork: {
|
|
171
171
|
mainnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
|
|
172
|
-
mode: "local" | "
|
|
172
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
173
173
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
174
174
|
sdk: SuiSdkShim;
|
|
175
175
|
rpcUrl: string;
|
|
@@ -188,7 +188,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
188
188
|
buildImage: ImageRef | null;
|
|
189
189
|
}, readonly []>;
|
|
190
190
|
testnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
|
|
191
|
-
mode: "local" | "
|
|
191
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
192
192
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
193
193
|
sdk: SuiSdkShim;
|
|
194
194
|
rpcUrl: string;
|
|
@@ -207,7 +207,7 @@ declare const suiFor: ModeNamespace<{
|
|
|
207
207
|
buildImage: ImageRef | null;
|
|
208
208
|
}, readonly []>;
|
|
209
209
|
devnet: (opts?: Omit<SuiForkOptions, "mode" | "upstream">) => Plugin<"sui", {
|
|
210
|
-
mode: "local" | "
|
|
210
|
+
mode: "local" | "local-rpc" | "live" | "fork";
|
|
211
211
|
fundingFaucetStrategy: FaucetStrategy | null;
|
|
212
212
|
sdk: SuiSdkShim;
|
|
213
213
|
rpcUrl: string;
|
|
@@ -7,12 +7,31 @@ import { Effect, Layer } from "effect";
|
|
|
7
7
|
import { basename, dirname, join } from "node:path";
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
9
9
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
10
|
-
import { cp, mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
10
|
+
import { cp, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
11
11
|
//#region src/plugins/sui/move-summary-runner.ts
|
|
12
12
|
const layerSuiMoveSummaryRunnerDocker = Layer.effect(MoveSummaryRunnerService, Effect.gen(function* () {
|
|
13
13
|
const runtime = yield* ContainerRuntimeService;
|
|
14
14
|
return MoveSummaryRunnerService.of({ runSummary: (input) => runSummaryViaDocker(runtime, input) });
|
|
15
15
|
}));
|
|
16
|
+
/** A minimal, DISPOSABLE sui client config. `sui move summary` initialises a
|
|
17
|
+
* client config on first use and PROMPTS ("No sui config found, create one
|
|
18
|
+
* [Y/n]?") when none exists — which blocks forever on a non-interactive stdin
|
|
19
|
+
* (e.g. CI), hanging codegen. Pointing `SUI_CONFIG_DIR` at a pre-seeded config
|
|
20
|
+
* inside the per-run scratch dir sidesteps the prompt without touching the
|
|
21
|
+
* developer's real `~/.sui`. The summary is an OFFLINE build (framework deps
|
|
22
|
+
* are embedded in the CLI), so we write the SMALLEST config the CLI parser
|
|
23
|
+
* accepts: a keystore path and an EMPTY env list. No network env at all — the
|
|
24
|
+
* `keystore` + `envs` fields are required by the parser, but no `rpc` is ever
|
|
25
|
+
* contacted. */
|
|
26
|
+
const disposableSuiClientConfig = (configDir) => [
|
|
27
|
+
"---",
|
|
28
|
+
"keystore:",
|
|
29
|
+
` File: ${join(configDir, "sui.keystore")}`,
|
|
30
|
+
"envs: []",
|
|
31
|
+
"active_env: ~",
|
|
32
|
+
"active_address: ~",
|
|
33
|
+
""
|
|
34
|
+
].join("\n");
|
|
16
35
|
const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Effect.gen(function* () {
|
|
17
36
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
18
37
|
return MoveSummaryRunnerService.of({ runSummary: ({ packageName, sourcePath }) => Effect.gen(function* () {
|
|
@@ -28,6 +47,7 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
|
|
|
28
47
|
});
|
|
29
48
|
const summaryPath = join(scratchDir, "package");
|
|
30
49
|
const stagedPkg = join(scratchDir, "src");
|
|
50
|
+
const suiConfigDir = join(scratchDir, "sui-config");
|
|
31
51
|
const cleanupScratch = Effect.promise(() => rm(scratchDir, {
|
|
32
52
|
recursive: true,
|
|
33
53
|
force: true
|
|
@@ -44,6 +64,9 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
|
|
|
44
64
|
await cp(sourcePath, stagedPkg, { recursive: true });
|
|
45
65
|
await copyLocalMoveDeps(sourcePath, stagedPkg, dirname(stagedPkg));
|
|
46
66
|
await cp(join(sourcePath, "Move.toml"), join(summaryPath, "Move.toml")).catch(() => {});
|
|
67
|
+
await mkdir(suiConfigDir, { recursive: true });
|
|
68
|
+
await writeFile(join(suiConfigDir, "sui.keystore"), "[]");
|
|
69
|
+
await writeFile(join(suiConfigDir, "client.yaml"), disposableSuiClientConfig(suiConfigDir));
|
|
47
70
|
},
|
|
48
71
|
catch: (cause) => new CodegenBindingsFailed({
|
|
49
72
|
package: packageName,
|
|
@@ -62,7 +85,11 @@ const layerSuiMoveSummaryRunnerHost = Layer.effect(MoveSummaryRunnerService, Eff
|
|
|
62
85
|
join(scratchDir, "install"),
|
|
63
86
|
"--output-directory",
|
|
64
87
|
join(summaryPath, "package_summaries")
|
|
65
|
-
], {
|
|
88
|
+
], {
|
|
89
|
+
cwd: stagedPkg,
|
|
90
|
+
env: { SUI_CONFIG_DIR: suiConfigDir },
|
|
91
|
+
extendEnv: true
|
|
92
|
+
}), {
|
|
66
93
|
op: `sui move summary (${sourcePath})`,
|
|
67
94
|
nonZeroIsFailure: true,
|
|
68
95
|
stdoutTruncate: Infinity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-summary-runner.mjs","names":[],"sources":["../../../src/plugins/sui/move-summary-runner.ts"],"sourcesContent":["// Sui plugin — Move-summary runner Layer factories.\n//\n// The codegen orchestrator (L3) consumes an abstract\n// `MoveSummaryRunnerService`; it does NOT know which CLI image or\n// host binary produces the summary JSON. Both production\n// implementations live here because they encode Sui-specific\n// knowledge (the `sui` binary name, the Sui CLI image, the\n// `sui move summary` argv shape).\n//\n// Architecture: per \"Orchestrator boundaries — never names a\n// service\", the codegen orchestrator imports only the abstract\n// `MoveSummaryRunnerService` from its `bindings.ts`; the runtime\n// composer wires one of these sui-plugin layers in.\n//\n// Implementations:\n// - `layerSuiMoveSummaryRunnerDocker` — runs `sui move summary`\n// inside the Sui CLI container image; the default production\n// wiring (`orchestrators/boot.ts`).\n// - `layerSuiMoveSummaryRunnerHost` — runs the local `sui`\n// binary directly via `ChildProcessSpawner`. Useful for\n// embedders that already have a Sui CLI on PATH.\n\nimport { cp, mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { homedir, tmpdir } from 'node:os';\nimport { basename, dirname, join } from 'node:path';\n\nimport { Effect, Layer } from 'effect';\nimport { ChildProcess, ChildProcessSpawner } from 'effect/unstable/process';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport {\n\ttype MoveSummary,\n\ttype MoveSummaryInput,\n\tMoveSummaryRunnerService,\n} from '../../orchestrators/codegen/bindings.ts';\nimport { CodegenBindingsFailed } from '../../orchestrators/codegen/errors.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { capture } from '../../substrate/runtime/observability/subprocess-capture.ts';\nimport { copyLocalMoveDeps, shellQuote, suiCliImageBuildContext } from './move/index.ts';\n\n// -----------------------------------------------------------------------------\n// Docker variant — `sui move summary` inside the Sui CLI container image.\n// -----------------------------------------------------------------------------\n\nexport const layerSuiMoveSummaryRunnerDocker: Layer.Layer<\n\tMoveSummaryRunnerService,\n\tnever,\n\tContainerRuntimeService\n> = Layer.effect(\n\tMoveSummaryRunnerService,\n\tEffect.gen(function* () {\n\t\tconst runtime: ContainerRuntime = yield* ContainerRuntimeService;\n\t\treturn MoveSummaryRunnerService.of({\n\t\t\trunSummary: (input) => runSummaryViaDocker(runtime, input),\n\t\t});\n\t}),\n);\n\n// -----------------------------------------------------------------------------\n// Host-binary variant — invoke a `sui` CLI on PATH directly.\n// -----------------------------------------------------------------------------\n\nexport const layerSuiMoveSummaryRunnerHost: Layer.Layer<\n\tMoveSummaryRunnerService,\n\tnever,\n\tChildProcessSpawner.ChildProcessSpawner\n> = Layer.effect(\n\tMoveSummaryRunnerService,\n\tEffect.gen(function* () {\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\treturn MoveSummaryRunnerService.of({\n\t\t\trunSummary: ({ packageName, sourcePath }) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst scratchDir = yield* Effect.tryPromise({\n\t\t\t\t\t\ttry: () => mkdtemp(join(tmpdir(), 'devstack-move-summary-')),\n\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\thint: 'Unable to create a temporary directory for Move summary output.',\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\tconst summaryPath = join(scratchDir, 'package');\n\t\t\t\t\t// Run summary inside a disposable copy of the package, never the\n\t\t\t\t\t// developer's real source — `sui move summary` rewrites Move.lock.\n\t\t\t\t\tconst stagedPkg = join(scratchDir, 'src');\n\t\t\t\t\tconst cleanupScratch = Effect.promise(() =>\n\t\t\t\t\t\trm(scratchDir, { recursive: true, force: true }),\n\t\t\t\t\t).pipe(Effect.ignore);\n\t\t\t\t\tconst result = yield* Effect.gen(function* () {\n\t\t\t\t\t\tyield* Effect.tryPromise({\n\t\t\t\t\t\t\ttry: async () => {\n\t\t\t\t\t\t\t\tawait mkdir(summaryPath, { recursive: true });\n\t\t\t\t\t\t\t\tawait cp(sourcePath, stagedPkg, { recursive: true });\n\t\t\t\t\t\t\t\t// Stage local relative deps so `sui move summary` resolves them.\n\t\t\t\t\t\t\t\tawait copyLocalMoveDeps(sourcePath, stagedPkg, dirname(stagedPkg));\n\t\t\t\t\t\t\t\t// Place the source manifest beside the emitted summary: it\n\t\t\t\t\t\t\t\t// is the dir we hand `@mysten/codegen`, which reads\n\t\t\t\t\t\t\t\t// `Move.toml` there for its `[addresses]` labels. Without\n\t\t\t\t\t\t\t\t// it the library logs \"Failed to read Move.toml for <dir>\"\n\t\t\t\t\t\t\t\t// and falls back to `packageName`; with it the read\n\t\t\t\t\t\t\t\t// succeeds (warning gone) and its native main-package\n\t\t\t\t\t\t\t\t// resolution works. Best-effort — a manifest-less source\n\t\t\t\t\t\t\t\t// just keeps the prior fallback.\n\t\t\t\t\t\t\t\tawait cp(join(sourcePath, 'Move.toml'), join(summaryPath, 'Move.toml')).catch(\n\t\t\t\t\t\t\t\t\t() => {},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\thint: 'Unable to stage a disposable copy of the Move package for summary.',\n\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst cmd = ChildProcess.make(\n\t\t\t\t\t\t\t'sui',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'move',\n\t\t\t\t\t\t\t\t'summary',\n\t\t\t\t\t\t\t\t'--path',\n\t\t\t\t\t\t\t\t'.',\n\t\t\t\t\t\t\t\t'--install-dir',\n\t\t\t\t\t\t\t\tjoin(scratchDir, 'install'),\n\t\t\t\t\t\t\t\t'--output-directory',\n\t\t\t\t\t\t\t\tjoin(summaryPath, 'package_summaries'),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t{ cwd: stagedPkg },\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn yield* capture(spawner, cmd, {\n\t\t\t\t\t\t\top: `sui move summary (${sourcePath})`,\n\t\t\t\t\t\t\tnonZeroIsFailure: true,\n\t\t\t\t\t\t\tstdoutTruncate: Infinity,\n\t\t\t\t\t\t\tstderrTruncate: 4_000,\n\t\t\t\t\t\t}).pipe(\n\t\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\t\thint: 'Install the Sui CLI and ensure this Move package can run `sui move summary`.',\n\t\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}).pipe(Effect.tapError(() => cleanupScratch));\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpackageName,\n\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\tsummaryPath,\n\t\t\t\t\t\tcleanupPath: scratchDir,\n\t\t\t\t\t\tsummaryJson: parseSummaryStdout(result.stdout),\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t});\n\t}),\n);\n\n// -----------------------------------------------------------------------------\n// Docker-variant helpers — shared with `runSummaryViaDocker`.\n// -----------------------------------------------------------------------------\n\nconst runSummaryViaDocker = (\n\truntime: ContainerRuntime,\n\tinput: MoveSummaryInput,\n): Effect.Effect<MoveSummary, CodegenBindingsFailed> =>\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst scratchDir = yield* makeSummaryScratch(input);\n\t\t\tconst summaryPath = join(scratchDir, 'package');\n\t\t\tconst cleanupScratch = Effect.promise(() =>\n\t\t\t\trm(scratchDir, { recursive: true, force: true }),\n\t\t\t).pipe(Effect.ignore);\n\t\t\tconst result = yield* Effect.gen(function* () {\n\t\t\t\tyield* prepareSummaryPackage(summaryPath, input);\n\t\t\t\tconst image = input.buildImage ?? (yield* resolveDefaultSummaryImage(runtime, input));\n\t\t\t\tconst moveHome = join(homedir(), '.move');\n\t\t\t\tyield* ensureMoveHome(moveHome, input);\n\t\t\t\tconst packageDir = basename(input.sourcePath);\n\t\t\t\t// Mount a disposable staged copy at /workspace, never the real source\n\t\t\t\t// tree — `sui move summary` rewrites Move.lock during resolution.\n\t\t\t\tconst stagedRoot = join(scratchDir, 'src');\n\t\t\t\tyield* stageSummarySource(input, join(stagedRoot, packageDir));\n\t\t\t\tconst hostUid = typeof process.getuid === 'function' ? process.getuid() : 0;\n\t\t\t\tconst hostGid = typeof process.getgid === 'function' ? process.getgid() : 0;\n\t\t\t\tconst command = [\n\t\t\t\t\t'set -e',\n\t\t\t\t\t'cleanup_summary() { status=$?; ' +\n\t\t\t\t\t\t'chmod -R a+rwX /summary /workspace 2>/dev/null || true; ' +\n\t\t\t\t\t\t`chown -R ${hostUid}:${hostGid} /summary /workspace 2>/dev/null || true; ` +\n\t\t\t\t\t\t'exit \"$status\"; }',\n\t\t\t\t\t'trap cleanup_summary EXIT',\n\t\t\t\t\t'mkdir -p /summary/package_summaries',\n\t\t\t\t\t`sui move summary --path /workspace/${shellQuote(packageDir)} ` +\n\t\t\t\t\t\t'--install-dir /tmp/devstack-move-summary-install ' +\n\t\t\t\t\t\t'--output-directory /summary/package_summaries',\n\t\t\t\t].join('; ');\n\t\t\t\tconst run = yield* runtime\n\t\t\t\t\t.runOneShot({\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tentrypoint: 'sh',\n\t\t\t\t\t\targv: ['-c', command],\n\t\t\t\t\t\tmounts: [\n\t\t\t\t\t\t\t{ source: stagedRoot, target: '/workspace' },\n\t\t\t\t\t\t\t{ source: summaryPath, target: '/summary' },\n\t\t\t\t\t\t\t{ source: moveHome, target: '/root/.move' },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimeoutMillis: 5 * 60_000,\n\t\t\t\t\t})\n\t\t\t\t\t.pipe(\n\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\thint: 'Docker runtime failed while running `sui move summary` for bindings codegen.',\n\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\tif (run.exitCode !== 0) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\thint:\n\t\t\t\t\t\t\t\t`sui move summary exited ${run.exitCode}. ` +\n\t\t\t\t\t\t\t\t`stderr: ${run.stderr || '(empty)'}; stdout tail: ${\n\t\t\t\t\t\t\t\t\trun.stdout.slice(-400) || '(empty)'\n\t\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\t\t\t\treturn run;\n\t\t\t}).pipe(Effect.tapError(() => cleanupScratch));\n\t\t\treturn {\n\t\t\t\tpackageName: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\tsummaryPath,\n\t\t\t\tcleanupPath: scratchDir,\n\t\t\t\tsummaryJson: parseSummaryStdout(result.stdout),\n\t\t\t};\n\t\t}),\n\t);\n\nconst makeSummaryScratch = (\n\tinput: MoveSummaryInput,\n): Effect.Effect<string, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: () => mkdtemp(join(tmpdir(), 'devstack-move-summary-')),\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to create a temporary directory for Move summary output.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst prepareSummaryPackage = (\n\tsummaryPath: string,\n\tinput: MoveSummaryInput,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\t// Only create the OUTPUT mount dir; the package itself is mounted from a\n\t\t// disposable staged copy (see `stageSummarySource`), never the real source.\n\t\t// Also drop in the source manifest so the host-side `@mysten/codegen` reads\n\t\t// its `[addresses]` from this dir (see `layerSuiMoveSummaryRunnerHost`) —\n\t\t// silences the \"Failed to read Move.toml\" warning. Best-effort.\n\t\ttry: async () => {\n\t\t\tawait mkdir(summaryPath, { recursive: true });\n\t\t\tawait cp(join(input.sourcePath, 'Move.toml'), join(summaryPath, 'Move.toml')).catch(() => {});\n\t\t},\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to prepare a temporary Move summary output directory.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\n// Stage a disposable copy of the Move package. `sui move summary` rewrites\n// `Move.lock` during dependency resolution, so running it against the\n// developer's real checked-in tree would dirty their working copy. The copy\n// lives under the scoped scratch dir and is reaped with it.\nconst stageSummarySource = (\n\tinput: MoveSummaryInput,\n\tstagedPkg: string,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: async () => {\n\t\t\tawait mkdir(dirname(stagedPkg), { recursive: true });\n\t\t\tawait cp(input.sourcePath, stagedPkg, { recursive: true });\n\t\t\t// Bring local `../` deps (`{ local = \"../token\" }`) into the staged\n\t\t\t// tree so `sui move summary` resolves them (mirrors the build path).\n\t\t\tawait copyLocalMoveDeps(input.sourcePath, stagedPkg, dirname(stagedPkg));\n\t\t},\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to stage a disposable copy of the Move package for summary.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst resolveDefaultSummaryImage = (\n\truntime: ContainerRuntime,\n\tinput: MoveSummaryInput,\n): Effect.Effect<ImageRef, CodegenBindingsFailed> =>\n\t// Shared CLI image — owned at the daemon-level _per-app_ pin (see\n\t// `chain-build-container.ts:PER_APP_SHARED_STACK`), not per-stack;\n\t// the build container that materialises it carries the labels, so\n\t// `ensureImage` itself is intentionally label-free here.\n\truntime.ensureImage(suiCliImageBuildContext()).pipe(\n\t\tEffect.mapError(\n\t\t\t(cause) =>\n\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\thint: 'Unable to resolve the Sui CLI container image for Move bindings codegen.',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t),\n\t);\n\nconst ensureMoveHome = (\n\tmoveHome: string,\n\tinput: MoveSummaryInput,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: () => mkdir(moveHome, { recursive: true }),\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: `Unable to create Move cache mount source \"${moveHome}\".`,\n\t\t\t\tcause,\n\t\t\t}),\n\t}).pipe(Effect.asVoid);\n\nconst parseSummaryStdout = (stdout: string): unknown => {\n\tconst trimmed = stdout.trim();\n\tif (trimmed.length === 0) return null;\n\ttry {\n\t\treturn JSON.parse(trimmed) as unknown;\n\t} catch {\n\t\treturn trimmed;\n\t}\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"move-summary-runner.mjs","names":[],"sources":["../../../src/plugins/sui/move-summary-runner.ts"],"sourcesContent":["// Sui plugin — Move-summary runner Layer factories.\n//\n// The codegen orchestrator (L3) consumes an abstract\n// `MoveSummaryRunnerService`; it does NOT know which CLI image or\n// host binary produces the summary JSON. Both production\n// implementations live here because they encode Sui-specific\n// knowledge (the `sui` binary name, the Sui CLI image, the\n// `sui move summary` argv shape).\n//\n// Architecture: per \"Orchestrator boundaries — never names a\n// service\", the codegen orchestrator imports only the abstract\n// `MoveSummaryRunnerService` from its `bindings.ts`; the runtime\n// composer wires one of these sui-plugin layers in.\n//\n// Implementations:\n// - `layerSuiMoveSummaryRunnerDocker` — runs `sui move summary`\n// inside the Sui CLI container image; the default production\n// wiring (`orchestrators/boot.ts`).\n// - `layerSuiMoveSummaryRunnerHost` — runs the local `sui`\n// binary directly via `ChildProcessSpawner`. Useful for\n// embedders that already have a Sui CLI on PATH.\n\nimport { cp, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { homedir, tmpdir } from 'node:os';\nimport { basename, dirname, join } from 'node:path';\n\nimport { Effect, Layer } from 'effect';\nimport { ChildProcess, ChildProcessSpawner } from 'effect/unstable/process';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport {\n\ttype MoveSummary,\n\ttype MoveSummaryInput,\n\tMoveSummaryRunnerService,\n} from '../../orchestrators/codegen/bindings.ts';\nimport { CodegenBindingsFailed } from '../../orchestrators/codegen/errors.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { capture } from '../../substrate/runtime/observability/subprocess-capture.ts';\nimport { copyLocalMoveDeps, shellQuote, suiCliImageBuildContext } from './move/index.ts';\n\n// -----------------------------------------------------------------------------\n// Docker variant — `sui move summary` inside the Sui CLI container image.\n// -----------------------------------------------------------------------------\n\nexport const layerSuiMoveSummaryRunnerDocker: Layer.Layer<\n\tMoveSummaryRunnerService,\n\tnever,\n\tContainerRuntimeService\n> = Layer.effect(\n\tMoveSummaryRunnerService,\n\tEffect.gen(function* () {\n\t\tconst runtime: ContainerRuntime = yield* ContainerRuntimeService;\n\t\treturn MoveSummaryRunnerService.of({\n\t\t\trunSummary: (input) => runSummaryViaDocker(runtime, input),\n\t\t});\n\t}),\n);\n\n// -----------------------------------------------------------------------------\n// Host-binary variant — invoke a `sui` CLI on PATH directly.\n// -----------------------------------------------------------------------------\n\n/** A minimal, DISPOSABLE sui client config. `sui move summary` initialises a\n * client config on first use and PROMPTS (\"No sui config found, create one\n * [Y/n]?\") when none exists — which blocks forever on a non-interactive stdin\n * (e.g. CI), hanging codegen. Pointing `SUI_CONFIG_DIR` at a pre-seeded config\n * inside the per-run scratch dir sidesteps the prompt without touching the\n * developer's real `~/.sui`. The summary is an OFFLINE build (framework deps\n * are embedded in the CLI), so we write the SMALLEST config the CLI parser\n * accepts: a keystore path and an EMPTY env list. No network env at all — the\n * `keystore` + `envs` fields are required by the parser, but no `rpc` is ever\n * contacted. */\nconst disposableSuiClientConfig = (configDir: string): string =>\n\t[\n\t\t'---',\n\t\t'keystore:',\n\t\t` File: ${join(configDir, 'sui.keystore')}`,\n\t\t'envs: []',\n\t\t'active_env: ~',\n\t\t'active_address: ~',\n\t\t'',\n\t].join('\\n');\n\nexport const layerSuiMoveSummaryRunnerHost: Layer.Layer<\n\tMoveSummaryRunnerService,\n\tnever,\n\tChildProcessSpawner.ChildProcessSpawner\n> = Layer.effect(\n\tMoveSummaryRunnerService,\n\tEffect.gen(function* () {\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\treturn MoveSummaryRunnerService.of({\n\t\t\trunSummary: ({ packageName, sourcePath }) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst scratchDir = yield* Effect.tryPromise({\n\t\t\t\t\t\ttry: () => mkdtemp(join(tmpdir(), 'devstack-move-summary-')),\n\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\thint: 'Unable to create a temporary directory for Move summary output.',\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\tconst summaryPath = join(scratchDir, 'package');\n\t\t\t\t\t// Run summary inside a disposable copy of the package, never the\n\t\t\t\t\t// developer's real source — `sui move summary` rewrites Move.lock.\n\t\t\t\t\tconst stagedPkg = join(scratchDir, 'src');\n\t\t\t\t\t// Disposable sui config dir so the CLI never prompts to create one\n\t\t\t\t\t// (see `disposableSuiClientConfig`). Passed via `SUI_CONFIG_DIR`.\n\t\t\t\t\tconst suiConfigDir = join(scratchDir, 'sui-config');\n\t\t\t\t\tconst cleanupScratch = Effect.promise(() =>\n\t\t\t\t\t\trm(scratchDir, { recursive: true, force: true }),\n\t\t\t\t\t).pipe(Effect.ignore);\n\t\t\t\t\tconst result = yield* Effect.gen(function* () {\n\t\t\t\t\t\tyield* Effect.tryPromise({\n\t\t\t\t\t\t\ttry: async () => {\n\t\t\t\t\t\t\t\tawait mkdir(summaryPath, { recursive: true });\n\t\t\t\t\t\t\t\tawait cp(sourcePath, stagedPkg, { recursive: true });\n\t\t\t\t\t\t\t\t// Stage local relative deps so `sui move summary` resolves them.\n\t\t\t\t\t\t\t\tawait copyLocalMoveDeps(sourcePath, stagedPkg, dirname(stagedPkg));\n\t\t\t\t\t\t\t\t// Place the source manifest beside the emitted summary: it\n\t\t\t\t\t\t\t\t// is the dir we hand `@mysten/codegen`, which reads\n\t\t\t\t\t\t\t\t// `Move.toml` there for its `[addresses]` labels. Without\n\t\t\t\t\t\t\t\t// it the library logs \"Failed to read Move.toml for <dir>\"\n\t\t\t\t\t\t\t\t// and falls back to `packageName`; with it the read\n\t\t\t\t\t\t\t\t// succeeds (warning gone) and its native main-package\n\t\t\t\t\t\t\t\t// resolution works. Best-effort — a manifest-less source\n\t\t\t\t\t\t\t\t// just keeps the prior fallback.\n\t\t\t\t\t\t\t\tawait cp(join(sourcePath, 'Move.toml'), join(summaryPath, 'Move.toml')).catch(\n\t\t\t\t\t\t\t\t\t() => {},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t// Pre-seed the disposable sui config so the CLI never prompts.\n\t\t\t\t\t\t\t\tawait mkdir(suiConfigDir, { recursive: true });\n\t\t\t\t\t\t\t\tawait writeFile(join(suiConfigDir, 'sui.keystore'), '[]');\n\t\t\t\t\t\t\t\tawait writeFile(\n\t\t\t\t\t\t\t\t\tjoin(suiConfigDir, 'client.yaml'),\n\t\t\t\t\t\t\t\t\tdisposableSuiClientConfig(suiConfigDir),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\thint: 'Unable to stage a disposable copy of the Move package for summary.',\n\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst cmd = ChildProcess.make(\n\t\t\t\t\t\t\t'sui',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t'move',\n\t\t\t\t\t\t\t\t'summary',\n\t\t\t\t\t\t\t\t'--path',\n\t\t\t\t\t\t\t\t'.',\n\t\t\t\t\t\t\t\t'--install-dir',\n\t\t\t\t\t\t\t\tjoin(scratchDir, 'install'),\n\t\t\t\t\t\t\t\t'--output-directory',\n\t\t\t\t\t\t\t\tjoin(summaryPath, 'package_summaries'),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t{ cwd: stagedPkg, env: { SUI_CONFIG_DIR: suiConfigDir }, extendEnv: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn yield* capture(spawner, cmd, {\n\t\t\t\t\t\t\top: `sui move summary (${sourcePath})`,\n\t\t\t\t\t\t\tnonZeroIsFailure: true,\n\t\t\t\t\t\t\tstdoutTruncate: Infinity,\n\t\t\t\t\t\t\tstderrTruncate: 4_000,\n\t\t\t\t\t\t}).pipe(\n\t\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\t\thint: 'Install the Sui CLI and ensure this Move package can run `sui move summary`.',\n\t\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}).pipe(Effect.tapError(() => cleanupScratch));\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpackageName,\n\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\tsummaryPath,\n\t\t\t\t\t\tcleanupPath: scratchDir,\n\t\t\t\t\t\tsummaryJson: parseSummaryStdout(result.stdout),\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t});\n\t}),\n);\n\n// -----------------------------------------------------------------------------\n// Docker-variant helpers — shared with `runSummaryViaDocker`.\n// -----------------------------------------------------------------------------\n\nconst runSummaryViaDocker = (\n\truntime: ContainerRuntime,\n\tinput: MoveSummaryInput,\n): Effect.Effect<MoveSummary, CodegenBindingsFailed> =>\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst scratchDir = yield* makeSummaryScratch(input);\n\t\t\tconst summaryPath = join(scratchDir, 'package');\n\t\t\tconst cleanupScratch = Effect.promise(() =>\n\t\t\t\trm(scratchDir, { recursive: true, force: true }),\n\t\t\t).pipe(Effect.ignore);\n\t\t\tconst result = yield* Effect.gen(function* () {\n\t\t\t\tyield* prepareSummaryPackage(summaryPath, input);\n\t\t\t\tconst image = input.buildImage ?? (yield* resolveDefaultSummaryImage(runtime, input));\n\t\t\t\tconst moveHome = join(homedir(), '.move');\n\t\t\t\tyield* ensureMoveHome(moveHome, input);\n\t\t\t\tconst packageDir = basename(input.sourcePath);\n\t\t\t\t// Mount a disposable staged copy at /workspace, never the real source\n\t\t\t\t// tree — `sui move summary` rewrites Move.lock during resolution.\n\t\t\t\tconst stagedRoot = join(scratchDir, 'src');\n\t\t\t\tyield* stageSummarySource(input, join(stagedRoot, packageDir));\n\t\t\t\tconst hostUid = typeof process.getuid === 'function' ? process.getuid() : 0;\n\t\t\t\tconst hostGid = typeof process.getgid === 'function' ? process.getgid() : 0;\n\t\t\t\tconst command = [\n\t\t\t\t\t'set -e',\n\t\t\t\t\t'cleanup_summary() { status=$?; ' +\n\t\t\t\t\t\t'chmod -R a+rwX /summary /workspace 2>/dev/null || true; ' +\n\t\t\t\t\t\t`chown -R ${hostUid}:${hostGid} /summary /workspace 2>/dev/null || true; ` +\n\t\t\t\t\t\t'exit \"$status\"; }',\n\t\t\t\t\t'trap cleanup_summary EXIT',\n\t\t\t\t\t'mkdir -p /summary/package_summaries',\n\t\t\t\t\t`sui move summary --path /workspace/${shellQuote(packageDir)} ` +\n\t\t\t\t\t\t'--install-dir /tmp/devstack-move-summary-install ' +\n\t\t\t\t\t\t'--output-directory /summary/package_summaries',\n\t\t\t\t].join('; ');\n\t\t\t\tconst run = yield* runtime\n\t\t\t\t\t.runOneShot({\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tentrypoint: 'sh',\n\t\t\t\t\t\targv: ['-c', command],\n\t\t\t\t\t\tmounts: [\n\t\t\t\t\t\t\t{ source: stagedRoot, target: '/workspace' },\n\t\t\t\t\t\t\t{ source: summaryPath, target: '/summary' },\n\t\t\t\t\t\t\t{ source: moveHome, target: '/root/.move' },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimeoutMillis: 5 * 60_000,\n\t\t\t\t\t})\n\t\t\t\t\t.pipe(\n\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\t\t\thint: 'Docker runtime failed while running `sui move summary` for bindings codegen.',\n\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\tif (run.exitCode !== 0) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\t\t\thint:\n\t\t\t\t\t\t\t\t`sui move summary exited ${run.exitCode}. ` +\n\t\t\t\t\t\t\t\t`stderr: ${run.stderr || '(empty)'}; stdout tail: ${\n\t\t\t\t\t\t\t\t\trun.stdout.slice(-400) || '(empty)'\n\t\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\t\t\t\treturn run;\n\t\t\t}).pipe(Effect.tapError(() => cleanupScratch));\n\t\t\treturn {\n\t\t\t\tpackageName: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\tsummaryPath,\n\t\t\t\tcleanupPath: scratchDir,\n\t\t\t\tsummaryJson: parseSummaryStdout(result.stdout),\n\t\t\t};\n\t\t}),\n\t);\n\nconst makeSummaryScratch = (\n\tinput: MoveSummaryInput,\n): Effect.Effect<string, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: () => mkdtemp(join(tmpdir(), 'devstack-move-summary-')),\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to create a temporary directory for Move summary output.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst prepareSummaryPackage = (\n\tsummaryPath: string,\n\tinput: MoveSummaryInput,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\t// Only create the OUTPUT mount dir; the package itself is mounted from a\n\t\t// disposable staged copy (see `stageSummarySource`), never the real source.\n\t\t// Also drop in the source manifest so the host-side `@mysten/codegen` reads\n\t\t// its `[addresses]` from this dir (see `layerSuiMoveSummaryRunnerHost`) —\n\t\t// silences the \"Failed to read Move.toml\" warning. Best-effort.\n\t\ttry: async () => {\n\t\t\tawait mkdir(summaryPath, { recursive: true });\n\t\t\tawait cp(join(input.sourcePath, 'Move.toml'), join(summaryPath, 'Move.toml')).catch(() => {});\n\t\t},\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to prepare a temporary Move summary output directory.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\n// Stage a disposable copy of the Move package. `sui move summary` rewrites\n// `Move.lock` during dependency resolution, so running it against the\n// developer's real checked-in tree would dirty their working copy. The copy\n// lives under the scoped scratch dir and is reaped with it.\nconst stageSummarySource = (\n\tinput: MoveSummaryInput,\n\tstagedPkg: string,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: async () => {\n\t\t\tawait mkdir(dirname(stagedPkg), { recursive: true });\n\t\t\tawait cp(input.sourcePath, stagedPkg, { recursive: true });\n\t\t\t// Bring local `../` deps (`{ local = \"../token\" }`) into the staged\n\t\t\t// tree so `sui move summary` resolves them (mirrors the build path).\n\t\t\tawait copyLocalMoveDeps(input.sourcePath, stagedPkg, dirname(stagedPkg));\n\t\t},\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: 'Unable to stage a disposable copy of the Move package for summary.',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst resolveDefaultSummaryImage = (\n\truntime: ContainerRuntime,\n\tinput: MoveSummaryInput,\n): Effect.Effect<ImageRef, CodegenBindingsFailed> =>\n\t// Shared CLI image — owned at the daemon-level _per-app_ pin (see\n\t// `chain-build-container.ts:PER_APP_SHARED_STACK`), not per-stack;\n\t// the build container that materialises it carries the labels, so\n\t// `ensureImage` itself is intentionally label-free here.\n\truntime.ensureImage(suiCliImageBuildContext()).pipe(\n\t\tEffect.mapError(\n\t\t\t(cause) =>\n\t\t\t\tnew CodegenBindingsFailed({\n\t\t\t\t\tpackage: input.packageName,\n\t\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\t\treason: 'summary-failed',\n\t\t\t\t\thint: 'Unable to resolve the Sui CLI container image for Move bindings codegen.',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t),\n\t);\n\nconst ensureMoveHome = (\n\tmoveHome: string,\n\tinput: MoveSummaryInput,\n): Effect.Effect<void, CodegenBindingsFailed> =>\n\tEffect.tryPromise({\n\t\ttry: () => mkdir(moveHome, { recursive: true }),\n\t\tcatch: (cause) =>\n\t\t\tnew CodegenBindingsFailed({\n\t\t\t\tpackage: input.packageName,\n\t\t\t\tsourcePath: input.sourcePath,\n\t\t\t\treason: 'summary-failed',\n\t\t\t\thint: `Unable to create Move cache mount source \"${moveHome}\".`,\n\t\t\t\tcause,\n\t\t\t}),\n\t}).pipe(Effect.asVoid);\n\nconst parseSummaryStdout = (stdout: string): unknown => {\n\tconst trimmed = stdout.trim();\n\tif (trimmed.length === 0) return null;\n\ttry {\n\t\treturn JSON.parse(trimmed) as unknown;\n\t} catch {\n\t\treturn trimmed;\n\t}\n};\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import "./cross-process/command-channel/channel.mjs";
|
|
|
3
3
|
import "./cross-process/command-channel/index.mjs";
|
|
4
4
|
import "./cross-process/roster.mjs";
|
|
5
5
|
import "./supervisor/contribution-dispatcher.mjs";
|
|
6
|
+
import "./lifecycle/file-watcher.mjs";
|
|
6
7
|
import "./observability/logger.mjs";
|
|
7
8
|
import "./supervisor/start-supervisor.mjs";
|
|
8
9
|
import "./supervisor/index.mjs";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Effect, Scope } from "effect";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { deriveWatchRoots } from "./watch-attribution.mjs";
|
|
2
|
+
import { Effect, Queue } from "effect";
|
|
3
|
+
import { watch } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
//#region src/substrate/runtime/lifecycle/file-watcher.ts
|
|
6
|
+
/** Coalescing window for a burst of fs events. Editors save by
|
|
7
|
+
* rename-replace (temp write + rename), so a single save surfaces as
|
|
8
|
+
* several events within a few ms — one settle window collapses them
|
|
9
|
+
* into one restart per plugin. */
|
|
10
|
+
const DEFAULT_DEBOUNCE_MILLIS = 150;
|
|
11
|
+
/**
|
|
12
|
+
* Start the L0 file watcher. Acquires one recursive `fs.watch` per
|
|
13
|
+
* distinct root (released on scope close) and forks a debouncing drain
|
|
14
|
+
* loop that fires `notifyWatchFire` for each distinct changed path.
|
|
15
|
+
* Returns once the watchers + loop are installed; it lives for the
|
|
16
|
+
* lifetime of the surrounding scope, so callers `Effect.forkScoped` it
|
|
17
|
+
* (or just `yield*` it inside a scoped region).
|
|
18
|
+
*
|
|
19
|
+
* Watcher setup never fails the boot: a root that cannot be watched
|
|
20
|
+
* (e.g. a not-yet-created directory) is logged and skipped.
|
|
21
|
+
*/
|
|
22
|
+
const startFileWatcher = (params) => Effect.gen(function* () {
|
|
23
|
+
const roots = deriveWatchRoots(params.watchIndex);
|
|
24
|
+
if (roots.length === 0) return;
|
|
25
|
+
const debounceMillis = params.debounceMillis ?? DEFAULT_DEBOUNCE_MILLIS;
|
|
26
|
+
const events = yield* Queue.dropping(1024);
|
|
27
|
+
const supervisorContext = yield* Effect.context();
|
|
28
|
+
const runForkInherited = Effect.runForkWith(supervisorContext);
|
|
29
|
+
for (const root of roots) if ((yield* Effect.acquireRelease(Effect.sync(() => {
|
|
30
|
+
try {
|
|
31
|
+
const fsWatcher = watch(root, { recursive: true }, (_eventType, filename) => {
|
|
32
|
+
if (filename === null) return;
|
|
33
|
+
const abs = join(root, filename.toString());
|
|
34
|
+
runForkInherited(Queue.offer(events, abs));
|
|
35
|
+
});
|
|
36
|
+
fsWatcher.on("error", () => {});
|
|
37
|
+
return fsWatcher;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}), (watcher) => Effect.sync(() => watcher?.close()))) === null) yield* Effect.logWarning(`file-watcher: could not watch ${root}`);
|
|
42
|
+
const drain = Effect.gen(function* () {
|
|
43
|
+
const first = yield* Queue.take(events);
|
|
44
|
+
yield* Effect.sleep(`${debounceMillis} millis`);
|
|
45
|
+
const rest = yield* Queue.takeAll(events);
|
|
46
|
+
const paths = new Set([first, ...rest]);
|
|
47
|
+
for (const path of paths) yield* params.notifyWatchFire(path);
|
|
48
|
+
}).pipe(Effect.forever);
|
|
49
|
+
yield* Effect.forkScoped(drain);
|
|
50
|
+
});
|
|
51
|
+
//#endregion
|
|
52
|
+
export { startFileWatcher };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=file-watcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher.mjs","names":["fsWatch"],"sources":["../../../../src/substrate/runtime/lifecycle/file-watcher.ts"],"sourcesContent":["// L0 file watcher — the \"thick watcher\" the lifecycle architecture\n// describes (§ L3 Watch dispatcher: \"receives watcher events from L0\n// which already debounced + dedup'd\").\n//\n// Generic: it watches the literal roots derived from the supervisor's\n// watch index — the union of every plugin's declared `watch` paths,\n// whatever they are — and feeds each changed path to `notifyWatchFire`,\n// which attributes it to the owning plugin(s) and issues a selective\n// restart (→ re-acquire → re-cache-key → cache-miss → re-produce). The\n// package plugin's Move sources are today's only declarer, but nothing\n// here is Move-specific. Without this, the watch index +\n// `notifyWatchFire` are built but never driven, so a `watch`-declaring\n// plugin never restarts on a source edit.\n//\n// Dev-only: wired from the `up` verb (see `cli/wirings/up.ts`). `apply`\n// and the snapshot verbs boot once and exit, so they never start it.\n//\n// Dependency-free by design — devstack pulls in no glob/watch library\n// (cf. the hand-rolled `collectHashedSources`). Node's recursive\n// `fs.watch` is supported on macOS and Windows, and on Linux from\n// Node 20; one watcher is placed per distinct root.\n\nimport { type FSWatcher, watch as fsWatch } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { Effect, Queue, Scope } from 'effect';\n\nimport { deriveWatchRoots, type WatchEntry } from './watch-attribution.ts';\n\n/** Coalescing window for a burst of fs events. Editors save by\n * rename-replace (temp write + rename), so a single save surfaces as\n * several events within a few ms — one settle window collapses them\n * into one restart per plugin. */\nconst DEFAULT_DEBOUNCE_MILLIS = 150;\n\nexport interface FileWatcherParams {\n\treadonly watchIndex: ReadonlyArray<WatchEntry>;\n\treadonly notifyWatchFire: (path: string) => Effect.Effect<void>;\n\treadonly debounceMillis?: number;\n}\n\n/**\n * Start the L0 file watcher. Acquires one recursive `fs.watch` per\n * distinct root (released on scope close) and forks a debouncing drain\n * loop that fires `notifyWatchFire` for each distinct changed path.\n * Returns once the watchers + loop are installed; it lives for the\n * lifetime of the surrounding scope, so callers `Effect.forkScoped` it\n * (or just `yield*` it inside a scoped region).\n *\n * Watcher setup never fails the boot: a root that cannot be watched\n * (e.g. a not-yet-created directory) is logged and skipped.\n */\nexport const startFileWatcher = (\n\tparams: FileWatcherParams,\n): Effect.Effect<void, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst roots = deriveWatchRoots(params.watchIndex);\n\t\tif (roots.length === 0) return;\n\n\t\tconst debounceMillis = params.debounceMillis ?? DEFAULT_DEBOUNCE_MILLIS;\n\t\t// Bounded so a pathological event storm (e.g. a `git checkout` touching\n\t\t// thousands of files) can't grow the queue unboundedly; offers into a\n\t\t// dropping queue never suspend, so the fs.watch callback stays cheap.\n\t\t// 1024 comfortably covers a normal multi-file save burst, whose\n\t\t// duplicates the drain loop collapses within the settle window into one\n\t\t// restart per plugin. If a burst ever exceeds the bound the overflow is\n\t\t// dropped — at worst a reload is missed until the next edit re-fires the\n\t\t// path (and dev reload stays manually recoverable).\n\t\tconst events = yield* Queue.dropping<string>(1024);\n\t\t// Capture the supervisor Context so the offer fork inherits its\n\t\t// logger Layer / fiber-refs (mirrors `installSignalHandler`); a bare\n\t\t// `Effect.runFork` would evaluate against an empty context.\n\t\tconst supervisorContext = yield* Effect.context<never>();\n\t\tconst runForkInherited = Effect.runForkWith(supervisorContext);\n\n\t\tfor (const root of roots) {\n\t\t\tconst watcher = yield* Effect.acquireRelease(\n\t\t\t\tEffect.sync((): FSWatcher | null => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst fsWatcher = fsWatch(root, { recursive: true }, (_eventType, filename) => {\n\t\t\t\t\t\t\tif (filename === null) return;\n\t\t\t\t\t\t\tconst abs = join(root, filename.toString());\n\t\t\t\t\t\t\t// Bridge the Node callback into the queue via the captured\n\t\t\t\t\t\t\t// Context. Dropping queue ⇒ offer never suspends.\n\t\t\t\t\t\t\trunForkInherited(Queue.offer(events, abs));\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// A watcher-level error (e.g. the root was removed) must not\n\t\t\t\t\t\t// crash the supervisor; swallow it. Scope close still calls\n\t\t\t\t\t\t// `close()` on the finalizer below.\n\t\t\t\t\t\tfsWatcher.on('error', () => {});\n\t\t\t\t\t\treturn fsWatcher;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\t(watcher) => Effect.sync(() => watcher?.close()),\n\t\t\t);\n\t\t\tif (watcher === null) {\n\t\t\t\tyield* Effect.logWarning(`file-watcher: could not watch ${root}`);\n\t\t\t}\n\t\t}\n\n\t\t// Drain loop: block for one change, settle, then drain + dedup the\n\t\t// burst and fire each distinct path once. `notifyWatchFire` itself\n\t\t// dedups owning plugins, so editing several files in one save yields\n\t\t// one restart per affected plugin.\n\t\tconst drain = Effect.gen(function* () {\n\t\t\tconst first = yield* Queue.take(events);\n\t\t\tyield* Effect.sleep(`${debounceMillis} millis`);\n\t\t\tconst rest = yield* Queue.takeAll(events);\n\t\t\tconst paths = new Set<string>([first, ...rest]);\n\t\t\tfor (const path of paths) {\n\t\t\t\tyield* params.notifyWatchFire(path);\n\t\t\t}\n\t\t}).pipe(Effect.forever);\n\n\t\tyield* Effect.forkScoped(drain);\n\t});\n"],"mappings":";;;;;;;;;AAiCA,MAAM,0BAA0B;;;;;;;;;;;;AAmBhC,MAAa,oBACZ,WAEA,OAAO,IAAI,aAAa;CACvB,MAAM,QAAQ,iBAAiB,OAAO,UAAU;CAChD,IAAI,MAAM,WAAW,GAAG;CAExB,MAAM,iBAAiB,OAAO,kBAAkB;CAShD,MAAM,SAAS,OAAO,MAAM,SAAiB,IAAI;CAIjD,MAAM,oBAAoB,OAAO,OAAO,QAAe;CACvD,MAAM,mBAAmB,OAAO,YAAY,iBAAiB;CAE7D,KAAK,MAAM,QAAQ,OAsBlB,KAAI,OArBmB,OAAO,eAC7B,OAAO,WAA6B;EACnC,IAAI;GACH,MAAM,YAAYA,MAAQ,MAAM,EAAE,WAAW,KAAK,IAAI,YAAY,aAAa;IAC9E,IAAI,aAAa,MAAM;IACvB,MAAM,MAAM,KAAK,MAAM,SAAS,SAAS,CAAC;IAG1C,iBAAiB,MAAM,MAAM,QAAQ,GAAG,CAAC;GAC1C,CAAC;GAID,UAAU,GAAG,eAAe,CAAC,CAAC;GAC9B,OAAO;EACR,QAAQ;GACP,OAAO;EACR;CACD,CAAC,IACA,YAAY,OAAO,WAAW,SAAS,MAAM,CAAC,CAChD,OACgB,MACf,OAAO,OAAO,WAAW,iCAAiC,MAAM;CAQlE,MAAM,QAAQ,OAAO,IAAI,aAAa;EACrC,MAAM,QAAQ,OAAO,MAAM,KAAK,MAAM;EACtC,OAAO,OAAO,MAAM,GAAG,eAAe,QAAQ;EAC9C,MAAM,OAAO,OAAO,MAAM,QAAQ,MAAM;EACxC,MAAM,QAAQ,IAAI,IAAY,CAAC,OAAO,GAAG,IAAI,CAAC;EAC9C,KAAK,MAAM,QAAQ,OAClB,OAAO,OAAO,gBAAgB,IAAI;CAEpC,CAAC,CAAC,CAAC,KAAK,OAAO,OAAO;CAEtB,OAAO,OAAO,WAAW,KAAK;AAC/B,CAAC"}
|