@mysten-incubation/devstack 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/seal/codegen.ts"],"sourcesContent":["// Seal plugin — Codegenable contribution, via the UNIFIED config-binding\n// declaration.\n//\n// The seal plugin contributes ONE codegen shape — the `seal-key-server`\n// config the user-facing bindings consume to construct a `SealClient`.\n//\n// ONE declaration, TWO derivations (see `contracts/config-bindings.ts`). Every\n// seal instance folds into a single `generated/seal.ts` exporting\n// `export const seal = { <name>: SealBindings, ... }` (sibling-keyed bucket):\n// - LIVE (boot): bakes the resolved key-server object id / URL / configs\n// AND feeds the generic deployment `values` channel.\n// - STATIC (committed tree): emits `requireValue(dep, 'seal:<name>', '<key>')`\n// so the committed `seal.ts` carries NO baked object id / endpoint URL.\n//\n// STRUCTURAL fields (`name`, `mode`) stay literals; the object id, key-server\n// URL, and `serverConfigs` committee (an array blob) are RUNTIME (loaded\n// config data), resolved at app build/dev time.\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\nimport {\n\tkeyedBucketSpec,\n\tliveBucketCodegen,\n\tstaticBucketCodegen,\n\ttype BucketField,\n\ttype SiblingBucketSpec,\n} from '../../contracts/config-bindings.ts';\nimport type { JsonValue } from '../../orchestrators/codegen/deployment.ts';\nimport type { SealKeyServerEntry } from './registry-publish.ts';\n\n/** Codegen-emitted shape for seal. */\nexport interface SealBindings {\n\treadonly name: string;\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n\treadonly serverConfigs: ReadonlyArray<SealKeyServerEntry>;\n\treadonly mode: 'local-keygen' | 'live' | 'fork-known';\n}\n\n/** User-declared known seal ids, available at factory time. The `live` and\n * `fork-known` modes resolve their `{objectId, keyServerUrl, serverConfigs}`\n * tuple at factory time (DECLARED config), so the committed `seal.ts` bakes\n * them as LITERALS. Absent for `local-keygen` (dev-deployed) whose key-server\n * ids/URL are dynamic. */\nexport interface SealKnownIds {\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n\treadonly serverConfigs: ReadonlyArray<SealKeyServerEntry>;\n}\n\n/** Static-config shape a seal instance knows BEFORE acquire — the\n * structural names the stack-free `staticCodegen` hook needs. When `known`\n * is present (live / fork-known), its declared ids are baked as literals;\n * otherwise (local-keygen) every id resolves at app build/dev time. */\nexport interface SealStaticConfig {\n\treadonly name: string;\n\treadonly mode: SealBindings['mode'];\n\treadonly known?: SealKnownIds;\n}\n\ntype SealLiveState = SealBindings;\n\n/** Build the seal instance's config-binding spec for `name`. `name` / `mode`\n * are structural literals. For a `local-keygen` instance the object id / URL\n * are dynamically-deployed (`requireValue(dep, …)`) and `serverConfigs` is a runtime\n * committee blob; for a `live` / `fork-known` instance these are DECLARED\n * config, baked as literals. */\nconst sealBucketSpec = (structural: SealStaticConfig): SiblingBucketSpec<SealLiveState> => {\n\tconst known = structural.known;\n\tconst fields: ReadonlyArray<BucketField<SealLiveState>> =\n\t\tknown !== undefined\n\t\t\t? [\n\t\t\t\t\t{ key: 'name', variant: 'literal', value: structural.name },\n\t\t\t\t\t{ key: 'mode', variant: 'literal', value: structural.mode },\n\t\t\t\t\t{ key: 'objectId', variant: 'literal', value: known.objectId },\n\t\t\t\t\t{ key: 'keyServerUrl', variant: 'literal', value: known.keyServerUrl },\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'serverConfigs',\n\t\t\t\t\t\tvariant: 'literal',\n\t\t\t\t\t\tvalue: known.serverConfigs as unknown as JsonValue,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t{ key: 'name', variant: 'literal', value: structural.name },\n\t\t\t\t\t{ key: 'mode', variant: 'literal', value: structural.mode },\n\t\t\t\t\t{ key: 'objectId', variant: 'resolved', tsType: 'string', live: (s) => s.objectId },\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'keyServerUrl',\n\t\t\t\t\t\tvariant: 'resolved',\n\t\t\t\t\t\ttsType: 'string',\n\t\t\t\t\t\tlive: (s) => s.keyServerUrl,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'serverConfigs',\n\t\t\t\t\t\tvariant: 'resolved',\n\t\t\t\t\t\t// Inline structural literal mirroring `SealKeyServerEntry` so the\n\t\t\t\t\t\t// committed `seal.ts` carries the concrete type (no emitted import).\n\t\t\t\t\t\ttsType:\n\t\t\t\t\t\t\t'ReadonlyArray<{ readonly objectId: string; readonly weight: number; readonly aggregatorUrl?: string }>',\n\t\t\t\t\t\tlive: (s) => s.serverConfigs as unknown as JsonValue,\n\t\t\t\t\t},\n\t\t\t\t];\n\treturn keyedBucketSpec({ bucket: 'seal.ts', kind: 'seal', key: structural.name, fields });\n};\n\n/** Build the LIVE Codegenable contribution for a seal instance. Bakes the\n * resolved key-server fields + feeds the generic deployment `values`\n * channel. */\nexport const makeSealCodegenable = (bindings: SealBindings): CodegenableDecl =>\n\tliveBucketCodegen(sealBucketSpec({ name: bindings.name, mode: bindings.mode }), bindings);\n\n/** Build the STATIC (stack-free) Codegenable contribution for a seal\n * instance. Emits `requireValue(dep, 'seal:<name>', '<key>')` for the runtime\n * fields; the committed `seal.ts` carries no baked object id / endpoint URL. */\nexport const makeSealStaticCodegen = (config: SealStaticConfig): CodegenableDecl =>\n\tstaticBucketCodegen(sealBucketSpec(config));\n"],"mappings":";;;;;;;AAkEA,MAAM,kBAAkB,eAAmE;CAC1F,MAAM,QAAQ,WAAW;CACzB,MAAM,SACL,UAAU,KAAA,IACP;EACA;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAY,SAAS;GAAW,OAAO,MAAM;EAAS;EAC7D;GAAE,KAAK;GAAgB,SAAS;GAAW,OAAO,MAAM;EAAa;EACrE;GACC,KAAK;GACL,SAAS;GACT,OAAO,MAAM;EACd;CACD,IACC;EACA;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAY,SAAS;GAAY,QAAQ;GAAU,OAAO,MAAM,EAAE;EAAS;EAClF;GACC,KAAK;GACL,SAAS;GACT,QAAQ;GACR,OAAO,MAAM,EAAE;EAChB;EACA;GACC,KAAK;GACL,SAAS;GAGT,QACC;GACD,OAAO,MAAM,EAAE;EAChB;CACD;CACH,OAAO,gBAAgB;EAAE,QAAQ;EAAW,MAAM;EAAQ,KAAK,WAAW;EAAM;CAAO,CAAC;AACzF;;;;AAKA,MAAa,uBAAuB,aACnC,kBAAkB,eAAe;CAAE,MAAM,SAAS;CAAM,MAAM,SAAS;AAAK,CAAC,GAAG,QAAQ;;;;AAKzF,MAAa,yBAAyB,WACrC,oBAAoB,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/seal/codegen.ts"],"sourcesContent":["// Seal plugin — Codegenable contribution, via the UNIFIED config-binding\n// declaration.\n//\n// The seal plugin contributes ONE codegen shape — the `seal-key-server`\n// config the user-facing bindings consume to construct a `SealClient`.\n//\n// ONE declaration, TWO derivations (see `contracts/config-bindings.ts`). Every\n// seal instance folds into a single `generated/seal.ts` exporting\n// `export const seal = { <name>: SealBindings, ... }` (sibling-keyed bucket):\n// - LIVE (boot): bakes the resolved key-server object id / URL / configs\n// AND feeds the generic deployment `values` channel.\n// - STATIC (committed tree): emits `requireValue(dep, 'seal:<name>', '<key>')`\n// so the committed `seal.ts` carries NO baked object id / endpoint URL.\n//\n// STRUCTURAL fields (`name`, `mode`) stay literals; the object id, key-server\n// URL, and `serverConfigs` committee (an array blob) are RUNTIME (loaded\n// config data), resolved at app build/dev time.\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\nimport {\n\tkeyedBucketSpec,\n\tliveBucketCodegen,\n\tstaticBucketCodegen,\n\ttype BucketField,\n\ttype SiblingBucketSpec,\n} from '../../contracts/config-bindings.ts';\nimport type { JsonValue } from '../../orchestrators/codegen/deployment.ts';\nimport type { SealKeyServerEntry } from './registry-publish.ts';\n\n/** Static-codegen TS type for the `serverConfigs` field — mirrors\n * `SealKeyServerEntry` (the structural literal so the committed `seal.ts`\n * carries the concrete type with NO emitted import). The `apiKey?` slot is\n * kept in the TYPE so a consumer can inject the secret at runtime, but devstack\n * never emits a `apiKey` VALUE (see `stripApiKey`). */\nconst SERVER_CONFIGS_TS_TYPE =\n\t'ReadonlyArray<{ readonly objectId: string; readonly weight: number; readonly apiKeyName?: string; readonly apiKey?: string; readonly aggregatorUrl?: string }>';\n\n/** Defense-in-depth: drop any `apiKey` from an emitted `serverConfigs` array.\n * devstack NEVER carries the secret committee apiKey value — both the committed\n * `seal.ts` and the browser-injected `deployment.json` (the `values` channel)\n * are world-readable. `validateLiveInputs` already refuses to accept an apiKey,\n * so this is belt-and-suspenders at the codegen boundary. The app injects the\n * apiKey into `serverConfigs` at runtime, keyed by the emitted non-secret\n * `apiKeyName`. */\nconst stripApiKey = (serverConfigs: ReadonlyArray<SealKeyServerEntry>): JsonValue =>\n\tserverConfigs.map((entry) => {\n\t\tconst rest: Record<string, unknown> = { ...entry };\n\t\tdelete rest.apiKey;\n\t\treturn rest;\n\t}) as unknown as JsonValue;\n\n/** Codegen-emitted shape for seal. */\nexport interface SealBindings {\n\treadonly name: string;\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n\treadonly serverConfigs: ReadonlyArray<SealKeyServerEntry>;\n\t/** Whether the SDK should verify the key servers (true on live /\n\t * fork-known, false on local-keygen). Declared config — known at\n\t * factory time, emitted as a plain boolean literal (never a\n\t * `requireValue`, since it's not a secret). */\n\treadonly verifyKeyServers: boolean;\n\treadonly mode: 'local-keygen' | 'live' | 'fork-known';\n}\n\n/** User-declared known seal ids, available at factory time. The `live` and\n * `fork-known` modes resolve their `{objectId, keyServerUrl, serverConfigs}`\n * tuple at factory time (DECLARED config), so the committed `seal.ts` bakes\n * them as LITERALS. Absent for `local-keygen` (dev-deployed) whose key-server\n * ids/URL are dynamic. */\nexport interface SealKnownIds {\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n\treadonly serverConfigs: ReadonlyArray<SealKeyServerEntry>;\n\treadonly verifyKeyServers: boolean;\n}\n\n/** Static-config shape a seal instance knows BEFORE acquire — the\n * structural names the stack-free `staticCodegen` hook needs. When `known`\n * is present (live / fork-known), its declared ids are baked as literals;\n * otherwise (local-keygen) every id resolves at app build/dev time. */\nexport interface SealStaticConfig {\n\treadonly name: string;\n\treadonly mode: SealBindings['mode'];\n\treadonly known?: SealKnownIds;\n}\n\ntype SealLiveState = SealBindings;\n\n/** Build the seal instance's config-binding spec for `name`. `name` / `mode`\n * are structural literals. For a `local-keygen` instance the object id / URL\n * are dynamically-deployed (`requireValue(dep, …)`) and `serverConfigs` is a runtime\n * committee blob; for a `live` / `fork-known` instance these are DECLARED\n * config, baked as literals. */\nconst sealBucketSpec = (structural: SealStaticConfig): SiblingBucketSpec<SealLiveState> => {\n\tconst known = structural.known;\n\tconst fields: ReadonlyArray<BucketField<SealLiveState>> =\n\t\tknown !== undefined\n\t\t\t? [\n\t\t\t\t\t{ key: 'name', variant: 'literal', value: structural.name },\n\t\t\t\t\t{ key: 'mode', variant: 'literal', value: structural.mode },\n\t\t\t\t\t{ key: 'objectId', variant: 'literal', value: known.objectId },\n\t\t\t\t\t{ key: 'keyServerUrl', variant: 'literal', value: known.keyServerUrl },\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'serverConfigs',\n\t\t\t\t\t\tvariant: 'literal',\n\t\t\t\t\t\t// Bake objectId / weight / aggregatorUrl / apiKeyName as literals.\n\t\t\t\t\t\t// Any apiKey is stripped — devstack never carries the secret; the\n\t\t\t\t\t\t// app injects it at runtime keyed by apiKeyName.\n\t\t\t\t\t\tvalue: stripApiKey(known.serverConfigs),\n\t\t\t\t\t},\n\t\t\t\t\t// Declared config: a plain boolean literal (not a secret, so never\n\t\t\t\t\t// a `requireValue`). True on live / fork-known.\n\t\t\t\t\t{ key: 'verifyKeyServers', variant: 'literal', value: known.verifyKeyServers },\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t{ key: 'name', variant: 'literal', value: structural.name },\n\t\t\t\t\t{ key: 'mode', variant: 'literal', value: structural.mode },\n\t\t\t\t\t{ key: 'objectId', variant: 'resolved', tsType: 'string', live: (s) => s.objectId },\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'keyServerUrl',\n\t\t\t\t\t\tvariant: 'resolved',\n\t\t\t\t\t\ttsType: 'string',\n\t\t\t\t\t\tlive: (s) => s.keyServerUrl,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'serverConfigs',\n\t\t\t\t\t\tvariant: 'resolved',\n\t\t\t\t\t\t// Inline structural literal mirroring `SealKeyServerEntry` so the\n\t\t\t\t\t\t// committed `seal.ts` carries the concrete type (no emitted import).\n\t\t\t\t\t\t// `stripApiKey` guards the world-readable `values` channel — the\n\t\t\t\t\t\t// resolved blob must never carry a secret apiKey.\n\t\t\t\t\t\ttsType: SERVER_CONFIGS_TS_TYPE,\n\t\t\t\t\t\tlive: (s) => stripApiKey(s.serverConfigs),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'verifyKeyServers',\n\t\t\t\t\t\tvariant: 'resolved',\n\t\t\t\t\t\ttsType: 'boolean',\n\t\t\t\t\t\tlive: (s) => s.verifyKeyServers,\n\t\t\t\t\t},\n\t\t\t\t];\n\treturn keyedBucketSpec({ bucket: 'seal.ts', kind: 'seal', key: structural.name, fields });\n};\n\n/** Build the LIVE Codegenable contribution for a seal instance.\n *\n * Live / fork-known deployments resolve their ids at factory time, so they\n * are DECLARED config — pass `known` so they bake as literals (the SAME branch\n * the static codegen uses). This keeps the two derivations consistent AND\n * keeps the known `serverConfigs` OUT of the world-readable `values` channel\n * entirely (literals don't ride `values`). Only `local-keygen`'s\n * dynamically-deployed ids flow through the resolved/`values` channel. */\nexport const makeSealCodegenable = (bindings: SealBindings): CodegenableDecl => {\n\tconst known: SealKnownIds | undefined =\n\t\tbindings.mode === 'local-keygen'\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t\tverifyKeyServers: bindings.verifyKeyServers,\n\t\t\t\t};\n\treturn liveBucketCodegen(\n\t\tsealBucketSpec({ name: bindings.name, mode: bindings.mode, known }),\n\t\tbindings,\n\t);\n};\n\n/** Build the STATIC (stack-free) Codegenable contribution for a seal\n * instance. Emits `requireValue(dep, 'seal:<name>', '<key>')` for the runtime\n * fields; the committed `seal.ts` carries no baked object id / endpoint URL. */\nexport const makeSealStaticCodegen = (config: SealStaticConfig): CodegenableDecl =>\n\tstaticBucketCodegen(sealBucketSpec(config));\n"],"mappings":";;;;;;;AAkCA,MAAM,yBACL;;;;;;;;AASD,MAAM,eAAe,kBACpB,cAAc,KAAK,UAAU;CAC5B,MAAM,OAAgC,EAAE,GAAG,MAAM;CACjD,OAAO,KAAK;CACZ,OAAO;AACR,CAAC;;;;;;AA6CF,MAAM,kBAAkB,eAAmE;CAC1F,MAAM,QAAQ,WAAW;CACzB,MAAM,SACL,UAAU,KAAA,IACP;EACA;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAY,SAAS;GAAW,OAAO,MAAM;EAAS;EAC7D;GAAE,KAAK;GAAgB,SAAS;GAAW,OAAO,MAAM;EAAa;EACrE;GACC,KAAK;GACL,SAAS;GAIT,OAAO,YAAY,MAAM,aAAa;EACvC;EAGA;GAAE,KAAK;GAAoB,SAAS;GAAW,OAAO,MAAM;EAAiB;CAC9E,IACC;EACA;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAQ,SAAS;GAAW,OAAO,WAAW;EAAK;EAC1D;GAAE,KAAK;GAAY,SAAS;GAAY,QAAQ;GAAU,OAAO,MAAM,EAAE;EAAS;EAClF;GACC,KAAK;GACL,SAAS;GACT,QAAQ;GACR,OAAO,MAAM,EAAE;EAChB;EACA;GACC,KAAK;GACL,SAAS;GAKT,QAAQ;GACR,OAAO,MAAM,YAAY,EAAE,aAAa;EACzC;EACA;GACC,KAAK;GACL,SAAS;GACT,QAAQ;GACR,OAAO,MAAM,EAAE;EAChB;CACD;CACH,OAAO,gBAAgB;EAAE,QAAQ;EAAW,MAAM;EAAQ,KAAK,WAAW;EAAM;CAAO,CAAC;AACzF;;;;;;;;;AAUA,MAAa,uBAAuB,aAA4C;CAC/E,MAAM,QACL,SAAS,SAAS,iBACf,KAAA,IACA;EACA,UAAU,SAAS;EACnB,cAAc,SAAS;EACvB,eAAe,SAAS;EACxB,kBAAkB,SAAS;CAC5B;CACH,OAAO,kBACN,eAAe;EAAE,MAAM,SAAS;EAAM,MAAM,SAAS;EAAM;CAAM,CAAC,GAClE,QACD;AACD;;;;AAKA,MAAa,yBAAyB,WACrC,oBAAoB,eAAe,MAAM,CAAC"}
@@ -4,10 +4,10 @@ import { SuiOptions } from "../sui/mode/spec.mjs";
4
4
  import { SuiClient } from "../sui/mode/shared.mjs";
5
5
  import { AccountValue } from "../account/service.mjs";
6
6
  import { AccountResourceId } from "../account/index.mjs";
7
+ import { SealAnyError, SealConfigError, SealError } from "./errors.mjs";
7
8
  import { SealKeyManager } from "./key-manager.mjs";
8
9
  import { SealKeyServer, SealKeyServerEntry, SealKnownResolved, SealLocalKeygenResolved, SealResolved } from "./registry-publish.mjs";
9
- import { SealAnyError, SealConfigError, SealError } from "./errors.mjs";
10
- import { KnownNetwork } from "./mode/live.mjs";
10
+ import { KnownNetwork, SealServerKind } from "./mode/live.mjs";
11
11
  import { ForkUpstream } from "./mode/fork-known.mjs";
12
12
  import { SealBindings } from "./codegen.mjs";
13
13
  //#region src/plugins/seal/index.d.ts
@@ -42,17 +42,38 @@ interface SealLocalKeygenOptions<Signer extends SealSignerMember = SealSignerMem
42
42
  };
43
43
  };
44
44
  }
45
- /** Live-mode options (testnet / mainnet). */
45
+ /** Live-mode options (testnet / mainnet).
46
+ *
47
+ * Zero-config `testnet()` resolves BOTH independent servers;
48
+ * `mainnet()` resolves the committee (which requires credentials — declare
49
+ * the non-secret `apiKeyName`). `{ server: 'committee' }` opts a testnet
50
+ * stack into the committee aggregator. `serverConfigs` is the raw verbatim
51
+ * override. `verifyKeyServers` defaults to the SDK default (true) on live /
52
+ * known — omit it; only local-keygen forces it false. This default also
53
+ * applies to a verbatim `serverConfigs` override: for a private / unregistered
54
+ * key server (whose on-chain registration can't be verified), pass
55
+ * `verifyKeyServers: false` explicitly.
56
+ *
57
+ * NOTE: devstack never carries the secret committee `apiKey` value (committed
58
+ * config + the browser-injected `deployment.json` are world-readable). Pass
59
+ * `apiKeyName` (the header name) and inject the apiKey at runtime when you
60
+ * construct `SealClient`. */
46
61
  interface SealLiveOptions extends SealCommonOptions {
47
62
  readonly network?: KnownNetwork;
48
- readonly objectId?: string;
49
- readonly keyServerUrl?: string;
63
+ readonly server?: SealServerKind;
64
+ readonly apiKeyName?: string;
65
+ readonly verifyKeyServers?: boolean;
66
+ readonly serverConfigs?: ReadonlyArray<SealKeyServerEntry>;
50
67
  }
51
- /** Fork-known-mode options. */
68
+ /** Fork-known-mode options. The `*-fork` network routes to the wrapped
69
+ * upstream's known deployment; `server` / `apiKeyName` mirror the live
70
+ * selectors (the secret apiKey is injected by the app at runtime, never
71
+ * carried by devstack). */
52
72
  interface SealForkKnownOptions extends SealCommonOptions {
53
73
  readonly upstream: ForkUpstream;
54
- readonly objectId?: string;
55
- readonly keyServerUrl?: string;
74
+ readonly server?: SealServerKind;
75
+ readonly apiKeyName?: string;
76
+ readonly verifyKeyServers?: boolean;
56
77
  }
57
78
  type SealOptions<Signer extends SealSignerMember = SealSignerMember> = ({
58
79
  readonly mode: 'local-keygen';
@@ -73,7 +94,21 @@ declare const seal: <const Signer extends SealSignerMember = SealSignerMember>(o
73
94
  readonly mode: SuiOptions["mode"];
74
95
  }>;
75
96
  readonly signer: Signer;
76
- } ? T extends Readonly<Record<string, AnyResourceRef>> ? readonly T[keyof T][] : readonly [] : never : never> | Plugin<`seal:${string}`, SealResolved, readonly []>;
97
+ } ? T extends Readonly<Record<string, AnyResourceRef>> ? readonly T[keyof T][] : readonly [] : never : never> | Plugin<`seal:${string}`, {
98
+ serverConfigs: readonly SealKeyServerEntry[];
99
+ keyServerUrl: string;
100
+ objectId: string;
101
+ verifyKeyServers: boolean;
102
+ mode: "live";
103
+ manager: null;
104
+ }, readonly []> | Plugin<`seal:${string}`, {
105
+ serverConfigs: readonly SealKeyServerEntry[];
106
+ keyServerUrl: string;
107
+ objectId: string;
108
+ verifyKeyServers: boolean;
109
+ mode: "fork-known";
110
+ manager: null;
111
+ }, readonly []>;
77
112
  /** Mode-narrowed factory namespace.
78
113
  *
79
114
  * Usage:
@@ -105,29 +140,39 @@ declare const sealFor: ModeNamespace<{
105
140
  };
106
141
  live: {
107
142
  testnet: (opts?: Omit<SealLiveOptions, "network">) => Plugin<`seal:${string}`, {
108
- mode: "live";
109
- manager: null;
110
- serverConfigs: ReadonlyArray<SealKeyServerEntry>;
143
+ serverConfigs: readonly SealKeyServerEntry[];
111
144
  keyServerUrl: string;
112
145
  objectId: string;
113
- }, readonly []>;
114
- mainnet: (opts?: Omit<SealLiveOptions, "network">) => Plugin<`seal:${string}`, {
146
+ verifyKeyServers: boolean;
115
147
  mode: "live";
116
148
  manager: null;
117
- serverConfigs: ReadonlyArray<SealKeyServerEntry>;
149
+ }, readonly []>;
150
+ mainnet: (opts?: Omit<SealLiveOptions, "network">) => Plugin<`seal:${string}`, {
151
+ serverConfigs: readonly SealKeyServerEntry[];
118
152
  keyServerUrl: string;
119
153
  objectId: string;
120
- }, readonly []>;
121
- custom: (opts: Required<Pick<SealLiveOptions, "objectId" | "keyServerUrl">> & SealLiveOptions) => Plugin<`seal:${string}`, {
154
+ verifyKeyServers: boolean;
122
155
  mode: "live";
123
156
  manager: null;
124
- serverConfigs: ReadonlyArray<SealKeyServerEntry>;
157
+ }, readonly []>;
158
+ custom: (opts: Required<Pick<SealLiveOptions, "serverConfigs">> & SealLiveOptions) => Plugin<`seal:${string}`, {
159
+ serverConfigs: readonly SealKeyServerEntry[];
125
160
  keyServerUrl: string;
126
161
  objectId: string;
162
+ verifyKeyServers: boolean;
163
+ mode: "live";
164
+ manager: null;
127
165
  }, readonly []>;
128
166
  };
129
167
  fork: {
130
- forkKnown: (opts: SealForkKnownOptions) => Plugin<`seal:${string}`, SealResolved, readonly []>;
168
+ forkKnown: (opts: SealForkKnownOptions) => Plugin<`seal:${string}`, {
169
+ serverConfigs: readonly SealKeyServerEntry[];
170
+ keyServerUrl: string;
171
+ objectId: string;
172
+ verifyKeyServers: boolean;
173
+ mode: "fork-known";
174
+ manager: null;
175
+ }, readonly []>;
131
176
  };
132
177
  }>;
133
178
  //#endregion
@@ -21,7 +21,6 @@ import { DEFAULT_SEAL_VERSION } from "./bootstrap-assets/source-fetch.mjs";
21
21
  import { bootLocalKeygen, resolveLocalKeygenOptions } from "./mode/local-keygen.mjs";
22
22
  import { makeSealResource } from "./registry-publish.mjs";
23
23
  import { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from "./snapshot.mjs";
24
- import { bootSealService } from "./service.mjs";
25
24
  import { Effect, FileSystem, Path } from "effect";
26
25
  //#region src/plugins/seal/index.ts
27
26
  /** Constants + shared knobs for the buildXyz helpers below. */
@@ -116,6 +115,7 @@ const buildLocalKeygenPlugin = (opts) => {
116
115
  objectId: resolvedValue.objectId,
117
116
  keyServerUrl: resolvedValue.keyServerUrl,
118
117
  serverConfigs: resolvedValue.serverConfigs,
118
+ verifyKeyServers: resolvedValue.verifyKeyServers,
119
119
  mode: "local-keygen"
120
120
  }));
121
121
  ctx.endpoint(makeSealRoutable({
@@ -130,18 +130,16 @@ const buildLocalKeygenPlugin = (opts) => {
130
130
  const buildLivePlugin = (opts) => {
131
131
  const name = opts.name ?? DEFAULT_NAME;
132
132
  const sealResource = makeSealResource(name);
133
- const validated = validateLiveInputs({
133
+ const resolved = validateLiveInputs({
134
134
  name,
135
135
  ...opts
136
136
  });
137
137
  const bindings = {
138
138
  name,
139
- objectId: validated.objectId,
140
- keyServerUrl: validated.keyServerUrl,
141
- serverConfigs: [{
142
- objectId: validated.objectId,
143
- weight: 1
144
- }],
139
+ objectId: resolved.objectId,
140
+ keyServerUrl: resolved.keyServerUrl,
141
+ serverConfigs: resolved.serverConfigs,
142
+ verifyKeyServers: resolved.verifyKeyServers,
145
143
  mode: "live"
146
144
  };
147
145
  const snap = makeKnownSnapshotable({ name });
@@ -155,21 +153,19 @@ const buildLivePlugin = (opts) => {
155
153
  known: {
156
154
  objectId: bindings.objectId,
157
155
  keyServerUrl: bindings.keyServerUrl,
158
- serverConfigs: bindings.serverConfigs
156
+ serverConfigs: bindings.serverConfigs,
157
+ verifyKeyServers: bindings.verifyKeyServers
159
158
  }
160
159
  })],
161
160
  start: () => Effect.gen(function* () {
162
161
  const ctx = yield* PluginContext;
163
- const mode = {
164
- mode: "live",
165
- name,
166
- resolved: validated
167
- };
168
- const resolved = yield* bootSealService(yield* CacheService, mode);
169
162
  ctx.snapshotExtra(snap);
170
163
  ctx.codegen(makeSealCodegenable(bindings));
171
164
  return {
172
- ...resolved.keyServer,
165
+ serverConfigs: resolved.serverConfigs,
166
+ keyServerUrl: resolved.keyServerUrl,
167
+ objectId: resolved.objectId,
168
+ verifyKeyServers: resolved.verifyKeyServers,
173
169
  mode: "live",
174
170
  manager: null
175
171
  };
@@ -206,35 +202,29 @@ const buildForkKnownPlugin = (opts) => {
206
202
  known: {
207
203
  objectId: validated.objectId,
208
204
  keyServerUrl: validated.keyServerUrl,
209
- serverConfigs: [{
210
- objectId: validated.objectId,
211
- weight: 1
212
- }]
205
+ serverConfigs: validated.serverConfigs,
206
+ verifyKeyServers: validated.verifyKeyServers
213
207
  }
214
208
  })],
215
209
  start: () => Effect.gen(function* () {
216
210
  const ctx = yield* PluginContext;
217
- const mode = {
218
- mode: "fork-known",
219
- name,
220
- upstream: opts.upstream,
221
- resolved: validated
222
- };
223
- const resolved = yield* bootSealService(yield* CacheService, mode);
224
- const resolvedValue = {
225
- ...resolved.keyServer,
226
- mode: "fork-known",
227
- manager: null
228
- };
229
211
  ctx.snapshotExtra(snap);
230
212
  ctx.codegen(makeSealCodegenable({
231
213
  name,
232
- objectId: resolved.keyServer.objectId,
233
- keyServerUrl: resolved.keyServer.keyServerUrl,
234
- serverConfigs: resolved.keyServer.serverConfigs,
214
+ objectId: validated.objectId,
215
+ keyServerUrl: validated.keyServerUrl,
216
+ serverConfigs: validated.serverConfigs,
217
+ verifyKeyServers: validated.verifyKeyServers,
235
218
  mode: "fork-known"
236
219
  }));
237
- return resolvedValue;
220
+ return {
221
+ serverConfigs: validated.serverConfigs,
222
+ keyServerUrl: validated.keyServerUrl,
223
+ objectId: validated.objectId,
224
+ verifyKeyServers: validated.verifyKeyServers,
225
+ mode: "fork-known",
226
+ manager: null
227
+ };
238
228
  })
239
229
  });
240
230
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. `ctx.codegen` — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. `ctx.endpoint` — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, makeSealStaticCodegen, type SealBindings } from './codegen.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { bootSealService, type SealMode } from './service.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport { type SealError, type SealAnyError, type SealConfigError } from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet). */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n/** Fork-known-mode options. */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n// ---------------------------------------------------------------------------\n// The three seal `start` bodies emit their contributions inline via the typed\n// `ctx` verbs after resolving the value. The decl shapes + emit ORDER are\n// load-bearing.\n//\n// ⚠ ID-STABILITY: the snapshotable decl captures the seal vault / master-key\n// secret material subtree; its shape (subtree paths, container label tuple,\n// secretMaterial / missingTolerance flags) MUST stay byte-identical.\n// ---------------------------------------------------------------------------\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\t// Stack-free codegen: the key-server object id / URL / committee are\n\t\t// LOADED CONFIG DATA -- the committed `seal.ts` stub emits\n\t\t// `requireValue(dep, 'seal:<name>', '<key>')`, never a baked object id.\n\t\tstaticCodegen: () => [makeSealStaticCodegen({ name: resolved.name, mode: 'local-keygen' })],\n\t\t// `deps` auto-infers the resolved `{ sui, signer }` dependency\n\t\t// object from seal's `dependsOn: { sui: suiResource, signer:\n\t\t// opts.signer }`. `ctx` is the typed plugin-authoring surface the\n\t\t// contribution emission below drives; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chainId);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchainId: sui.chainId,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\t// Emit the resolved contributions inline: snapshot (seal vault /\n\t\t\t\t// master-key secret-material subtree) → codegen → routable (key\n\t\t\t\t// server). `resolvedValue` is the just-resolved `SealResolved`;\n\t\t\t\t// `identity` (from `IdentityContext`) stamps the snapshot +\n\t\t\t\t// routable container name. The codegen bindings carry the REAL\n\t\t\t\t// objectId / keyServerUrl / serverConfigs.\n\t\t\t\tctx.snapshotExtra(\n\t\t\t\t\tmakeLocalKeygenSnapshotable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tobjectId: resolvedValue.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolvedValue.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolvedValue.serverConfigs,\n\t\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeSealRoutable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work.\n\tconst validated = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: validated.objectId,\n\t\tkeyServerUrl: validated.keyServerUrl,\n\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}` tuple\n\t\t// at factory time (DECLARED config) — bake them as literals in the\n\t\t// committed `seal.ts` (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'live',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Live mode has no `dependsOn`, so `start` is zero-arg. `ctx`\n\t\t// drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst mode: SealMode = { mode: 'live', name, resolved: validated };\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\t// Emit inline: snapshot → codegen. `snap` + `bindings` are\n\t\t\t\t// resolved at FACTORY time for live mode (validated\n\t\t\t\t// `{objectId, keyServerUrl}`), so the emit reuses the same\n\t\t\t\t// precomputed values.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeSealCodegenable(bindings));\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Fork-known mode resolves its `{objectId, keyServerUrl}` tuple at\n\t\t// factory time (DECLARED config, via `validateForkKnownInputs`) — bake\n\t\t// them as literals in the committed `seal.ts` (mirrors `knownPackage`).\n\t\t// The committee `serverConfigs` is the single declared key-server (the\n\t\t// same shape `acquireLive` derives), so it is declared config too.\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'fork-known',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Fork-known mode has no `dependsOn`, so `start` is zero-arg.\n\t\t// `ctx` drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Symmetric with the live branch's `{ mode, name, resolved }`\n\t\t\t\t// envelope. `upstream` rides through for downstream\n\t\t\t\t// span attribution; `resolved` carries the validated\n\t\t\t\t// `{objectId, keyServerUrl}` tuple.\n\t\t\t\tconst mode: SealMode = {\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tname,\n\t\t\t\t\tupstream: opts.upstream,\n\t\t\t\t\tresolved: validated,\n\t\t\t\t};\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t};\n\t\t\t\t// Emit inline: snapshot → codegen. `bindings` is built from the\n\t\t\t\t// post-acquire `resolved.keyServer` (`{objectId, keyServerUrl,\n\t\t\t\t// serverConfigs}`); `snap` is factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tobjectId: resolved.keyServer.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolved.keyServer.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolved.keyServer.serverConfigs,\n\t\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\tcustom: (\n\t\t\topts: Required<Pick<SealLiveOptions, 'objectId' | 'keyServerUrl'>> & SealLiveOptions,\n\t\t) => buildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. `ctx.codegen` — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. `ctx.endpoint` — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, makeSealStaticCodegen, type SealBindings } from './codegen.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork, ResolvedLiveInputs, SealServerKind } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealKeyServerEntry,\n\ttype SealLocalKeygenResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport { type SealError, type SealAnyError, type SealConfigError } from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet).\n *\n * Zero-config `testnet()` resolves BOTH independent servers;\n * `mainnet()` resolves the committee (which requires credentials — declare\n * the non-secret `apiKeyName`). `{ server: 'committee' }` opts a testnet\n * stack into the committee aggregator. `serverConfigs` is the raw verbatim\n * override. `verifyKeyServers` defaults to the SDK default (true) on live /\n * known — omit it; only local-keygen forces it false. This default also\n * applies to a verbatim `serverConfigs` override: for a private / unregistered\n * key server (whose on-chain registration can't be verified), pass\n * `verifyKeyServers: false` explicitly.\n *\n * NOTE: devstack never carries the secret committee `apiKey` value (committed\n * config + the browser-injected `deployment.json` are world-readable). Pass\n * `apiKeyName` (the header name) and inject the apiKey at runtime when you\n * construct `SealClient`. */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly server?: SealServerKind;\n\treadonly apiKeyName?: string;\n\treadonly verifyKeyServers?: boolean;\n\treadonly serverConfigs?: ReadonlyArray<SealKeyServerEntry>;\n}\n\n/** Fork-known-mode options. The `*-fork` network routes to the wrapped\n * upstream's known deployment; `server` / `apiKeyName` mirror the live\n * selectors (the secret apiKey is injected by the app at runtime, never\n * carried by devstack). */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly server?: SealServerKind;\n\treadonly apiKeyName?: string;\n\treadonly verifyKeyServers?: boolean;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n// ---------------------------------------------------------------------------\n// The three seal `start` bodies emit their contributions inline via the typed\n// `ctx` verbs after resolving the value. The decl shapes + emit ORDER are\n// load-bearing.\n//\n// ⚠ ID-STABILITY: the snapshotable decl captures the seal vault / master-key\n// secret material subtree; its shape (subtree paths, container label tuple,\n// secretMaterial / missingTolerance flags) MUST stay byte-identical.\n// ---------------------------------------------------------------------------\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\t// Stack-free codegen: the key-server object id / URL / committee are\n\t\t// LOADED CONFIG DATA -- the committed `seal.ts` stub emits\n\t\t// `requireValue(dep, 'seal:<name>', '<key>')`, never a baked object id.\n\t\tstaticCodegen: () => [makeSealStaticCodegen({ name: resolved.name, mode: 'local-keygen' })],\n\t\t// `deps` auto-infers the resolved `{ sui, signer }` dependency\n\t\t// object from seal's `dependsOn: { sui: suiResource, signer:\n\t\t// opts.signer }`. `ctx` is the typed plugin-authoring surface the\n\t\t// contribution emission below drives; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chainId);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchainId: sui.chainId,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\t// Emit the resolved contributions inline: snapshot (seal vault /\n\t\t\t\t// master-key secret-material subtree) → codegen → routable (key\n\t\t\t\t// server). `resolvedValue` is the just-resolved `SealResolved`;\n\t\t\t\t// `identity` (from `IdentityContext`) stamps the snapshot +\n\t\t\t\t// routable container name. The codegen bindings carry the REAL\n\t\t\t\t// objectId / keyServerUrl / serverConfigs.\n\t\t\t\tctx.snapshotExtra(\n\t\t\t\t\tmakeLocalKeygenSnapshotable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tobjectId: resolvedValue.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolvedValue.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolvedValue.serverConfigs,\n\t\t\t\t\t\tverifyKeyServers: resolvedValue.verifyKeyServers,\n\t\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeSealRoutable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate + resolve inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work. `resolved.serverConfigs` is the\n\t// full SDK-ready array (independent fan-out OR a single committee entry\n\t// with aggregatorUrl + the non-secret apiKeyName; never a secret apiKey).\n\tconst resolved: ResolvedLiveInputs = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: resolved.objectId,\n\t\tkeyServerUrl: resolved.keyServerUrl,\n\t\tserverConfigs: resolved.serverConfigs,\n\t\tverifyKeyServers: resolved.verifyKeyServers,\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}` tuple\n\t\t// at factory time (DECLARED config) — bake them as literals in the\n\t\t// committed `seal.ts` (mirrors `knownPackage`). The committed\n\t\t// `serverConfigs` carries ALL entries + aggregatorUrl + apiKeyName; the\n\t\t// secret apiKey is NEVER emitted (the app injects it at runtime).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'live',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t\tverifyKeyServers: bindings.verifyKeyServers,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Live mode has no `dependsOn`, so `start` is zero-arg. `ctx`\n\t\t// drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}`\n\t\t\t\t// tuple at FACTORY time (`resolved`), so `start` only projects the\n\t\t\t\t// already-resolved value — there is no runtime boot. `snap` +\n\t\t\t\t// `bindings` are likewise factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeSealCodegenable(bindings));\n\t\t\t\treturn {\n\t\t\t\t\tserverConfigs: resolved.serverConfigs,\n\t\t\t\t\tkeyServerUrl: resolved.keyServerUrl,\n\t\t\t\t\tobjectId: resolved.objectId,\n\t\t\t\t\tverifyKeyServers: resolved.verifyKeyServers,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Fork-known mode resolves its `{objectId, keyServerUrl, serverConfigs}`\n\t\t// bundle at factory time (DECLARED config, via `validateForkKnownInputs`)\n\t\t// — bake them as literals in the committed `seal.ts` (mirrors\n\t\t// `knownPackage`). The resolved `serverConfigs` is the full SDK-ready\n\t\t// array (independent fan-out or the committee entry + aggregatorUrl), so\n\t\t// it is declared config too; the secret committee apiKey is NEVER\n\t\t// emitted (the app injects it at runtime).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'fork-known',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tserverConfigs: validated.serverConfigs,\n\t\t\t\t\tverifyKeyServers: validated.verifyKeyServers,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Fork-known mode has no `dependsOn`, so `start` is zero-arg.\n\t\t// `ctx` drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Fork-known resolves its `{objectId, keyServerUrl, serverConfigs}`\n\t\t\t\t// bundle at FACTORY time (`validated`, via `validateForkKnownInputs`),\n\t\t\t\t// so `start` only projects the already-resolved value — no runtime\n\t\t\t\t// boot. `snap` is factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: validated.serverConfigs,\n\t\t\t\t\t\tverifyKeyServers: validated.verifyKeyServers,\n\t\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tserverConfigs: validated.serverConfigs,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tverifyKeyServers: validated.verifyKeyServers,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\t// Raw verbatim override — the caller supplies the full SDK-ready\n\t\t// `serverConfigs` array (e.g. a private deployment or a hand-tuned\n\t\t// committee). No known table is consulted.\n\t\tcustom: (opts: Required<Pick<SealLiveOptions, 'serverConfigs'>> & SealLiveOptions) =>\n\t\t\tbuildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
@@ -1,5 +1,3 @@
1
- import { Effect } from "effect";
2
-
3
1
  //#region src/plugins/seal/mode/fork-known.d.ts
4
2
  /** Map a fork upstream to its known-deployment lookup target. */
5
3
  type ForkUpstream = 'mainnet' | 'testnet' | 'devnet';
@@ -1,21 +1,23 @@
1
- import { acquireLive, validateLiveInputs } from "./live.mjs";
2
- import "effect";
1
+ import { validateLiveInputs } from "./live.mjs";
3
2
  //#region src/plugins/seal/mode/fork-known.ts
4
3
  /** Resolve the wrapped upstream's known deployment key. Distilled-
5
4
  * doc invariant #13. */
6
5
  const resolveDeploymentNetwork = (upstream) => upstream;
7
6
  /** Resolve the fork-known overrides + upstream-derived defaults into
8
- * a validated tuple. Pure synchronous projection — mirrors the
9
- * factory-boundary `validateLiveInputs` call in `index.ts` for the
10
- * live branch. Throws on missing fields after fallback (matches the
11
- * live branch's behaviour see `validateLiveInputs`). */
7
+ * a resolved bundle. Pure synchronous projection — delegates to
8
+ * `validateLiveInputs` (the live branch's resolver) after mapping the
9
+ * upstream alias to a `KnownNetwork`, so the resolved `serverConfigs`
10
+ * (independent fan-out or committee) is threaded through unchanged.
11
+ * Throws `SealConfigError` on missing fields (matches the live
12
+ * branch's behaviour). */
12
13
  const validateForkKnownInputs = (inputs) => {
13
14
  try {
14
15
  return validateLiveInputs({
15
16
  name: inputs.name,
16
17
  network: resolveDeploymentNetwork(inputs.upstream),
17
- objectId: inputs.objectId,
18
- keyServerUrl: inputs.keyServerUrl
18
+ ...inputs.server !== void 0 ? { server: inputs.server } : {},
19
+ ...inputs.apiKeyName !== void 0 ? { apiKeyName: inputs.apiKeyName } : {},
20
+ ...inputs.verifyKeyServers !== void 0 ? { verifyKeyServers: inputs.verifyKeyServers } : {}
19
21
  });
20
22
  } catch (err) {
21
23
  if (isSealConfigError(err)) throw {
@@ -26,20 +28,7 @@ const validateForkKnownInputs = (inputs) => {
26
28
  }
27
29
  };
28
30
  const isSealConfigError = (value) => typeof value === "object" && value !== null && value._tag === "SealConfigError" && typeof value.message === "string";
29
- /** Acquire body for the fork-known mode. Inputs already pre-validated
30
- * by the barrel via `validateForkKnownInputs`; delegates the
31
- * read-side projection to live mode. The `upstream` field rides
32
- * through for downstream span attribution.
33
- *
34
- * Error channel kept typed as `SealError` for forward-compatibility
35
- * with any future fallible work this body needs to do (currently
36
- * `acquireLive` is `Effect.sync` so the channel is effectively
37
- * `never`). */
38
- const acquireForkKnown = (inputs) => acquireLive({
39
- name: inputs.name,
40
- resolved: inputs.resolved
41
- });
42
31
  //#endregion
43
- export { acquireForkKnown, validateForkKnownInputs };
32
+ export { validateForkKnownInputs };
44
33
 
45
34
  //# sourceMappingURL=fork-known.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"fork-known.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/fork-known.ts"],"sourcesContent":["// Seal fork-known mode — *-fork networks route to the wrapped\n// upstream's known key-server deployment.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer` (testnet / mainnet\n// / fork)\": structurally IDENTICAL to live mode. The only difference\n// is the network resolver step at the barrel — `*-fork` networks\n// route to the wrapped upstream (mainnet-fork → mainnet,\n// testnet-fork → testnet, devnet-fork → devnet) BEFORE the\n// known-deployment lookup fires.\n//\n// Distilled-doc invariant #13: `Seal()` on `*-fork` MUST route to\n// `sealKnownKeyServer` with the wrapped upstream's deployment. The\n// barrel (`index.ts`) enforces this via `resolveDeploymentNetwork`;\n// this file's mode body simply consumes the resolved network the\n// barrel passed.\n//\n// The mode body re-uses `acquireLive` since the boot pipeline is\n// identical. We expose a distinct factory only so the mode-narrowed\n// factory namespace (`sealFor(network).forkKnown(opts)`) can\n// route by mode without leaking the live-mode internals.\n\nimport { Effect } from 'effect';\n\nimport { acquireLive, validateLiveInputs, type KnownNetwork } from './live.ts';\nimport type { SealError } from '../errors.ts';\nimport type { SealKnownResolved } from '../registry-publish.ts';\n\n// ---------------------------------------------------------------------------\n// Fork → upstream network mapping\n// ---------------------------------------------------------------------------\n\n/** Map a fork upstream to its known-deployment lookup target. */\nexport type ForkUpstream = 'mainnet' | 'testnet' | 'devnet';\n\n/** Resolve the wrapped upstream's known deployment key. Distilled-\n * doc invariant #13. */\nexport const resolveDeploymentNetwork = (upstream: ForkUpstream): KnownNetwork => upstream;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Pre-validated fork-known inputs. Symmetric with the live mode's\n * `{ name, resolved }` shapethe barrel resolves\n * `upstream → KnownNetwork → validated tuple` synchronously at\n * factory time so both branches reach `acquireLive` with the same\n * structural envelope. */\nexport interface ForkKnownInputs {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly resolved: { readonly objectId: string; readonly keyServerUrl: string };\n}\n\n/** Resolve the fork-known overrides + upstream-derived defaults into\n * a validated tuple. Pure synchronous projection mirrors the\n * factory-boundary `validateLiveInputs` call in `index.ts` for the\n * live branch. Throws on missing fields after fallback (matches the\n * live branch's behaviour — see `validateLiveInputs`). */\nexport const validateForkKnownInputs = (inputs: {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}): { readonly objectId: string; readonly keyServerUrl: string } => {\n\ttry {\n\t\treturn validateLiveInputs({\n\t\t\tname: inputs.name,\n\t\t\tnetwork: resolveDeploymentNetwork(inputs.upstream),\n\t\t\tobjectId: inputs.objectId,\n\t\t\tkeyServerUrl: inputs.keyServerUrl,\n\t\t});\n\t} catch (err) {\n\t\t// Re-throw the original tagged error so downstream\n\t\t// `Effect.catchTag('SealConfigError', …)` still matches.\n\t\t// Wrapping in `new Error(…)` would strip the `_tag` and turn\n\t\t// the typed refusal into an untyped runtime crash. Prepend the\n\t\t// upstream context to the message in-place instead.\n\t\tif (isSealConfigError(err)) {\n\t\t\tthrow {\n\t\t\t\t...err,\n\t\t\t\tmessage: `seal.fork-known (upstream=${inputs.upstream}): ${err.message}`,\n\t\t\t};\n\t\t}\n\t\tthrow err;\n\t}\n};\n\nconst isSealConfigError = (\n\tvalue: unknown,\n): value is { readonly _tag: 'SealConfigError'; readonly message: string; [k: string]: unknown } =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { _tag?: unknown })._tag === 'SealConfigError' &&\n\ttypeof (value as { message?: unknown }).message === 'string';\n\n// ---------------------------------------------------------------------------\n// Mode acquire\n// ---------------------------------------------------------------------------\n\n/** Acquire body for the fork-known mode. Inputs already pre-validated\n * by the barrel via `validateForkKnownInputs`; delegates the\n * read-side projection to live mode. The `upstream` field rides\n * through for downstream span attribution.\n *\n * Error channel kept typed as `SealError` for forward-compatibility\n * with any future fallible work this body needs to do (currently\n * `acquireLive` is `Effect.sync` so the channel is effectively\n * `never`). */\nexport const acquireForkKnown = (\n\tinputs: ForkKnownInputs,\n): Effect.Effect<SealKnownResolved, SealError> =>\n\tacquireLive({ name: inputs.name, resolved: inputs.resolved });\n"],"mappings":";;;;;AAoCA,MAAa,4BAA4B,aAAyC;;;;;;AAsBlF,MAAa,2BAA2B,WAK4B;CACnE,IAAI;EACH,OAAO,mBAAmB;GACzB,MAAM,OAAO;GACb,SAAS,yBAAyB,OAAO,QAAQ;GACjD,UAAU,OAAO;GACjB,cAAc,OAAO;EACtB,CAAC;CACF,SAAS,KAAK;EAMb,IAAI,kBAAkB,GAAG,GACxB,MAAM;GACL,GAAG;GACH,SAAS,6BAA6B,OAAO,SAAS,KAAK,IAAI;EAChE;EAED,MAAM;CACP;AACD;AAEA,MAAM,qBACL,UAEA,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,qBACvC,OAAQ,MAAgC,YAAY;;;;;;;;;;AAerD,MAAa,oBACZ,WAEA,YAAY;CAAE,MAAM,OAAO;CAAM,UAAU,OAAO;AAAS,CAAC"}
1
+ {"version":3,"file":"fork-known.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/fork-known.ts"],"sourcesContent":["// Seal fork-known mode — *-fork networks route to the wrapped\n// upstream's known key-server deployment.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer` (testnet / mainnet\n// / fork)\": structurally IDENTICAL to live mode. The only difference\n// is the network resolver step at the barrel — `*-fork` networks\n// route to the wrapped upstream (mainnet-fork → mainnet,\n// testnet-fork → testnet, devnet-fork → devnet) BEFORE the\n// known-deployment lookup fires.\n//\n// Distilled-doc invariant #13: `Seal()` on `*-fork` MUST route to\n// `sealKnownKeyServer` with the wrapped upstream's deployment. The\n// barrel (`index.ts`) enforces this via `resolveDeploymentNetwork`;\n// this file's mode body simply consumes the resolved network the\n// barrel passed.\n//\n// The mode body re-uses live mode's resolver (`validateLiveInputs`)\n// since the resolution pipeline is identical. We expose a distinct\n// factory only so the mode-narrowed factory namespace\n// (`sealFor(network).forkKnown(opts)`) can route by mode without\n// leaking the live-mode internals.\n\nimport {\n\tvalidateLiveInputs,\n\ttype KnownNetwork,\n\ttype ResolvedLiveInputs,\n\ttype SealServerKind,\n} from './live.ts';\n\n// ---------------------------------------------------------------------------\n// Fork → upstream network mapping\n// ---------------------------------------------------------------------------\n\n/** Map a fork upstream to its known-deployment lookup target. */\nexport type ForkUpstream = 'mainnet' | 'testnet' | 'devnet';\n\n/** Resolve the wrapped upstream's known deployment key. Distilled-\n * doc invariant #13. */\nexport const resolveDeploymentNetwork = (upstream: ForkUpstream): KnownNetwork => upstream;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Resolve the fork-known overrides + upstream-derived defaults into\n * a resolved bundle. Pure synchronous projection delegates to\n * `validateLiveInputs` (the live branch's resolver) after mapping the\n * upstream alias to a `KnownNetwork`, so the resolved `serverConfigs`\n * (independent fan-out or committee) is threaded through unchanged.\n * Throws `SealConfigError` on missing fields (matches the live\n * branch's behaviour). */\nexport const validateForkKnownInputs = (inputs: {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly server?: SealServerKind;\n\treadonly apiKeyName?: string;\n\treadonly verifyKeyServers?: boolean;\n}): ResolvedLiveInputs => {\n\ttry {\n\t\treturn validateLiveInputs({\n\t\t\tname: inputs.name,\n\t\t\tnetwork: resolveDeploymentNetwork(inputs.upstream),\n\t\t\t...(inputs.server !== undefined ? { server: inputs.server } : {}),\n\t\t\t...(inputs.apiKeyName !== undefined ? { apiKeyName: inputs.apiKeyName } : {}),\n\t\t\t...(inputs.verifyKeyServers !== undefined\n\t\t\t\t? { verifyKeyServers: inputs.verifyKeyServers }\n\t\t\t\t: {}),\n\t\t});\n\t} catch (err) {\n\t\t// Re-throw the original tagged error so downstream\n\t\t// `Effect.catchTag('SealConfigError', …)` still matches.\n\t\t// Wrapping in `new Error(…)` would strip the `_tag` and turn\n\t\t// the typed refusal into an untyped runtime crash. Prepend the\n\t\t// upstream context to the message in-place instead.\n\t\tif (isSealConfigError(err)) {\n\t\t\tthrow {\n\t\t\t\t...err,\n\t\t\t\tmessage: `seal.fork-known (upstream=${inputs.upstream}): ${err.message}`,\n\t\t\t};\n\t\t}\n\t\tthrow err;\n\t}\n};\n\nconst isSealConfigError = (\n\tvalue: unknown,\n): value is { readonly _tag: 'SealConfigError'; readonly message: string; [k: string]: unknown } =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { _tag?: unknown })._tag === 'SealConfigError' &&\n\ttypeof (value as { message?: unknown }).message === 'string';\n"],"mappings":";;;;AAsCA,MAAa,4BAA4B,aAAyC;;;;;;;;AAalF,MAAa,2BAA2B,WAMd;CACzB,IAAI;EACH,OAAO,mBAAmB;GACzB,MAAM,OAAO;GACb,SAAS,yBAAyB,OAAO,QAAQ;GACjD,GAAI,OAAO,WAAW,KAAA,IAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;GAC/D,GAAI,OAAO,eAAe,KAAA,IAAY,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;GAC3E,GAAI,OAAO,qBAAqB,KAAA,IAC7B,EAAE,kBAAkB,OAAO,iBAAiB,IAC5C,CAAC;EACL,CAAC;CACF,SAAS,KAAK;EAMb,IAAI,kBAAkB,GAAG,GACxB,MAAM;GACL,GAAG;GACH,SAAS,6BAA6B,OAAO,SAAS,KAAK,IAAI;EAChE;EAED,MAAM;CACP;AACD;AAEA,MAAM,qBACL,UAEA,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,qBACvC,OAAQ,MAAgC,YAAY"}
@@ -1,20 +1,43 @@
1
- import { Effect } from "effect";
2
-
3
1
  //#region src/plugins/seal/mode/live.d.ts
4
- /** Closed set of known deployments. `mainnet` + `devnet` intentionally
5
- * null (no public default key server). `testnet` carries the public
6
- * key-server URL but `keyServerObjectId` is `null` until a real id is
7
- * sourced `validateLiveInputs` forces the caller to supply
8
- * `objectId` explicitly in that case. */
9
- declare const KNOWN_DEPLOYMENTS: {
10
- readonly testnet: {
11
- readonly keyServerObjectId: string | null;
12
- readonly keyServerUrl: string;
2
+ /** Which class of known key-server backing to resolve. `independent`
3
+ * fans out to all of the network's standalone Open-mode servers
4
+ * (weight 1 each); `committee` resolves the single threshold-committee
5
+ * object reached through an aggregator. Plugin-INTERNAL not exported
6
+ * from the barrel. */
7
+ type SealServerKind = 'independent' | 'committee';
8
+ /** A single independent (Open-mode) key server. */
9
+ interface IndependentServerSpec {
10
+ readonly objectId: string;
11
+ readonly url: string;
12
+ }
13
+ /** The committee (threshold) deployment for a network. */
14
+ interface CommitteeSpec {
15
+ readonly objectId: string;
16
+ readonly aggregatorUrl: string;
17
+ /** Threshold `m-of-n`, carried for diagnostics / display only. */
18
+ readonly threshold: {
19
+ readonly m: number;
20
+ readonly n: number;
13
21
  };
14
- readonly mainnet: null;
22
+ /** When `true`, the committee aggregator demands an API key and the
23
+ * factory throws `SealConfigError` if the caller omits `apiKeyName`. */
24
+ readonly requiresApiKey: boolean;
25
+ }
26
+ /** Per-network known deployment. `independent` is `null` when the
27
+ * network ships no public standalone server (mainnet); `committee` is
28
+ * `null` when none ships (devnet). */
29
+ interface KnownDeployment {
30
+ readonly independent: ReadonlyArray<IndependentServerSpec> | null;
31
+ readonly committee: CommitteeSpec | null;
32
+ /** The default server kind for zero-config use of this network. */
33
+ readonly defaultServer: SealServerKind;
34
+ }
35
+ declare const KNOWN_DEPLOYMENTS: {
36
+ readonly testnet: KnownDeployment;
37
+ readonly mainnet: KnownDeployment;
15
38
  readonly devnet: null;
16
39
  };
17
40
  type KnownNetwork = keyof typeof KNOWN_DEPLOYMENTS;
18
41
  //#endregion
19
- export { KnownNetwork };
42
+ export { KnownNetwork, SealServerKind };
20
43
  //# sourceMappingURL=live.d.mts.map