@tabai/sdk 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +12 -9
  2. package/dist/_shared/abi.d.ts.map +1 -1
  3. package/dist/_shared/abi.js +6 -3
  4. package/dist/_shared/abi.js.map +1 -1
  5. package/dist/_shared/chains.d.ts +4 -6
  6. package/dist/_shared/chains.d.ts.map +1 -1
  7. package/dist/_shared/chains.js +1 -2
  8. package/dist/_shared/chains.js.map +1 -1
  9. package/dist/_shared/keccak256.d.ts +6 -6
  10. package/dist/_shared/keccak256.js +6 -6
  11. package/dist/_shared/keccak256.js.map +1 -1
  12. package/dist/_shared/result.d.ts +5 -6
  13. package/dist/_shared/result.d.ts.map +1 -1
  14. package/dist/_shared/result.js +5 -6
  15. package/dist/_shared/result.js.map +1 -1
  16. package/dist/cli/client-config.d.ts +4 -5
  17. package/dist/cli/client-config.d.ts.map +1 -1
  18. package/dist/cli/client-config.js +4 -5
  19. package/dist/cli/client-config.js.map +1 -1
  20. package/dist/cli/connect.d.ts +1 -3
  21. package/dist/cli/connect.d.ts.map +1 -1
  22. package/dist/cli/connect.js +5 -3
  23. package/dist/cli/connect.js.map +1 -1
  24. package/dist/cli/doctor.d.ts +1 -3
  25. package/dist/cli/doctor.d.ts.map +1 -1
  26. package/dist/cli/doctor.js +1 -3
  27. package/dist/cli/doctor.js.map +1 -1
  28. package/dist/cli/index.d.ts +1 -1
  29. package/dist/cli/index.js +1 -1
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/main.d.ts +1 -3
  32. package/dist/cli/main.d.ts.map +1 -1
  33. package/dist/cli/main.js +7 -6
  34. package/dist/cli/main.js.map +1 -1
  35. package/dist/errors.d.ts +2 -4
  36. package/dist/errors.d.ts.map +1 -1
  37. package/dist/errors.js +2 -4
  38. package/dist/errors.js.map +1 -1
  39. package/dist/http/client-402.d.ts +11 -13
  40. package/dist/http/client-402.d.ts.map +1 -1
  41. package/dist/http/client-402.js +12 -14
  42. package/dist/http/client-402.js.map +1 -1
  43. package/dist/http/headers.d.ts +9 -11
  44. package/dist/http/headers.d.ts.map +1 -1
  45. package/dist/http/headers.js +9 -11
  46. package/dist/http/headers.js.map +1 -1
  47. package/dist/http/index.d.ts +0 -2
  48. package/dist/http/index.d.ts.map +1 -1
  49. package/dist/http/index.js +0 -2
  50. package/dist/http/index.js.map +1 -1
  51. package/dist/http/metering-claim.d.ts +0 -2
  52. package/dist/http/metering-claim.d.ts.map +1 -1
  53. package/dist/http/metering-claim.js +0 -2
  54. package/dist/http/metering-claim.js.map +1 -1
  55. package/dist/index.d.ts +15 -12
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +15 -12
  58. package/dist/index.js.map +1 -1
  59. package/dist/logger.d.ts +1 -4
  60. package/dist/logger.d.ts.map +1 -1
  61. package/dist/logger.js +1 -4
  62. package/dist/logger.js.map +1 -1
  63. package/dist/mcp/index.d.ts +1 -1
  64. package/dist/mcp/index.js +1 -1
  65. package/dist/mcp/index.js.map +1 -1
  66. package/dist/mcp/json-schema.d.ts +1 -3
  67. package/dist/mcp/json-schema.d.ts.map +1 -1
  68. package/dist/mcp/json-schema.js +1 -3
  69. package/dist/mcp/json-schema.js.map +1 -1
  70. package/dist/mcp/json.d.ts +0 -2
  71. package/dist/mcp/json.d.ts.map +1 -1
  72. package/dist/mcp/json.js +0 -2
  73. package/dist/mcp/json.js.map +1 -1
  74. package/dist/mcp/registry-client.d.ts +0 -2
  75. package/dist/mcp/registry-client.d.ts.map +1 -1
  76. package/dist/mcp/registry-client.js +3 -4
  77. package/dist/mcp/registry-client.js.map +1 -1
  78. package/dist/mcp/schemas.d.ts +10 -8
  79. package/dist/mcp/schemas.d.ts.map +1 -1
  80. package/dist/mcp/schemas.js +5 -7
  81. package/dist/mcp/schemas.js.map +1 -1
  82. package/dist/mcp/server.d.ts +0 -2
  83. package/dist/mcp/server.d.ts.map +1 -1
  84. package/dist/mcp/server.js +4 -7
  85. package/dist/mcp/server.js.map +1 -1
  86. package/dist/mcp/settings.d.ts +5 -1
  87. package/dist/mcp/settings.d.ts.map +1 -1
  88. package/dist/mcp/settings.js +28 -3
  89. package/dist/mcp/settings.js.map +1 -1
  90. package/dist/mcp/toolset.d.ts +2 -5
  91. package/dist/mcp/toolset.d.ts.map +1 -1
  92. package/dist/mcp/toolset.js +3 -6
  93. package/dist/mcp/toolset.js.map +1 -1
  94. package/dist/payments/config.d.ts +6 -8
  95. package/dist/payments/config.d.ts.map +1 -1
  96. package/dist/payments/config.js +5 -7
  97. package/dist/payments/config.js.map +1 -1
  98. package/dist/payments/index.d.ts +0 -2
  99. package/dist/payments/index.d.ts.map +1 -1
  100. package/dist/payments/index.js +0 -2
  101. package/dist/payments/index.js.map +1 -1
  102. package/dist/payments/registry.d.ts +11 -12
  103. package/dist/payments/registry.d.ts.map +1 -1
  104. package/dist/payments/registry.js +11 -12
  105. package/dist/payments/registry.js.map +1 -1
  106. package/dist/payments/strategy.d.ts +9 -5
  107. package/dist/payments/strategy.d.ts.map +1 -1
  108. package/dist/payments/strategy.js +9 -5
  109. package/dist/payments/strategy.js.map +1 -1
  110. package/dist/proxy/hooks.d.ts +3 -5
  111. package/dist/proxy/hooks.d.ts.map +1 -1
  112. package/dist/proxy/hooks.js +2 -4
  113. package/dist/proxy/hooks.js.map +1 -1
  114. package/dist/proxy/index.d.ts +2 -2
  115. package/dist/proxy/index.js +2 -2
  116. package/dist/proxy/index.js.map +1 -1
  117. package/dist/proxy/proxy.d.ts +3 -5
  118. package/dist/proxy/proxy.d.ts.map +1 -1
  119. package/dist/proxy/proxy.js +2 -4
  120. package/dist/proxy/proxy.js.map +1 -1
  121. package/dist/server/adapters/express.d.ts +0 -2
  122. package/dist/server/adapters/express.d.ts.map +1 -1
  123. package/dist/server/adapters/express.js +0 -2
  124. package/dist/server/adapters/express.js.map +1 -1
  125. package/dist/server/adapters/hono.d.ts +0 -2
  126. package/dist/server/adapters/hono.d.ts.map +1 -1
  127. package/dist/server/adapters/hono.js +0 -2
  128. package/dist/server/adapters/hono.js.map +1 -1
  129. package/dist/server/adapters/next.d.ts +0 -2
  130. package/dist/server/adapters/next.d.ts.map +1 -1
  131. package/dist/server/adapters/next.js +0 -2
  132. package/dist/server/adapters/next.js.map +1 -1
  133. package/dist/server/index.d.ts +5 -5
  134. package/dist/server/index.js +5 -5
  135. package/dist/server/index.js.map +1 -1
  136. package/dist/server/metering.d.ts +9 -11
  137. package/dist/server/metering.d.ts.map +1 -1
  138. package/dist/server/metering.js +6 -8
  139. package/dist/server/metering.js.map +1 -1
  140. package/dist/server/post-paid.d.ts +8 -10
  141. package/dist/server/post-paid.d.ts.map +1 -1
  142. package/dist/server/post-paid.js +7 -9
  143. package/dist/server/post-paid.js.map +1 -1
  144. package/dist/x402/client.d.ts +5 -6
  145. package/dist/x402/client.d.ts.map +1 -1
  146. package/dist/x402/client.js +6 -7
  147. package/dist/x402/client.js.map +1 -1
  148. package/dist/x402/server.d.ts +5 -5
  149. package/dist/x402/server.d.ts.map +1 -1
  150. package/dist/x402/server.js +2 -2
  151. package/dist/x402/server.js.map +1 -1
  152. package/dist/x402/wire.d.ts +1 -1
  153. package/dist/x402/wire.js +1 -1
  154. package/dist/x402/wire.js.map +1 -1
  155. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/payments/config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab.config.ts` discovery: mechanism three of R23.6.\n *\n * Zero-code wiring. A consumer writes a config file naming strategies as module\n * specifiers, and the strategies register themselves at startup with no\n * application code involved at all:\n *\n * ```ts\n * // tab.config.ts, at the consumer's project root\n * import { defineTabConfig } from \"@tabai/sdk\";\n * export default defineTabConfig({ strategies: [\"@acme/tab-strategy-solana\"] });\n * ```\n *\n * ## What an entry may be\n *\n * A module specifier, a strategy object, or a factory returning one. The\n * specifier form is the point of the mechanism; the other two exist because a\n * config file that can only name packages forces a consumer to publish one before\n * they can try anything.\n *\n * ## Where a specifier resolves from\n *\n * From the **config file**, not from this package. `@acme/tab-strategy-solana` is\n * the consumer's dependency and under pnpm it is not visible from inside\n * `@tabai/sdk` at all, so resolving relative to this module would fail for the\n * exact layout the workspace uses. `createRequire(configFileUrl)` resolves the\n * way the consumer's own `import` would, and a bare specifier that resolution\n * misses is retried as a plain dynamic import before the error is reported.\n *\n * ## The `.ts` config file and the host runtime\n *\n * This module imports the config file; it does not compile it. A `.ts` config\n * loads under a runtime that strips types, `tsx`, `node --experimental-strip-types`,\n * a bundler's dev server, and fails under one that does not. That failure comes\n * back as a `Result` naming the file and the requirement rather than as a stack\n * trace, and `tab.config.js` and `tab.config.mjs` are discovered too so a\n * consumer with a plain Node process has a first-class option.\n *\n * Requirements: 23.6, 21.5\n */\n\nimport { existsSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, isAbsolute, resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { causeOf, ok, wrap, wrapSync, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { notFoundError, validationError } from \"../errors.js\";\nimport { validatePaymentStrategy, type PaymentStrategy } from \"./strategy.js\";\nimport type { X402SignerFactory } from \"../x402/client.js\";\nimport {\n moduleStrategyRegistry,\n type StrategyRegistration,\n type StrategyRegistry,\n} from \"./registry.js\";\n\n/**\n * A factory in a config file, so a strategy that needs a signer can be built lazily.\n *\n * Returning `undefined` is a supported answer and means \"not available in this\n * environment\". That is what keeps every read on this rail keyless: the whole\n * point of a factory rather than an object is that a config file can declare a\n * strategy that only exists once a signing key does, and `tab_discover`,\n * `tab_status` and `doctor` never need one. A declining factory is skipped, and\n * the rest of the config - the Agent, the registry URL, the Service endpoints -\n * is kept.\n */\nexport type PaymentStrategyFactory = () =>\n | PaymentStrategy\n | undefined\n | Promise<PaymentStrategy | undefined>;\n\n/** A module specifier, a ready strategy, or a factory returning one. */\nexport type TabConfigStrategyEntry = string | PaymentStrategy | PaymentStrategyFactory;\n\n/**\n * One Service's off-chain coordinates.\n *\n * The chain records who operates a Service, what its tools cost and where it\n * collects Settlements. It records no URL, deliberately: an endpoint moves, and\n * a registry that pinned one would either go stale or need a write every time a\n * Service redeployed. So the endpoint is configuration, and this is where a\n * consumer states it.\n *\n * Without an entry here, `tab_discover` reports the Service with a null endpoint\n * and `tab_call` refuses it by name rather than inventing a URL.\n */\nexport interface TabServiceEntry {\n /** The Service's 32-byte registry key, as `tab_discover` reports it. */\n readonly serviceId: string;\n /** A label for a person. Defaults to the ascii the serviceId decodes to. */\n readonly name?: string;\n /** Absolute base URL `tab_call` sends requests to. */\n readonly endpoint: string;\n /**\n * The API Hub provider this Service fronts, if it fronts one.\n *\n * With this set, `tab_discover` fetches the provider's manifest and lists its\n * endpoints under the Service as the tools they are, each reachable through\n * the Service's `/hub/<prefix>` mount and metered onto the Agent's Open Tab.\n */\n readonly hub?: TabServiceHubEntry;\n /**\n * Headers sent with every call to this Service.\n *\n * A record for a Service that gates on something fixed, such as an API key. A\n * function for one that gates on something per request: the reference metering\n * gateway, for instance, requires a claim over the method, the path, the Agent\n * and the tool, which no static header can satisfy. Tab defines neither scheme\n * and validates neither -- this is the seam through which a Service's own\n * access control stays the Service's own.\n *\n * Never a Tab credential. The Tab identity headers are added by the 402 client\n * and nothing in Tab authenticates an Agent with a bearer token.\n */\n readonly headers?: Readonly<Record<string, string>> | ServiceHeaderProvider;\n}\n\n/** An API Hub provider fronted by a Service. See {@link TabServiceEntry.hub}. */\nexport interface TabServiceHubEntry {\n /** The Hub's provider slug, for example `weather-underground`. */\n readonly provider: string;\n /** The mount under the Service endpoint. Defaults to the provider slug, so `/hub/<provider>`. */\n readonly prefix?: string;\n /** Overrides the manifest URL, for a mirror or a test. */\n readonly manifestUrl?: string;\n}\n\n/** Builds the per-request headers one Service requires. See {@link TabServiceEntry.headers}. */\nexport type ServiceHeaderProvider = (\n request: ServiceHeaderRequest,\n) => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;\n\n/** What the provider is told about the call it is producing headers for. */\nexport interface ServiceHeaderRequest {\n readonly method: string;\n /** The absolute URL the request is going to. */\n readonly url: string;\n /** The tool name as the caller gave it, before it is packed into a 32-byte key. */\n readonly tool: string;\n /** The Agent the call is metered against. */\n readonly agent: string;\n readonly serviceId: string;\n}\n\nexport interface TabConfig {\n readonly strategies?: readonly TabConfigStrategyEntry[];\n /**\n * The Agent's Monad address: whose Open Tab a metered call lands on.\n *\n * An address and never a key. Nothing in this package derives an address from\n * a private key, because doing so would mean a config file that holds one.\n */\n readonly agent?: string;\n /** Absolute base URL of the Tab registry read API, which serves discovery and status. */\n readonly registryUrl?: string;\n /** Where each Service can be reached. See {@link TabServiceEntry}. */\n readonly services?: readonly TabServiceEntry[];\n /**\n * The x402 signer, for the prepaid fallback.\n *\n * A factory and only a factory, for the reason `strategies` holds factories:\n * a signer is built from a key, and a config file must be loadable by the\n * three surfaces that hold none. Nothing calls this until a Service has\n * refused a call on credit and offered x402 for it, and a factory returning\n * `undefined` declines, which leaves that refusal the `LIMIT_EXCEEDED` it was.\n */\n readonly x402?: X402SignerFactory;\n}\n\n/**\n * Types a config file's default export. Identity at runtime, its whole job is to\n * make a typo in the config a compile error in the consumer's editor.\n */\nexport const defineTabConfig = (config: TabConfig): TabConfig => config;\n\n/**\n * The file names discovery looks for, in order. `.ts` first because it is the\n * documented form and the one that type-checks; the plain-JavaScript forms follow\n * so a consumer whose runtime strips no types is not shut out.\n */\nexport const TAB_CONFIG_FILE_NAMES = [\n \"tab.config.ts\",\n \"tab.config.mts\",\n \"tab.config.mjs\",\n \"tab.config.js\",\n \"tab.config.cjs\",\n] as const;\n\nexport interface FindTabConfigOptions {\n /** Where the walk starts. Defaults to the working directory. */\n readonly cwd?: string;\n readonly fileNames?: readonly string[];\n}\n\n/**\n * Walks from `cwd` towards the filesystem root and returns the first config file\n * found, or `undefined` when there is none.\n *\n * Absence is not an error: the whole point of the mechanism is that a consumer\n * who wants nothing from it writes nothing.\n */\nexport function findTabConfig(options: FindTabConfigOptions = {}): Result<string | undefined> {\n return wrapSync(\n () => {\n const fileNames = options.fileNames ?? TAB_CONFIG_FILE_NAMES;\n let directory = resolvePath(options.cwd ?? \".\");\n for (;;) {\n for (const fileName of fileNames) {\n const candidate = resolvePath(directory, fileName);\n if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;\n }\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n },\n (error) => ({\n category: \"INTERNAL\",\n code: \"CONFIG_SEARCH_FAILED\",\n message: \"the tab.config search could not read the filesystem\",\n retryable: false,\n cause: causeOf(error),\n }),\n );\n}\n\nexport interface LoadTabConfigOptions extends FindTabConfigOptions {\n /** An explicit config file. Absolute, or relative to `cwd`. Missing is an error. */\n readonly configPath?: string;\n /**\n * Where the discovered strategies are registered. Omitted means the\n * module-level registry, which is what makes the mechanism zero-code; `false`\n * loads and validates without registering anything.\n */\n readonly registry?: StrategyRegistry | false;\n readonly logger?: Logger;\n}\n\nexport interface LoadedTabConfig {\n /** The file that was loaded, or `undefined` when none was found. */\n readonly path: string | undefined;\n readonly config: TabConfig;\n readonly strategies: readonly PaymentStrategy[];\n /** Empty when `registry` was `false`. */\n readonly registrations: readonly StrategyRegistration[];\n}\n\nconst EMPTY_CONFIG: TabConfig = {};\n\n/**\n * Loads a config file, resolves every strategy entry, and registers the result.\n *\n * Returns a `Result` for every failure, including a config file that throws on\n * import: a consumer's config is consumer code, and this package does not turn\n * their mistake into an unhandled rejection.\n */\nexport async function loadTabConfig(\n options: LoadTabConfigOptions = {},\n): Promise<Result<LoadedTabConfig>> {\n const logger = options.logger ?? defaultLogger;\n\n const located = locateConfig(options);\n if (!located.ok) return located;\n const path = located.value;\n\n if (path === undefined) {\n return ok({ path: undefined, config: EMPTY_CONFIG, strategies: [], registrations: [] });\n }\n\n const imported = await importModule(path, `tab config \\`${path}\\``);\n if (!imported.ok) return imported;\n\n const config = readDefaultExport(imported.value, path);\n if (!config.ok) return config;\n\n const strategies: PaymentStrategy[] = [];\n let declined = 0;\n for (const [index, entry] of (config.value.strategies ?? []).entries()) {\n const resolved = await resolveEntry(entry, index, path);\n if (!resolved.ok) return resolved;\n // `undefined` is the factory declining, not a fault. Skip it and keep going.\n if (resolved.value === undefined) {\n declined += 1;\n continue;\n }\n strategies.push(resolved.value);\n }\n\n const registrations: StrategyRegistration[] = [];\n if (options.registry !== false) {\n const registry = options.registry ?? moduleStrategyRegistry(logger);\n for (const strategy of strategies) {\n const outcome = registry.register(strategy);\n if (!outcome.ok) return outcome;\n registrations.push(outcome.value);\n }\n }\n\n logger.debug(\"tab config loaded\", { path, strategies: strategies.length, declined });\n return ok({ path, config: config.value, strategies, registrations });\n}\n\nfunction locateConfig(options: LoadTabConfigOptions): Result<string | undefined> {\n if (options.configPath === undefined) return findTabConfig(options);\n\n const cwd = resolvePath(options.cwd ?? \".\");\n const path = isAbsolute(options.configPath)\n ? options.configPath\n : resolvePath(cwd, options.configPath);\n if (!existsSync(path)) {\n return notFoundError(\"CONFIG_NOT_FOUND\", `no tab config file at \\`${path}\\``, {\n details: { path },\n });\n }\n return ok(path);\n}\n\n/** Imports a file by path. A `.ts` file needs a type-stripping runtime, so say so. */\nasync function importModule(path: string, label: string): Promise<Result<Record<string, unknown>>> {\n const href = pathToFileURL(path).href;\n return wrap(\n async () => (await import(href)) as Record<string, unknown>,\n (error) => ({\n category: \"UPSTREAM\",\n code: \"CONFIG_IMPORT_FAILED\",\n message: path.endsWith(\".ts\") || path.endsWith(\".mts\")\n ? `${label} could not be imported; a TypeScript config file needs a runtime that strips types, or use tab.config.mjs`\n : `${label} could not be imported`,\n retryable: false,\n details: { path },\n cause: causeOf(error),\n }),\n );\n}\n\nfunction readDefaultExport(module: Record<string, unknown>, path: string): Result<TabConfig> {\n const exported = module[\"default\"];\n if (exported === undefined) {\n return validationError(\n \"CONFIG_NO_DEFAULT_EXPORT\",\n `\\`${path}\\` must default-export a config, for example \\`export default defineTabConfig({ strategies: [] })\\``,\n { details: { path } },\n );\n }\n if (typeof exported !== \"object\" || exported === null) {\n return validationError(\n \"CONFIG_INVALID\",\n `the default export of \\`${path}\\` must be an object`,\n { details: { path } },\n );\n }\n const candidate = exported as { strategies?: unknown; services?: unknown; x402?: unknown };\n if (candidate.x402 !== undefined && typeof candidate.x402 !== \"function\") {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`x402\\` but it is not a factory; it must be a function returning a signer or undefined, so the file holds no key`,\n { details: { path } },\n );\n }\n if (candidate.strategies !== undefined && !Array.isArray(candidate.strategies)) {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`strategies\\` but it is not an array`,\n { details: { path } },\n );\n }\n if (candidate.services !== undefined && !Array.isArray(candidate.services)) {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`services\\` but it is not an array`,\n { details: { path } },\n );\n }\n return ok(exported as TabConfig);\n}\n\nasync function resolveEntry(\n entry: TabConfigStrategyEntry,\n index: number,\n configPath: string,\n): Promise<Result<PaymentStrategy | undefined>> {\n const label = `strategies[${index}] of \\`${configPath}\\``;\n\n if (typeof entry === \"string\") {\n const module = await importSpecifier(entry, configPath);\n if (!module.ok) return module;\n const exported = module.value[\"default\"];\n if (exported === undefined) {\n return validationError(\n \"STRATEGY_MODULE_INVALID\",\n `${label}: \\`${entry}\\` must default-export a PaymentStrategy or a factory returning one`,\n { details: { specifier: entry } },\n );\n }\n return callIfFactory(exported, `${label} (\\`${entry}\\`)`);\n }\n\n return callIfFactory(entry, label);\n}\n\n/**\n * A strategy is an object and a factory is a function, so `typeof` separates them.\n *\n * A factory returning `undefined` is passed straight back as `undefined` rather\n * than sent to the validator, because declining is one of the two answers a\n * factory is allowed to give. A bare `undefined` written directly in the array\n * is still invalid, and still reaches the validator: that is a typo rather than\n * a decision, and nothing about it says a key was missing.\n */\nasync function callIfFactory(\n value: unknown,\n label: string,\n): Promise<Result<PaymentStrategy | undefined>> {\n if (typeof value !== \"function\") return validatePaymentStrategy(value, label);\n\n const produced = await wrap(\n async () => (await (value as PaymentStrategyFactory)()) as unknown,\n (error) => ({\n category: \"UPSTREAM\",\n code: \"STRATEGY_FACTORY_FAILED\",\n message: `${label}: the strategy factory threw`,\n retryable: false,\n cause: causeOf(error),\n }),\n );\n if (!produced.ok) return produced;\n if (produced.value === undefined || produced.value === null) return ok(undefined);\n return validatePaymentStrategy(produced.value, label);\n}\n\n/**\n * Resolves a bare or relative specifier the way the consumer's own `import`\n * would: from the config file. Falls back to a plain dynamic import, which covers\n * a package the CommonJS resolver cannot see through its `exports` conditions.\n */\nasync function importSpecifier(\n specifier: string,\n configPath: string,\n): Promise<Result<Record<string, unknown>>> {\n const fromConfig = wrapSync(\n () => createRequire(pathToFileURL(configPath)).resolve(specifier),\n (error) => ({\n category: \"NOT_FOUND\",\n code: \"STRATEGY_MODULE_NOT_FOUND\",\n message: `\\`${specifier}\\` could not be resolved from \\`${configPath}\\``,\n retryable: false,\n details: { specifier, configPath },\n cause: causeOf(error),\n }),\n );\n\n if (fromConfig.ok) {\n return importModule(fromConfig.value, `strategy module \\`${specifier}\\``);\n }\n\n return wrap(\n async () => (await import(specifier)) as Record<string, unknown>,\n (error) => ({\n category: \"NOT_FOUND\",\n code: \"STRATEGY_MODULE_NOT_FOUND\",\n message: `\\`${specifier}\\` could not be imported from \\`${configPath}\\` or resolved as a bare module`,\n retryable: false,\n details: { specifier, configPath },\n cause: causeOf(error),\n }),\n );\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/payments/config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `tab.config.ts` discovery: the zero-code way to add a payment strategy.\n *\n * Zero-code wiring. A consumer writes a config file naming strategies as module\n * specifiers, and the strategies register themselves at startup with no\n * application code involved at all:\n *\n * ```ts\n * // tab.config.ts, at the consumer's project root\n * import { defineTabConfig } from \"@tabai/sdk\";\n * export default defineTabConfig({ strategies: [\"@acme/tab-strategy-session-key\"] });\n * ```\n *\n * ## What an entry may be\n *\n * A module specifier, a strategy object, or a factory returning one. The\n * specifier form is the point of the mechanism; the other two exist because a\n * config file that can only name packages forces a consumer to publish one before\n * they can try anything.\n *\n * ## Where a specifier resolves from\n *\n * From the **config file**, not from this package. `@acme/tab-strategy-session-key` is\n * the consumer's dependency and under pnpm it is not visible from inside\n * `@tabai/sdk` at all, so resolving relative to this module would fail for the\n * exact layout the workspace uses. `createRequire(configFileUrl)` resolves the\n * way the consumer's own `import` would, and a bare specifier that resolution\n * misses is retried as a plain dynamic import before the error is reported.\n *\n * ## The `.ts` config file and the host runtime\n *\n * This module imports the config file; it does not compile it. A `.ts` config\n * loads under a runtime that strips types (`tsx`, `node --experimental-strip-types`,\n * a bundler's dev server) and fails under one that does not. That failure comes\n * back as a `Result` naming the file and the requirement rather than as a stack\n * trace, and `tab.config.js` and `tab.config.mjs` are discovered too so a\n * consumer with a plain Node process has a first-class option.\n */\n\nimport { existsSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, isAbsolute, resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { causeOf, ok, wrap, wrapSync, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { notFoundError, validationError } from \"../errors.js\";\nimport { validatePaymentStrategy, type PaymentStrategy } from \"./strategy.js\";\nimport type { X402SignerFactory } from \"../x402/client.js\";\nimport {\n moduleStrategyRegistry,\n type StrategyRegistration,\n type StrategyRegistry,\n} from \"./registry.js\";\n\n/**\n * A factory in a config file, so a strategy that needs a signer can be built lazily.\n *\n * Returning `undefined` is a supported answer and means \"not available in this\n * environment\". That is what keeps every read on this rail keyless: the whole\n * point of a factory rather than an object is that a config file can declare a\n * strategy that only exists once a signing key does, and `tab_discover`,\n * `tab_status` and `doctor` never need one. A declining factory is skipped, and\n * the rest of the config - the Agent, the registry URL, the Service endpoints -\n * is kept.\n */\nexport type PaymentStrategyFactory = () =>\n | PaymentStrategy\n | undefined\n | Promise<PaymentStrategy | undefined>;\n\n/** A module specifier, a ready strategy, or a factory returning one. */\nexport type TabConfigStrategyEntry = string | PaymentStrategy | PaymentStrategyFactory;\n\n/**\n * One Service's off-chain coordinates.\n *\n * The chain records who operates a Service, what its tools cost and where it\n * collects Settlements. It records no URL, deliberately: an endpoint moves, and\n * a registry that pinned one would either go stale or need a write every time a\n * Service redeployed. So the endpoint is configuration, and this is where a\n * consumer states it.\n *\n * Without an entry here, `tab_discover` reports the Service with a null endpoint\n * and `tab_call` refuses it by name rather than inventing a URL.\n */\nexport interface TabServiceEntry {\n /** The Service's 32-byte registry key, as `tab_discover` reports it. */\n readonly serviceId: string;\n /** A label for a person. Defaults to the ascii the serviceId decodes to. */\n readonly name?: string;\n /** Absolute base URL `tab_call` sends requests to. */\n readonly endpoint: string;\n /**\n * The API Hub provider this Service fronts, if it fronts one.\n *\n * With this set, `tab_discover` fetches the provider's manifest and lists its\n * endpoints under the Service as the tools they are, each reachable through\n * the Service's `/hub/<prefix>` mount and metered onto the Agent's Open Tab.\n */\n readonly hub?: TabServiceHubEntry;\n /**\n * Headers sent with every call to this Service.\n *\n * A record for a Service that gates on something fixed, such as an API key. A\n * function for one that gates on something per request: Tab's metering\n * gateway, for instance, requires a claim over the method, the path, the Agent\n * and the tool, which no static header can satisfy. Tab defines neither scheme\n * and validates neither -- this is the seam through which a Service's own\n * access control stays the Service's own.\n *\n * Never a Tab credential. The Tab identity headers are added by the 402 client\n * and nothing in Tab authenticates an Agent with a bearer token.\n */\n readonly headers?: Readonly<Record<string, string>> | ServiceHeaderProvider;\n}\n\n/** An API Hub provider fronted by a Service. See {@link TabServiceEntry.hub}. */\nexport interface TabServiceHubEntry {\n /** The Hub's provider slug, for example `weather-underground`. */\n readonly provider: string;\n /** The mount under the Service endpoint. Defaults to the provider slug, so `/hub/<provider>`. */\n readonly prefix?: string;\n /** Overrides the manifest URL, for a mirror or a test. */\n readonly manifestUrl?: string;\n}\n\n/** Builds the per-request headers one Service requires. See {@link TabServiceEntry.headers}. */\nexport type ServiceHeaderProvider = (\n request: ServiceHeaderRequest,\n) => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;\n\n/** What the provider is told about the call it is producing headers for. */\nexport interface ServiceHeaderRequest {\n readonly method: string;\n /** The absolute URL the request is going to. */\n readonly url: string;\n /** The tool name as the caller gave it, before it is packed into a 32-byte key. */\n readonly tool: string;\n /** The Agent the call is metered against. */\n readonly agent: string;\n readonly serviceId: string;\n}\n\nexport interface TabConfig {\n readonly strategies?: readonly TabConfigStrategyEntry[];\n /**\n * The Agent's Monad address: whose Open Tab a metered call lands on.\n *\n * An address and never a key. Nothing in this package derives an address from\n * a private key, because doing so would mean a config file that holds one.\n */\n readonly agent?: string;\n /** Absolute base URL of the Tab registry read API, which serves discovery and status. */\n readonly registryUrl?: string;\n /** Where each Service can be reached. See {@link TabServiceEntry}. */\n readonly services?: readonly TabServiceEntry[];\n /**\n * The x402 signer, for the prepaid fallback.\n *\n * A factory and only a factory, for the reason `strategies` holds factories:\n * a signer is built from a key, and a config file must be loadable by the\n * three surfaces that hold none. Nothing calls this until a Service has\n * refused a call on credit and offered x402 for it, and a factory returning\n * `undefined` declines, which leaves that refusal the `LIMIT_EXCEEDED` it was.\n */\n readonly x402?: X402SignerFactory;\n}\n\n/**\n * Types a config file's default export. Identity at runtime, its whole job is to\n * make a typo in the config a compile error in the consumer's editor.\n */\nexport const defineTabConfig = (config: TabConfig): TabConfig => config;\n\n/**\n * The file names discovery looks for, in order. `.ts` first because it is the\n * documented form and the one that type-checks; the plain-JavaScript forms follow\n * so a consumer whose runtime strips no types is not shut out.\n */\nexport const TAB_CONFIG_FILE_NAMES = [\n \"tab.config.ts\",\n \"tab.config.mts\",\n \"tab.config.mjs\",\n \"tab.config.js\",\n \"tab.config.cjs\",\n] as const;\n\nexport interface FindTabConfigOptions {\n /** Where the walk starts. Defaults to the working directory. */\n readonly cwd?: string;\n readonly fileNames?: readonly string[];\n}\n\n/**\n * Walks from `cwd` towards the filesystem root and returns the first config file\n * found, or `undefined` when there is none.\n *\n * Absence is not an error: the whole point of the mechanism is that a consumer\n * who wants nothing from it writes nothing.\n */\nexport function findTabConfig(options: FindTabConfigOptions = {}): Result<string | undefined> {\n return wrapSync(\n () => {\n const fileNames = options.fileNames ?? TAB_CONFIG_FILE_NAMES;\n let directory = resolvePath(options.cwd ?? \".\");\n for (;;) {\n for (const fileName of fileNames) {\n const candidate = resolvePath(directory, fileName);\n if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;\n }\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n },\n (error) => ({\n category: \"INTERNAL\",\n code: \"CONFIG_SEARCH_FAILED\",\n message: \"the tab.config search could not read the filesystem\",\n retryable: false,\n cause: causeOf(error),\n }),\n );\n}\n\nexport interface LoadTabConfigOptions extends FindTabConfigOptions {\n /** An explicit config file. Absolute, or relative to `cwd`. Missing is an error. */\n readonly configPath?: string;\n /**\n * Where the discovered strategies are registered. Omitted means the\n * module-level registry, which is what makes the mechanism zero-code; `false`\n * loads and validates without registering anything.\n */\n readonly registry?: StrategyRegistry | false;\n readonly logger?: Logger;\n}\n\nexport interface LoadedTabConfig {\n /** The file that was loaded, or `undefined` when none was found. */\n readonly path: string | undefined;\n readonly config: TabConfig;\n readonly strategies: readonly PaymentStrategy[];\n /** Empty when `registry` was `false`. */\n readonly registrations: readonly StrategyRegistration[];\n}\n\nconst EMPTY_CONFIG: TabConfig = {};\n\n/**\n * Loads a config file, resolves every strategy entry, and registers the result.\n *\n * Returns a `Result` for every failure, including a config file that throws on\n * import: a consumer's config is consumer code, and this package does not turn\n * their mistake into an unhandled rejection.\n */\nexport async function loadTabConfig(\n options: LoadTabConfigOptions = {},\n): Promise<Result<LoadedTabConfig>> {\n const logger = options.logger ?? defaultLogger;\n\n const located = locateConfig(options);\n if (!located.ok) return located;\n const path = located.value;\n\n if (path === undefined) {\n return ok({ path: undefined, config: EMPTY_CONFIG, strategies: [], registrations: [] });\n }\n\n const imported = await importModule(path, `tab config \\`${path}\\``);\n if (!imported.ok) return imported;\n\n const config = readDefaultExport(imported.value, path);\n if (!config.ok) return config;\n\n const strategies: PaymentStrategy[] = [];\n let declined = 0;\n for (const [index, entry] of (config.value.strategies ?? []).entries()) {\n const resolved = await resolveEntry(entry, index, path);\n if (!resolved.ok) return resolved;\n // `undefined` is the factory declining, not a fault. Skip it and keep going.\n if (resolved.value === undefined) {\n declined += 1;\n continue;\n }\n strategies.push(resolved.value);\n }\n\n const registrations: StrategyRegistration[] = [];\n if (options.registry !== false) {\n const registry = options.registry ?? moduleStrategyRegistry(logger);\n for (const strategy of strategies) {\n const outcome = registry.register(strategy);\n if (!outcome.ok) return outcome;\n registrations.push(outcome.value);\n }\n }\n\n logger.debug(\"tab config loaded\", { path, strategies: strategies.length, declined });\n return ok({ path, config: config.value, strategies, registrations });\n}\n\nfunction locateConfig(options: LoadTabConfigOptions): Result<string | undefined> {\n if (options.configPath === undefined) return findTabConfig(options);\n\n const cwd = resolvePath(options.cwd ?? \".\");\n const path = isAbsolute(options.configPath)\n ? options.configPath\n : resolvePath(cwd, options.configPath);\n if (!existsSync(path)) {\n return notFoundError(\"CONFIG_NOT_FOUND\", `no tab config file at \\`${path}\\``, {\n details: { path },\n });\n }\n return ok(path);\n}\n\n/** Imports a file by path. A `.ts` file needs a type-stripping runtime, so say so. */\nasync function importModule(path: string, label: string): Promise<Result<Record<string, unknown>>> {\n const href = pathToFileURL(path).href;\n return wrap(\n async () => (await import(href)) as Record<string, unknown>,\n (error) => ({\n category: \"UPSTREAM\",\n code: \"CONFIG_IMPORT_FAILED\",\n message: path.endsWith(\".ts\") || path.endsWith(\".mts\")\n ? `${label} could not be imported; a TypeScript config file needs a runtime that strips types, or use tab.config.mjs`\n : `${label} could not be imported`,\n retryable: false,\n details: { path },\n cause: causeOf(error),\n }),\n );\n}\n\nfunction readDefaultExport(module: Record<string, unknown>, path: string): Result<TabConfig> {\n const exported = module[\"default\"];\n if (exported === undefined) {\n return validationError(\n \"CONFIG_NO_DEFAULT_EXPORT\",\n `\\`${path}\\` must default-export a config, for example \\`export default defineTabConfig({ strategies: [] })\\``,\n { details: { path } },\n );\n }\n if (typeof exported !== \"object\" || exported === null) {\n return validationError(\n \"CONFIG_INVALID\",\n `the default export of \\`${path}\\` must be an object`,\n { details: { path } },\n );\n }\n const candidate = exported as { strategies?: unknown; services?: unknown; x402?: unknown };\n if (candidate.x402 !== undefined && typeof candidate.x402 !== \"function\") {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`x402\\` but it is not a factory; it must be a function returning a signer or undefined, so the file holds no key`,\n { details: { path } },\n );\n }\n if (candidate.strategies !== undefined && !Array.isArray(candidate.strategies)) {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`strategies\\` but it is not an array`,\n { details: { path } },\n );\n }\n if (candidate.services !== undefined && !Array.isArray(candidate.services)) {\n return validationError(\n \"CONFIG_INVALID\",\n `\\`${path}\\` declares \\`services\\` but it is not an array`,\n { details: { path } },\n );\n }\n return ok(exported as TabConfig);\n}\n\nasync function resolveEntry(\n entry: TabConfigStrategyEntry,\n index: number,\n configPath: string,\n): Promise<Result<PaymentStrategy | undefined>> {\n const label = `strategies[${index}] of \\`${configPath}\\``;\n\n if (typeof entry === \"string\") {\n const module = await importSpecifier(entry, configPath);\n if (!module.ok) return module;\n const exported = module.value[\"default\"];\n if (exported === undefined) {\n return validationError(\n \"STRATEGY_MODULE_INVALID\",\n `${label}: \\`${entry}\\` must default-export a PaymentStrategy or a factory returning one`,\n { details: { specifier: entry } },\n );\n }\n return callIfFactory(exported, `${label} (\\`${entry}\\`)`);\n }\n\n return callIfFactory(entry, label);\n}\n\n/**\n * A strategy is an object and a factory is a function, so `typeof` separates them.\n *\n * A factory returning `undefined` is passed straight back as `undefined` rather\n * than sent to the validator, because declining is one of the two answers a\n * factory is allowed to give. A bare `undefined` written directly in the array\n * is still invalid, and still reaches the validator: that is a typo rather than\n * a decision, and nothing about it says a key was missing.\n */\nasync function callIfFactory(\n value: unknown,\n label: string,\n): Promise<Result<PaymentStrategy | undefined>> {\n if (typeof value !== \"function\") return validatePaymentStrategy(value, label);\n\n const produced = await wrap(\n async () => (await (value as PaymentStrategyFactory)()) as unknown,\n (error) => ({\n category: \"UPSTREAM\",\n code: \"STRATEGY_FACTORY_FAILED\",\n message: `${label}: the strategy factory threw`,\n retryable: false,\n cause: causeOf(error),\n }),\n );\n if (!produced.ok) return produced;\n if (produced.value === undefined || produced.value === null) return ok(undefined);\n return validatePaymentStrategy(produced.value, label);\n}\n\n/**\n * Resolves a bare or relative specifier the way the consumer's own `import`\n * would: from the config file. Falls back to a plain dynamic import, which covers\n * a package the CommonJS resolver cannot see through its `exports` conditions.\n */\nasync function importSpecifier(\n specifier: string,\n configPath: string,\n): Promise<Result<Record<string, unknown>>> {\n const fromConfig = wrapSync(\n () => createRequire(pathToFileURL(configPath)).resolve(specifier),\n (error) => ({\n category: \"NOT_FOUND\",\n code: \"STRATEGY_MODULE_NOT_FOUND\",\n message: `\\`${specifier}\\` could not be resolved from \\`${configPath}\\``,\n retryable: false,\n details: { specifier, configPath },\n cause: causeOf(error),\n }),\n );\n\n if (fromConfig.ok) {\n return importModule(fromConfig.value, `strategy module \\`${specifier}\\``);\n }\n\n return wrap(\n async () => (await import(specifier)) as Record<string, unknown>,\n (error) => ({\n category: \"NOT_FOUND\",\n code: \"STRATEGY_MODULE_NOT_FOUND\",\n message: `\\`${specifier}\\` could not be imported from \\`${configPath}\\` or resolved as a bare module`,\n retryable: false,\n details: { specifier, configPath },\n cause: causeOf(error),\n }),\n );\n}\n"]}
@@ -1,7 +1,5 @@
1
1
  /**
2
2
  * The payment-strategy seam, assembled.
3
- *
4
- * Requirements: 23.1, 23.6, 23.7
5
3
  */
6
4
  export * from "./strategy.js";
7
5
  export * from "./registry.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -1,7 +1,5 @@
1
1
  /**
2
2
  * The payment-strategy seam, assembled.
3
- *
4
- * Requirements: 23.1, 23.6, 23.7
5
3
  */
6
4
  export * from "./strategy.js";
7
5
  export * from "./registry.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC","sourcesContent":["/**\n * The payment-strategy seam, assembled.\n *\n * Requirements: 23.1, 23.6, 23.7\n */\n\nexport * from \"./strategy.js\";\nexport * from \"./registry.js\";\nexport * from \"./config.js\";\nexport * from \"./abi.js\";\nexport * from \"./monad.js\";\nexport * from \"./kuru.js\";\nexport * from \"./permit2.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/payments/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC","sourcesContent":["/**\n * The payment-strategy seam, assembled.\n */\n\nexport * from \"./strategy.js\";\nexport * from \"./registry.js\";\nexport * from \"./config.js\";\nexport * from \"./abi.js\";\nexport * from \"./monad.js\";\nexport * from \"./kuru.js\";\nexport * from \"./permit2.js\";\n"]}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Strategy registration and resolution: mechanisms one and two of R23.6.
2
+ * Strategy registration and resolution: constructor injection and the
3
+ * module-level registry.
3
4
  *
4
5
  * One implementation serves both. A registry is a keyed set of strategies with an
5
6
  * optional parent it falls back to:
@@ -16,8 +17,8 @@
16
17
  * ## Why the module-level state hangs off `globalThis`
17
18
  *
18
19
  * A plugin package that self-registers on import may resolve a *different copy*
19
- * of `@tabai/sdk` than the application does, different versions, a nested
20
- * `node_modules`, a bundled duplicate. With module-scoped state each copy gets
20
+ * of `@tabai/sdk` than the application does (different versions, a nested
21
+ * `node_modules`, a bundled duplicate). With module-scoped state each copy gets
21
22
  * its own registry, the plugin registers into a registry the application never
22
23
  * reads, and the failure is silent: the strategy simply never resolves. So the
23
24
  * state lives under a versioned `Symbol.for` key on `globalThis` and every copy
@@ -30,9 +31,9 @@
30
31
  *
31
32
  * - the same object again is a no-op, `unchanged`, no warning, no reordering;
32
33
  * - a *different* object under a live id replaces it **in its original
33
- * position** and warns through the logger rather than throwing (design section
34
- * 9.3), because a strategy replaced at the back of the queue would silently
35
- * change which strategy resolves for every other Asset too;
34
+ * position** and warns through the logger rather than throwing, because a
35
+ * strategy replaced at the back of the queue would silently change which
36
+ * strategy resolves for every other Asset too;
36
37
  * - anything else appends.
37
38
  *
38
39
  * Order matters because resolution order is registration order, so the operation
@@ -43,11 +44,9 @@
43
44
  *
44
45
  * An explicit `strategyId` wins. Otherwise the first strategy whose
45
46
  * `supports(asset)` returns true, in registration order, own entries before the
46
- * parent's (design section 9.3). A named strategy that does not support the Asset
47
+ * parent's. A named strategy that does not support the Asset
47
48
  * is an error rather than a silent fall-through to another one: a caller that
48
49
  * named a strategy meant it.
49
- *
50
- * Requirements: 23.6, 21.5
51
50
  */
52
51
  import { type Result } from "../_shared/index.js";
53
52
  import { type Logger } from "../logger.js";
@@ -97,13 +96,13 @@ export interface StrategyRegistryOptions {
97
96
  * directly when the caller wants the `Result` for each one.
98
97
  */
99
98
  export declare function createStrategyRegistry(options?: StrategyRegistryOptions): StrategyRegistry;
100
- /** The process-wide registry mechanism two writes to. */
99
+ /** The process-wide registry that {@link registerPaymentStrategy} writes to. */
101
100
  export declare function moduleStrategyRegistry(logger?: Logger): StrategyRegistry;
102
101
  /**
103
102
  * Registers a strategy process-wide. Idempotent by `strategy.id`.
104
103
  *
105
- * This is the whole of mechanism two: a plugin package calls it at import time,
106
- * and the consumer's only line is `import "@acme/tab-strategy-solana"`.
104
+ * A plugin package calls it at import time, and the consumer's only line is
105
+ * `import "@acme/tab-strategy-session-key"`.
107
106
  */
108
107
  export declare function registerPaymentStrategy(strategy: PaymentStrategy, options?: {
109
108
  readonly logger?: Logger;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/payments/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;CACrC;AAED,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAClE,8EAA8E;IAC9E,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,8DAA8D;IAC9D,KAAK,IAAI,IAAI,CAAC;IACd,+EAA+E;IAC/E,IAAI,IAAI,SAAS,eAAe,EAAE,CAAC;IACnC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAC7C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;CAC7C;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAe9F;AAED,yDAAyD;AACzD,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACzC,MAAM,CAAC,oBAAoB,CAAC,CAE9B;AAED,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,GAAI,IAAI,MAAM,KAAG,OACd,CAAC;AAE1C,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,QAAO,SAAS,eAAe,EAChC,CAAC;AAElC,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,QAAO,IAAwC,CAAC;AAEnF,wDAAwD;AACxD,eAAO,MAAM,sBAAsB,GAAI,OAAO,aAAa,KAAG,MAAM,CAAC,eAAe,CAC3C,CAAC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/payments/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;CACrC;AAED,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAClE,8EAA8E;IAC9E,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,8DAA8D;IAC9D,KAAK,IAAI,IAAI,CAAC;IACd,+EAA+E;IAC/E,IAAI,IAAI,SAAS,eAAe,EAAE,CAAC;IACnC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAC7C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;CAC7C;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAe9F;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACzC,MAAM,CAAC,oBAAoB,CAAC,CAE9B;AAED,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,GAAI,IAAI,MAAM,KAAG,OACd,CAAC;AAE1C,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,QAAO,SAAS,eAAe,EAChC,CAAC;AAElC,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,QAAO,IAAwC,CAAC;AAEnF,wDAAwD;AACxD,eAAO,MAAM,sBAAsB,GAAI,OAAO,aAAa,KAAG,MAAM,CAAC,eAAe,CAC3C,CAAC"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Strategy registration and resolution: mechanisms one and two of R23.6.
2
+ * Strategy registration and resolution: constructor injection and the
3
+ * module-level registry.
3
4
  *
4
5
  * One implementation serves both. A registry is a keyed set of strategies with an
5
6
  * optional parent it falls back to:
@@ -16,8 +17,8 @@
16
17
  * ## Why the module-level state hangs off `globalThis`
17
18
  *
18
19
  * A plugin package that self-registers on import may resolve a *different copy*
19
- * of `@tabai/sdk` than the application does, different versions, a nested
20
- * `node_modules`, a bundled duplicate. With module-scoped state each copy gets
20
+ * of `@tabai/sdk` than the application does (different versions, a nested
21
+ * `node_modules`, a bundled duplicate). With module-scoped state each copy gets
21
22
  * its own registry, the plugin registers into a registry the application never
22
23
  * reads, and the failure is silent: the strategy simply never resolves. So the
23
24
  * state lives under a versioned `Symbol.for` key on `globalThis` and every copy
@@ -30,9 +31,9 @@
30
31
  *
31
32
  * - the same object again is a no-op, `unchanged`, no warning, no reordering;
32
33
  * - a *different* object under a live id replaces it **in its original
33
- * position** and warns through the logger rather than throwing (design section
34
- * 9.3), because a strategy replaced at the back of the queue would silently
35
- * change which strategy resolves for every other Asset too;
34
+ * position** and warns through the logger rather than throwing, because a
35
+ * strategy replaced at the back of the queue would silently change which
36
+ * strategy resolves for every other Asset too;
36
37
  * - anything else appends.
37
38
  *
38
39
  * Order matters because resolution order is registration order, so the operation
@@ -43,11 +44,9 @@
43
44
  *
44
45
  * An explicit `strategyId` wins. Otherwise the first strategy whose
45
46
  * `supports(asset)` returns true, in registration order, own entries before the
46
- * parent's (design section 9.3). A named strategy that does not support the Asset
47
+ * parent's. A named strategy that does not support the Asset
47
48
  * is an error rather than a silent fall-through to another one: a caller that
48
49
  * named a strategy meant it.
49
- *
50
- * Requirements: 23.6, 21.5
51
50
  */
52
51
  import { ok } from "../_shared/index.js";
53
52
  import { defaultLogger } from "../logger.js";
@@ -88,15 +87,15 @@ export function createStrategyRegistry(options = {}) {
88
87
  }
89
88
  return registry;
90
89
  }
91
- /** The process-wide registry mechanism two writes to. */
90
+ /** The process-wide registry that {@link registerPaymentStrategy} writes to. */
92
91
  export function moduleStrategyRegistry(logger) {
93
92
  return registryOver(moduleState().strategies, logger ?? defaultLogger, () => undefined);
94
93
  }
95
94
  /**
96
95
  * Registers a strategy process-wide. Idempotent by `strategy.id`.
97
96
  *
98
- * This is the whole of mechanism two: a plugin package calls it at import time,
99
- * and the consumer's only line is `import "@acme/tab-strategy-solana"`.
97
+ * A plugin package calls it at import time, and the consumer's only line is
98
+ * `import "@acme/tab-strategy-session-key"`.
100
99
  */
101
100
  export function registerPaymentStrategy(strategy, options = {}) {
102
101
  return moduleStrategyRegistry(options.logger).register(strategy);
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/payments/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Strategy registration and resolution: mechanisms one and two of R23.6.\n *\n * One implementation serves both. A registry is a keyed set of strategies with an\n * optional parent it falls back to:\n *\n * - **Constructor injection.** `createStrategyRegistry({ strategies: [...] })`\n * is what a client wrapper builds from its own options, so a consumer passes\n * strategies in and never touches global state. Its parent is the module-level\n * registry by default, so injection adds to what is already registered instead\n * of hiding it.\n * - **The module-level registry.** `registerPaymentStrategy(strategy)` writes to\n * one process-wide registry, which is what a plugin package needs: it\n * self-registers on import and the consumer's only line is the import.\n *\n * ## Why the module-level state hangs off `globalThis`\n *\n * A plugin package that self-registers on import may resolve a *different copy*\n * of `@tabai/sdk` than the application does, different versions, a nested\n * `node_modules`, a bundled duplicate. With module-scoped state each copy gets\n * its own registry, the plugin registers into a registry the application never\n * reads, and the failure is silent: the strategy simply never resolves. So the\n * state lives under a versioned `Symbol.for` key on `globalThis` and every copy\n * of this module wraps the same `Map`. Only the shared state is global; the\n * behaviour is each copy's own.\n *\n * ## Idempotence, and what replacement means\n *\n * `register` is keyed by `strategy.id`:\n *\n * - the same object again is a no-op, `unchanged`, no warning, no reordering;\n * - a *different* object under a live id replaces it **in its original\n * position** and warns through the logger rather than throwing (design section\n * 9.3), because a strategy replaced at the back of the queue would silently\n * change which strategy resolves for every other Asset too;\n * - anything else appends.\n *\n * Order matters because resolution order is registration order, so the operation\n * has to be idempotent in the ordering as well as in the membership. `Map.set`\n * on a live key keeps the key's insertion position, which is exactly this rule.\n *\n * ## Resolution order\n *\n * An explicit `strategyId` wins. Otherwise the first strategy whose\n * `supports(asset)` returns true, in registration order, own entries before the\n * parent's (design section 9.3). A named strategy that does not support the Asset\n * is an error rather than a silent fall-through to another one: a caller that\n * named a strategy meant it.\n *\n * Requirements: 23.6, 21.5\n */\n\nimport { ok, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { notFoundError, validationError } from \"../errors.js\";\nimport {\n assetKey,\n supportsAsset,\n validatePaymentStrategy,\n type AssetRef,\n type PaymentStrategy,\n} from \"./strategy.js\";\n\n/** What `register` did. `unchanged` is the idempotent case. */\nexport type RegistrationAction = \"registered\" | \"replaced\" | \"unchanged\";\n\nexport interface StrategyRegistration {\n readonly action: RegistrationAction;\n readonly strategy: PaymentStrategy;\n /** The strategy that was displaced, on `replaced` alone. */\n readonly previous?: PaymentStrategy;\n}\n\n/** What resolution is given: the Asset that must be settled, and an optional override. */\nexport interface StrategyQuery {\n readonly asset: AssetRef;\n readonly strategyId?: string;\n}\n\nexport interface StrategyRegistry {\n register(strategy: PaymentStrategy): Result<StrategyRegistration>;\n /** Removes a strategy from *this* registry. Never reaches into the parent. */\n unregister(id: string): boolean;\n /** Empties *this* registry. Never reaches into the parent. */\n clear(): void;\n /** This registry's own strategies in registration order, then the parent's. */\n list(): readonly PaymentStrategy[];\n get(id: string): PaymentStrategy | undefined;\n resolve(query: StrategyQuery): Result<PaymentStrategy>;\n}\n\nexport interface StrategyRegistryOptions {\n /** Registered in array order at construction. Mechanism one. */\n readonly strategies?: readonly PaymentStrategy[];\n readonly logger?: Logger;\n /**\n * The registry to fall back to. Omitted means the module-level registry;\n * `false` means an isolated registry, which is what the module-level registry\n * itself is and what a test wants.\n */\n readonly inherit?: StrategyRegistry | false;\n}\n\n/** Versioned so a future state-shape change cannot be misread by an older copy. */\nconst MODULE_STATE_KEY = Symbol.for(\"@tabai/sdk.paymentStrategies.v1\");\n\ninterface ModuleState {\n readonly version: 1;\n readonly strategies: Map<string, PaymentStrategy>;\n}\n\nfunction moduleState(): ModuleState {\n const host = globalThis as typeof globalThis & { [MODULE_STATE_KEY]?: ModuleState };\n const existing = host[MODULE_STATE_KEY];\n if (existing !== undefined && existing.version === 1) return existing;\n const created: ModuleState = { version: 1, strategies: new Map() };\n host[MODULE_STATE_KEY] = created;\n return created;\n}\n\n/**\n * Builds a registry.\n *\n * Construction cannot fail, so it does not return a `Result`. An invalid entry in\n * `strategies` is refused and reported through the logger, and the registry comes\n * back holding the valid ones, a consumer's typo in one strategy should not take\n * out the strategies that were fine. Use {@link StrategyRegistry.register}\n * directly when the caller wants the `Result` for each one.\n */\nexport function createStrategyRegistry(options: StrategyRegistryOptions = {}): StrategyRegistry {\n const logger = options.logger ?? defaultLogger;\n const own = new Map<string, PaymentStrategy>();\n const registry = registryOver(own, logger, () => resolveParent(options.inherit));\n\n for (const strategy of options.strategies ?? []) {\n const outcome = registry.register(strategy);\n if (!outcome.ok) {\n logger.error(\"payment strategy rejected at construction\", {\n code: outcome.error.code,\n message: outcome.error.message,\n });\n }\n }\n return registry;\n}\n\n/** The process-wide registry mechanism two writes to. */\nexport function moduleStrategyRegistry(logger?: Logger): StrategyRegistry {\n return registryOver(moduleState().strategies, logger ?? defaultLogger, () => undefined);\n}\n\n/**\n * Registers a strategy process-wide. Idempotent by `strategy.id`.\n *\n * This is the whole of mechanism two: a plugin package calls it at import time,\n * and the consumer's only line is `import \"@acme/tab-strategy-solana\"`.\n */\nexport function registerPaymentStrategy(\n strategy: PaymentStrategy,\n options: { readonly logger?: Logger } = {},\n): Result<StrategyRegistration> {\n return moduleStrategyRegistry(options.logger).register(strategy);\n}\n\n/** Removes a process-wide registration. Returns false when the id was not registered. */\nexport const unregisterPaymentStrategy = (id: string): boolean =>\n moduleStrategyRegistry().unregister(id);\n\n/** Every process-wide registration, in registration order. */\nexport const listPaymentStrategies = (): readonly PaymentStrategy[] =>\n moduleStrategyRegistry().list();\n\n/** Empties the process-wide registry. Present for hosts that rebuild their world. */\nexport const clearPaymentStrategies = (): void => moduleStrategyRegistry().clear();\n\n/** Resolves against the process-wide registry alone. */\nexport const resolvePaymentStrategy = (query: StrategyQuery): Result<PaymentStrategy> =>\n moduleStrategyRegistry().resolve(query);\n\nfunction resolveParent(inherit: StrategyRegistry | false | undefined): StrategyRegistry | undefined {\n if (inherit === false) return undefined;\n if (inherit !== undefined) return inherit;\n return moduleStrategyRegistry();\n}\n\n/**\n * The one registry implementation, over a `Map` it does not own.\n *\n * `parent` is a thunk so the module-level registry can be the default parent\n * without this function forcing it into existence at construction time, which\n * would make the load order of two modules matter.\n */\nfunction registryOver(\n own: Map<string, PaymentStrategy>,\n logger: Logger,\n parent: () => StrategyRegistry | undefined,\n): StrategyRegistry {\n const registry: StrategyRegistry = {\n register(candidate) {\n const validated = validatePaymentStrategy(candidate);\n if (!validated.ok) return validated;\n const strategy = validated.value;\n const previous = own.get(strategy.id);\n\n if (previous === strategy) {\n return ok({ action: \"unchanged\", strategy });\n }\n if (previous !== undefined) {\n // Map.set keeps the key's original insertion position, so the replacement\n // inherits the displaced strategy's place in the resolution order.\n own.set(strategy.id, strategy);\n logger.warn(\"payment strategy replaced an earlier registration of the same id\", {\n strategyId: strategy.id,\n chainIds: strategy.chainIds.map((chainId) => chainId.toString(10)),\n });\n return ok({ action: \"replaced\", strategy, previous });\n }\n own.set(strategy.id, strategy);\n return ok({ action: \"registered\", strategy });\n },\n\n unregister: (id) => own.delete(id),\n\n clear: () => own.clear(),\n\n list() {\n const inherited = parent()?.list() ?? [];\n const merged = [...own.values()];\n for (const strategy of inherited) {\n if (!own.has(strategy.id)) merged.push(strategy);\n }\n return merged;\n },\n\n get(id) {\n return own.get(id) ?? parent()?.get(id);\n },\n\n resolve(query) {\n const candidates = registry.list();\n const onThrow = (strategyId: string) => (error: unknown) =>\n logger.warn(\"payment strategy supports() threw and was read as unsupported\", {\n strategyId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (query.strategyId !== undefined) {\n const named = registry.get(query.strategyId);\n if (named === undefined) {\n return notFoundError(\n \"STRATEGY_NOT_FOUND\",\n `no payment strategy is registered under id \\`${query.strategyId}\\``,\n {\n details: {\n strategyId: query.strategyId,\n registered: candidates.map((strategy) => strategy.id).join(\", \"),\n },\n },\n );\n }\n if (!supportsAsset(named, query.asset, onThrow(named.id))) {\n return validationError(\n \"STRATEGY_ASSET_MISMATCH\",\n `payment strategy \\`${named.id}\\` does not support asset ${assetKey(query.asset)}`,\n { details: { strategyId: named.id, asset: assetKey(query.asset) } },\n );\n }\n return ok(named);\n }\n\n for (const strategy of candidates) {\n if (supportsAsset(strategy, query.asset, onThrow(strategy.id))) return ok(strategy);\n }\n return notFoundError(\n \"NO_STRATEGY_FOR_ASSET\",\n `no registered payment strategy supports asset ${assetKey(query.asset)}`,\n {\n details: {\n asset: assetKey(query.asset),\n registered: candidates.map((strategy) => strategy.id).join(\", \"),\n },\n },\n );\n },\n };\n\n return registry;\n}\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/payments/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Strategy registration and resolution: constructor injection and the\n * module-level registry.\n *\n * One implementation serves both. A registry is a keyed set of strategies with an\n * optional parent it falls back to:\n *\n * - **Constructor injection.** `createStrategyRegistry({ strategies: [...] })`\n * is what a client wrapper builds from its own options, so a consumer passes\n * strategies in and never touches global state. Its parent is the module-level\n * registry by default, so injection adds to what is already registered instead\n * of hiding it.\n * - **The module-level registry.** `registerPaymentStrategy(strategy)` writes to\n * one process-wide registry, which is what a plugin package needs: it\n * self-registers on import and the consumer's only line is the import.\n *\n * ## Why the module-level state hangs off `globalThis`\n *\n * A plugin package that self-registers on import may resolve a *different copy*\n * of `@tabai/sdk` than the application does (different versions, a nested\n * `node_modules`, a bundled duplicate). With module-scoped state each copy gets\n * its own registry, the plugin registers into a registry the application never\n * reads, and the failure is silent: the strategy simply never resolves. So the\n * state lives under a versioned `Symbol.for` key on `globalThis` and every copy\n * of this module wraps the same `Map`. Only the shared state is global; the\n * behaviour is each copy's own.\n *\n * ## Idempotence, and what replacement means\n *\n * `register` is keyed by `strategy.id`:\n *\n * - the same object again is a no-op, `unchanged`, no warning, no reordering;\n * - a *different* object under a live id replaces it **in its original\n * position** and warns through the logger rather than throwing, because a\n * strategy replaced at the back of the queue would silently change which\n * strategy resolves for every other Asset too;\n * - anything else appends.\n *\n * Order matters because resolution order is registration order, so the operation\n * has to be idempotent in the ordering as well as in the membership. `Map.set`\n * on a live key keeps the key's insertion position, which is exactly this rule.\n *\n * ## Resolution order\n *\n * An explicit `strategyId` wins. Otherwise the first strategy whose\n * `supports(asset)` returns true, in registration order, own entries before the\n * parent's. A named strategy that does not support the Asset\n * is an error rather than a silent fall-through to another one: a caller that\n * named a strategy meant it.\n */\n\nimport { ok, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { notFoundError, validationError } from \"../errors.js\";\nimport {\n assetKey,\n supportsAsset,\n validatePaymentStrategy,\n type AssetRef,\n type PaymentStrategy,\n} from \"./strategy.js\";\n\n/** What `register` did. `unchanged` is the idempotent case. */\nexport type RegistrationAction = \"registered\" | \"replaced\" | \"unchanged\";\n\nexport interface StrategyRegistration {\n readonly action: RegistrationAction;\n readonly strategy: PaymentStrategy;\n /** The strategy that was displaced, on `replaced` alone. */\n readonly previous?: PaymentStrategy;\n}\n\n/** What resolution is given: the Asset that must be settled, and an optional override. */\nexport interface StrategyQuery {\n readonly asset: AssetRef;\n readonly strategyId?: string;\n}\n\nexport interface StrategyRegistry {\n register(strategy: PaymentStrategy): Result<StrategyRegistration>;\n /** Removes a strategy from *this* registry. Never reaches into the parent. */\n unregister(id: string): boolean;\n /** Empties *this* registry. Never reaches into the parent. */\n clear(): void;\n /** This registry's own strategies in registration order, then the parent's. */\n list(): readonly PaymentStrategy[];\n get(id: string): PaymentStrategy | undefined;\n resolve(query: StrategyQuery): Result<PaymentStrategy>;\n}\n\nexport interface StrategyRegistryOptions {\n /** Registered in array order at construction. Mechanism one. */\n readonly strategies?: readonly PaymentStrategy[];\n readonly logger?: Logger;\n /**\n * The registry to fall back to. Omitted means the module-level registry;\n * `false` means an isolated registry, which is what the module-level registry\n * itself is and what a test wants.\n */\n readonly inherit?: StrategyRegistry | false;\n}\n\n/** Versioned so a future state-shape change cannot be misread by an older copy. */\nconst MODULE_STATE_KEY = Symbol.for(\"@tabai/sdk.paymentStrategies.v1\");\n\ninterface ModuleState {\n readonly version: 1;\n readonly strategies: Map<string, PaymentStrategy>;\n}\n\nfunction moduleState(): ModuleState {\n const host = globalThis as typeof globalThis & { [MODULE_STATE_KEY]?: ModuleState };\n const existing = host[MODULE_STATE_KEY];\n if (existing !== undefined && existing.version === 1) return existing;\n const created: ModuleState = { version: 1, strategies: new Map() };\n host[MODULE_STATE_KEY] = created;\n return created;\n}\n\n/**\n * Builds a registry.\n *\n * Construction cannot fail, so it does not return a `Result`. An invalid entry in\n * `strategies` is refused and reported through the logger, and the registry comes\n * back holding the valid ones, a consumer's typo in one strategy should not take\n * out the strategies that were fine. Use {@link StrategyRegistry.register}\n * directly when the caller wants the `Result` for each one.\n */\nexport function createStrategyRegistry(options: StrategyRegistryOptions = {}): StrategyRegistry {\n const logger = options.logger ?? defaultLogger;\n const own = new Map<string, PaymentStrategy>();\n const registry = registryOver(own, logger, () => resolveParent(options.inherit));\n\n for (const strategy of options.strategies ?? []) {\n const outcome = registry.register(strategy);\n if (!outcome.ok) {\n logger.error(\"payment strategy rejected at construction\", {\n code: outcome.error.code,\n message: outcome.error.message,\n });\n }\n }\n return registry;\n}\n\n/** The process-wide registry that {@link registerPaymentStrategy} writes to. */\nexport function moduleStrategyRegistry(logger?: Logger): StrategyRegistry {\n return registryOver(moduleState().strategies, logger ?? defaultLogger, () => undefined);\n}\n\n/**\n * Registers a strategy process-wide. Idempotent by `strategy.id`.\n *\n * A plugin package calls it at import time, and the consumer's only line is\n * `import \"@acme/tab-strategy-session-key\"`.\n */\nexport function registerPaymentStrategy(\n strategy: PaymentStrategy,\n options: { readonly logger?: Logger } = {},\n): Result<StrategyRegistration> {\n return moduleStrategyRegistry(options.logger).register(strategy);\n}\n\n/** Removes a process-wide registration. Returns false when the id was not registered. */\nexport const unregisterPaymentStrategy = (id: string): boolean =>\n moduleStrategyRegistry().unregister(id);\n\n/** Every process-wide registration, in registration order. */\nexport const listPaymentStrategies = (): readonly PaymentStrategy[] =>\n moduleStrategyRegistry().list();\n\n/** Empties the process-wide registry. Present for hosts that rebuild their world. */\nexport const clearPaymentStrategies = (): void => moduleStrategyRegistry().clear();\n\n/** Resolves against the process-wide registry alone. */\nexport const resolvePaymentStrategy = (query: StrategyQuery): Result<PaymentStrategy> =>\n moduleStrategyRegistry().resolve(query);\n\nfunction resolveParent(inherit: StrategyRegistry | false | undefined): StrategyRegistry | undefined {\n if (inherit === false) return undefined;\n if (inherit !== undefined) return inherit;\n return moduleStrategyRegistry();\n}\n\n/**\n * The one registry implementation, over a `Map` it does not own.\n *\n * `parent` is a thunk so the module-level registry can be the default parent\n * without this function forcing it into existence at construction time, which\n * would make the load order of two modules matter.\n */\nfunction registryOver(\n own: Map<string, PaymentStrategy>,\n logger: Logger,\n parent: () => StrategyRegistry | undefined,\n): StrategyRegistry {\n const registry: StrategyRegistry = {\n register(candidate) {\n const validated = validatePaymentStrategy(candidate);\n if (!validated.ok) return validated;\n const strategy = validated.value;\n const previous = own.get(strategy.id);\n\n if (previous === strategy) {\n return ok({ action: \"unchanged\", strategy });\n }\n if (previous !== undefined) {\n // Map.set keeps the key's original insertion position, so the replacement\n // inherits the displaced strategy's place in the resolution order.\n own.set(strategy.id, strategy);\n logger.warn(\"payment strategy replaced an earlier registration of the same id\", {\n strategyId: strategy.id,\n chainIds: strategy.chainIds.map((chainId) => chainId.toString(10)),\n });\n return ok({ action: \"replaced\", strategy, previous });\n }\n own.set(strategy.id, strategy);\n return ok({ action: \"registered\", strategy });\n },\n\n unregister: (id) => own.delete(id),\n\n clear: () => own.clear(),\n\n list() {\n const inherited = parent()?.list() ?? [];\n const merged = [...own.values()];\n for (const strategy of inherited) {\n if (!own.has(strategy.id)) merged.push(strategy);\n }\n return merged;\n },\n\n get(id) {\n return own.get(id) ?? parent()?.get(id);\n },\n\n resolve(query) {\n const candidates = registry.list();\n const onThrow = (strategyId: string) => (error: unknown) =>\n logger.warn(\"payment strategy supports() threw and was read as unsupported\", {\n strategyId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (query.strategyId !== undefined) {\n const named = registry.get(query.strategyId);\n if (named === undefined) {\n return notFoundError(\n \"STRATEGY_NOT_FOUND\",\n `no payment strategy is registered under id \\`${query.strategyId}\\``,\n {\n details: {\n strategyId: query.strategyId,\n registered: candidates.map((strategy) => strategy.id).join(\", \"),\n },\n },\n );\n }\n if (!supportsAsset(named, query.asset, onThrow(named.id))) {\n return validationError(\n \"STRATEGY_ASSET_MISMATCH\",\n `payment strategy \\`${named.id}\\` does not support asset ${assetKey(query.asset)}`,\n { details: { strategyId: named.id, asset: assetKey(query.asset) } },\n );\n }\n return ok(named);\n }\n\n for (const strategy of candidates) {\n if (supportsAsset(strategy, query.asset, onThrow(strategy.id))) return ok(strategy);\n }\n return notFoundError(\n \"NO_STRATEGY_FOR_ASSET\",\n `no registered payment strategy supports asset ${assetKey(query.asset)}`,\n {\n details: {\n asset: assetKey(query.asset),\n registered: candidates.map((strategy) => strategy.id).join(\", \"),\n },\n },\n );\n },\n };\n\n return registry;\n}\n"]}
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * The payment-strategy seam.
3
3
  *
4
- * A strategy is how an Agent pays down an Open Tab. On Monad there is exactly one
5
- * way: approve the Asset and call `TabSettlement.settle`, which moves the Asset to
6
- * the Service and applies the Settlement in the same transaction. The seam still
7
- * exists so that a different signer, a smart account, a session key, or a test
8
- * double can stand behind the same call without the SDK caring which.
4
+ * A strategy is how an Agent pays down an Open Tab. Every Settlement lands through
5
+ * `TabSettlement`, which moves the Asset to the Service and applies the Settlement
6
+ * in the same transaction, by one of two entry points: `settle`, sent by the Agent
7
+ * after an approval (`createMonadStrategy`), or `settleWithPermit2`, signed by the
8
+ * Agent and sent by a relayer (`createRelayedMonadStrategy`).
9
+ * `createKuruFundedStrategy` wraps either one and swaps the Asset in first when
10
+ * the Agent is short. The seam also lets a different signer, a smart account, a
11
+ * session key, or a test double stand behind the same call without the SDK
12
+ * caring which.
9
13
  *
10
14
  * ## What a strategy does not do
11
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../src/payments/strategy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../src/payments/strategy.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * The payment-strategy seam.
3
3
  *
4
- * A strategy is how an Agent pays down an Open Tab. On Monad there is exactly one
5
- * way: approve the Asset and call `TabSettlement.settle`, which moves the Asset to
6
- * the Service and applies the Settlement in the same transaction. The seam still
7
- * exists so that a different signer, a smart account, a session key, or a test
8
- * double can stand behind the same call without the SDK caring which.
4
+ * A strategy is how an Agent pays down an Open Tab. Every Settlement lands through
5
+ * `TabSettlement`, which moves the Asset to the Service and applies the Settlement
6
+ * in the same transaction, by one of two entry points: `settle`, sent by the Agent
7
+ * after an approval (`createMonadStrategy`), or `settleWithPermit2`, signed by the
8
+ * Agent and sent by a relayer (`createRelayedMonadStrategy`).
9
+ * `createKuruFundedStrategy` wraps either one and swaps the Asset in first when
10
+ * the Agent is short. The seam also lets a different signer, a smart account, a
11
+ * session key, or a test double stand behind the same call without the SDK
12
+ * caring which.
9
13
  *
10
14
  * ## What a strategy does not do
11
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/payments/strategy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The payment-strategy seam.\n *\n * A strategy is how an Agent pays down an Open Tab. On Monad there is exactly one\n * way: approve the Asset and call `TabSettlement.settle`, which moves the Asset to\n * the Service and applies the Settlement in the same transaction. The seam still\n * exists so that a different signer, a smart account, a session key, or a test\n * double can stand behind the same call without the SDK caring which.\n *\n * ## What a strategy does not do\n *\n * It does not meter, it does not read tabs, and it does not decide amounts. It is\n * handed a fully specified charge and returns either a receipt or a typed error.\n * Every figure crossing this seam is a `bigint` count of Asset base units, never a\n * number and never a decimal string.\n */\nimport { isAddress, isBytes32, ok, type Address, type Bytes32, type Hex, type Result } from \"../_shared/index.js\";\nimport { validationError } from \"../errors.js\";\n\n/** One Asset a tab can be denominated in. `chainId` is the EVM chain id. */\nexport interface AssetRef {\n readonly chainId: bigint;\n readonly address: Address;\n readonly decimals: number;\n readonly symbol: string;\n}\n\n/** What a Service is asking to be paid, before any strategy is chosen. */\nexport interface ChargeRequest {\n readonly agent: Address;\n readonly serviceId: Bytes32;\n readonly asset: AssetRef;\n readonly amount: bigint;\n}\n\n/** A charge the strategy has been asked to pay. The surface resolves where the money goes. */\nexport type SettleRequest = ChargeRequest;\n\nexport interface ChargeQuote {\n readonly amount: bigint;\n readonly asset: AssetRef;\n readonly feeNote: string;\n}\n\n/**\n * What came back from a Settlement.\n *\n * `settlementId`, `applied` and `toPrepaid` are read from the `Settled` event in the\n * transaction receipt. They are `null` only when the signer could not wait for the\n * receipt, in which case the transaction hash still names the payment and the registry\n * will carry the figures once it indexes the block.\n */\nexport interface SettlementReceipt {\n readonly strategyId: string;\n readonly chainId: bigint;\n readonly txHash: Hex;\n readonly asset: AssetRef;\n readonly amount: bigint;\n readonly payer: Address;\n readonly serviceId: Bytes32;\n readonly settlementId: Bytes32 | null;\n readonly applied: bigint | null;\n readonly toPrepaid: bigint | null;\n readonly submittedAt: number;\n readonly batchIndex?: number;\n}\n\nexport interface PaymentStrategy {\n readonly id: string;\n /** The chain ids this strategy can settle on. */\n readonly chainIds: readonly bigint[];\n supports(asset: AssetRef): boolean;\n quote(request: ChargeRequest): Promise<Result<ChargeQuote>>;\n settle(request: SettleRequest): Promise<Result<SettlementReceipt>>;\n settleBatch?(requests: readonly SettleRequest[]): Promise<Result<readonly SettlementReceipt[]>>;\n}\n\n/** The registry key for an Asset: `<chainId>:<address>`, lower-cased. */\nexport const assetKey = (asset: AssetRef): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\nexport const sameAsset = (a: AssetRef, b: AssetRef): boolean => assetKey(a) === assetKey(b);\n\n/** A 20-byte address as a 32-byte topic. */\nexport const addressTopic = (address: Address): Bytes32 =>\n `0x${address.slice(2).toLowerCase().padStart(64, \"0\")}`;\n\nexport function supportsAsset(\n strategy: PaymentStrategy,\n asset: AssetRef,\n onThrow?: (error: unknown) => void,\n): boolean {\n try {\n return strategy.supports(asset) === true;\n } catch (error) {\n onThrow?.(error);\n return false;\n }\n}\n\nexport function validateAssetRef(value: unknown, label: string): Result<AssetRef> {\n if (typeof value !== \"object\" || value === null) {\n return validationError(\"ASSET_REF_INVALID\", `${label} must be an object describing one Asset`);\n }\n const candidate = value as Partial<AssetRef>;\n if (typeof candidate.chainId !== \"bigint\" || candidate.chainId <= 0n) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.chainId must be a positive bigint EVM chain id`);\n }\n if (!isAddress(candidate.address)) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.address must be a 20-byte 0x address`);\n }\n if (\n typeof candidate.decimals !== \"number\" ||\n !Number.isInteger(candidate.decimals) ||\n candidate.decimals < 0\n ) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.decimals must be a non-negative integer`);\n }\n if (typeof candidate.symbol !== \"string\" || candidate.symbol.length === 0) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.symbol must be a non-empty string`);\n }\n return ok(candidate as AssetRef);\n}\n\nexport function validatePaymentStrategy(value: unknown, label = \"strategy\"): Result<PaymentStrategy> {\n if (typeof value !== \"object\" || value === null) {\n return validationError(\"STRATEGY_INVALID\", `${label} must be an object implementing PaymentStrategy`);\n }\n const candidate = value as Partial<PaymentStrategy>;\n if (typeof candidate.id !== \"string\" || candidate.id.trim().length === 0) {\n return validationError(\"STRATEGY_INVALID\", `${label}.id must be a non-empty string`);\n }\n const id = candidate.id;\n if (!Array.isArray(candidate.chainIds) || candidate.chainIds.length === 0) {\n return validationError(\"STRATEGY_INVALID\", `${label} \\`${id}\\` must declare at least one chain id in chainIds`);\n }\n for (const chainId of candidate.chainIds) {\n if (typeof chainId !== \"bigint\") {\n return validationError(\n \"STRATEGY_INVALID\",\n `${label} \\`${id}\\` must declare every chain id as a bigint, received ${typeof chainId}`,\n );\n }\n }\n for (const method of [\"supports\", \"quote\", \"settle\"] as const) {\n if (typeof candidate[method] !== \"function\") {\n return validationError(\"STRATEGY_INVALID\", `${label} \\`${id}\\` must implement ${method}()`);\n }\n }\n if (candidate.settleBatch !== undefined && typeof candidate.settleBatch !== \"function\") {\n return validationError(\n \"STRATEGY_INVALID\",\n `${label} \\`${id}\\` declares settleBatch but it is not a function; leave it undefined when there is no batch form`,\n );\n }\n return ok(candidate as PaymentStrategy);\n}\n\nexport function validateChargeRequest(request: ChargeRequest): Result<ChargeRequest> {\n if (!isAddress(request.agent)) {\n return validationError(\"CHARGE_INVALID\", \"request.agent must be a 20-byte 0x address\");\n }\n if (!isBytes32(request.serviceId)) {\n return validationError(\"CHARGE_INVALID\", \"request.serviceId must be a 32-byte 0x word\");\n }\n const asset = validateAssetRef(request.asset, \"request.asset\");\n if (!asset.ok) return asset;\n if (typeof request.amount !== \"bigint\") {\n return validationError(\n \"CHARGE_INVALID\",\n \"request.amount must be a bigint count of Asset base units, never a number\",\n );\n }\n if (request.amount <= 0n) {\n return validationError(\"AMOUNT_NOT_POSITIVE\", \"request.amount must be greater than zero base units\");\n }\n if (request.amount > (1n << 128n) - 1n) {\n return validationError(\"AMOUNT_OUT_OF_RANGE\", \"request.amount must fit a uint128\");\n }\n return ok(request);\n}\n\nexport const validateSettleRequest = validateChargeRequest;\n"]}
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/payments/strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAqD,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AA4D/C,yEAAyE;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAe,EAAU,EAAE,CAClD,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAW,EAAE,CAAW,EAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE5F,4CAA4C;AAC5C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAgB,EAAW,EAAE,CACxD,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;AAE1D,MAAM,UAAU,aAAa,CAC3B,QAAyB,EACzB,KAAe,EACf,OAAkC;IAElC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,KAAa;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,eAAe,CAAC,mBAAmB,EAAE,GAAG,KAAK,yCAAyC,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,SAAS,GAAG,KAA0B,CAAC;IAC7C,IAAI,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,IAAI,SAAS,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACrE,OAAO,eAAe,CAAC,mBAAmB,EAAE,GAAG,KAAK,iDAAiD,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,eAAe,CAAC,mBAAmB,EAAE,GAAG,KAAK,uCAAuC,CAAC,CAAC;IAC/F,CAAC;IACD,IACE,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ;QACtC,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC;QACrC,SAAS,CAAC,QAAQ,GAAG,CAAC,EACtB,CAAC;QACD,OAAO,eAAe,CAAC,mBAAmB,EAAE,GAAG,KAAK,0CAA0C,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,OAAO,eAAe,CAAC,mBAAmB,EAAE,GAAG,KAAK,oCAAoC,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,EAAE,CAAC,SAAqB,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAc,EAAE,KAAK,GAAG,UAAU;IACxE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,eAAe,CAAC,kBAAkB,EAAE,GAAG,KAAK,iDAAiD,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,SAAS,GAAG,KAAiC,CAAC;IACpD,IAAI,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ,IAAI,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzE,OAAO,eAAe,CAAC,kBAAkB,EAAE,GAAG,KAAK,gCAAgC,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;IACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,OAAO,eAAe,CAAC,kBAAkB,EAAE,GAAG,KAAK,MAAM,EAAE,mDAAmD,CAAC,CAAC;IAClH,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;QACzC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,eAAe,CACpB,kBAAkB,EAClB,GAAG,KAAK,MAAM,EAAE,wDAAwD,OAAO,OAAO,EAAE,CACzF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAU,EAAE,CAAC;QAC9D,IAAI,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;YAC5C,OAAO,eAAe,CAAC,kBAAkB,EAAE,GAAG,KAAK,MAAM,EAAE,qBAAqB,MAAM,IAAI,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IACD,IAAI,SAAS,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QACvF,OAAO,eAAe,CACpB,kBAAkB,EAClB,GAAG,KAAK,MAAM,EAAE,kGAAkG,CACnH,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC,SAA4B,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAsB;IAC1D,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,eAAe,CAAC,gBAAgB,EAAE,4CAA4C,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,eAAe,CAAC,gBAAgB,EAAE,6CAA6C,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,eAAe,CACpB,gBAAgB,EAChB,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACzB,OAAO,eAAe,CAAC,qBAAqB,EAAE,qDAAqD,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACvC,OAAO,eAAe,CAAC,qBAAqB,EAAE,mCAAmC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAAC","sourcesContent":["/**\n * The payment-strategy seam.\n *\n * A strategy is how an Agent pays down an Open Tab. Every Settlement lands through\n * `TabSettlement`, which moves the Asset to the Service and applies the Settlement\n * in the same transaction, by one of two entry points: `settle`, sent by the Agent\n * after an approval (`createMonadStrategy`), or `settleWithPermit2`, signed by the\n * Agent and sent by a relayer (`createRelayedMonadStrategy`).\n * `createKuruFundedStrategy` wraps either one and swaps the Asset in first when\n * the Agent is short. The seam also lets a different signer, a smart account, a\n * session key, or a test double stand behind the same call without the SDK\n * caring which.\n *\n * ## What a strategy does not do\n *\n * It does not meter, it does not read tabs, and it does not decide amounts. It is\n * handed a fully specified charge and returns either a receipt or a typed error.\n * Every figure crossing this seam is a `bigint` count of Asset base units, never a\n * number and never a decimal string.\n */\nimport { isAddress, isBytes32, ok, type Address, type Bytes32, type Hex, type Result } from \"../_shared/index.js\";\nimport { validationError } from \"../errors.js\";\n\n/** One Asset a tab can be denominated in. `chainId` is the EVM chain id. */\nexport interface AssetRef {\n readonly chainId: bigint;\n readonly address: Address;\n readonly decimals: number;\n readonly symbol: string;\n}\n\n/** What a Service is asking to be paid, before any strategy is chosen. */\nexport interface ChargeRequest {\n readonly agent: Address;\n readonly serviceId: Bytes32;\n readonly asset: AssetRef;\n readonly amount: bigint;\n}\n\n/** A charge the strategy has been asked to pay. The surface resolves where the money goes. */\nexport type SettleRequest = ChargeRequest;\n\nexport interface ChargeQuote {\n readonly amount: bigint;\n readonly asset: AssetRef;\n readonly feeNote: string;\n}\n\n/**\n * What came back from a Settlement.\n *\n * `settlementId`, `applied` and `toPrepaid` are read from the `Settled` event in the\n * transaction receipt. They are `null` only when the signer could not wait for the\n * receipt, in which case the transaction hash still names the payment and the registry\n * will carry the figures once it indexes the block.\n */\nexport interface SettlementReceipt {\n readonly strategyId: string;\n readonly chainId: bigint;\n readonly txHash: Hex;\n readonly asset: AssetRef;\n readonly amount: bigint;\n readonly payer: Address;\n readonly serviceId: Bytes32;\n readonly settlementId: Bytes32 | null;\n readonly applied: bigint | null;\n readonly toPrepaid: bigint | null;\n readonly submittedAt: number;\n readonly batchIndex?: number;\n}\n\nexport interface PaymentStrategy {\n readonly id: string;\n /** The chain ids this strategy can settle on. */\n readonly chainIds: readonly bigint[];\n supports(asset: AssetRef): boolean;\n quote(request: ChargeRequest): Promise<Result<ChargeQuote>>;\n settle(request: SettleRequest): Promise<Result<SettlementReceipt>>;\n settleBatch?(requests: readonly SettleRequest[]): Promise<Result<readonly SettlementReceipt[]>>;\n}\n\n/** The registry key for an Asset: `<chainId>:<address>`, lower-cased. */\nexport const assetKey = (asset: AssetRef): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\nexport const sameAsset = (a: AssetRef, b: AssetRef): boolean => assetKey(a) === assetKey(b);\n\n/** A 20-byte address as a 32-byte topic. */\nexport const addressTopic = (address: Address): Bytes32 =>\n `0x${address.slice(2).toLowerCase().padStart(64, \"0\")}`;\n\nexport function supportsAsset(\n strategy: PaymentStrategy,\n asset: AssetRef,\n onThrow?: (error: unknown) => void,\n): boolean {\n try {\n return strategy.supports(asset) === true;\n } catch (error) {\n onThrow?.(error);\n return false;\n }\n}\n\nexport function validateAssetRef(value: unknown, label: string): Result<AssetRef> {\n if (typeof value !== \"object\" || value === null) {\n return validationError(\"ASSET_REF_INVALID\", `${label} must be an object describing one Asset`);\n }\n const candidate = value as Partial<AssetRef>;\n if (typeof candidate.chainId !== \"bigint\" || candidate.chainId <= 0n) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.chainId must be a positive bigint EVM chain id`);\n }\n if (!isAddress(candidate.address)) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.address must be a 20-byte 0x address`);\n }\n if (\n typeof candidate.decimals !== \"number\" ||\n !Number.isInteger(candidate.decimals) ||\n candidate.decimals < 0\n ) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.decimals must be a non-negative integer`);\n }\n if (typeof candidate.symbol !== \"string\" || candidate.symbol.length === 0) {\n return validationError(\"ASSET_REF_INVALID\", `${label}.symbol must be a non-empty string`);\n }\n return ok(candidate as AssetRef);\n}\n\nexport function validatePaymentStrategy(value: unknown, label = \"strategy\"): Result<PaymentStrategy> {\n if (typeof value !== \"object\" || value === null) {\n return validationError(\"STRATEGY_INVALID\", `${label} must be an object implementing PaymentStrategy`);\n }\n const candidate = value as Partial<PaymentStrategy>;\n if (typeof candidate.id !== \"string\" || candidate.id.trim().length === 0) {\n return validationError(\"STRATEGY_INVALID\", `${label}.id must be a non-empty string`);\n }\n const id = candidate.id;\n if (!Array.isArray(candidate.chainIds) || candidate.chainIds.length === 0) {\n return validationError(\"STRATEGY_INVALID\", `${label} \\`${id}\\` must declare at least one chain id in chainIds`);\n }\n for (const chainId of candidate.chainIds) {\n if (typeof chainId !== \"bigint\") {\n return validationError(\n \"STRATEGY_INVALID\",\n `${label} \\`${id}\\` must declare every chain id as a bigint, received ${typeof chainId}`,\n );\n }\n }\n for (const method of [\"supports\", \"quote\", \"settle\"] as const) {\n if (typeof candidate[method] !== \"function\") {\n return validationError(\"STRATEGY_INVALID\", `${label} \\`${id}\\` must implement ${method}()`);\n }\n }\n if (candidate.settleBatch !== undefined && typeof candidate.settleBatch !== \"function\") {\n return validationError(\n \"STRATEGY_INVALID\",\n `${label} \\`${id}\\` declares settleBatch but it is not a function; leave it undefined when there is no batch form`,\n );\n }\n return ok(candidate as PaymentStrategy);\n}\n\nexport function validateChargeRequest(request: ChargeRequest): Result<ChargeRequest> {\n if (!isAddress(request.agent)) {\n return validationError(\"CHARGE_INVALID\", \"request.agent must be a 20-byte 0x address\");\n }\n if (!isBytes32(request.serviceId)) {\n return validationError(\"CHARGE_INVALID\", \"request.serviceId must be a 32-byte 0x word\");\n }\n const asset = validateAssetRef(request.asset, \"request.asset\");\n if (!asset.ok) return asset;\n if (typeof request.amount !== \"bigint\") {\n return validationError(\n \"CHARGE_INVALID\",\n \"request.amount must be a bigint count of Asset base units, never a number\",\n );\n }\n if (request.amount <= 0n) {\n return validationError(\"AMOUNT_NOT_POSITIVE\", \"request.amount must be greater than zero base units\");\n }\n if (request.amount > (1n << 128n) - 1n) {\n return validationError(\"AMOUNT_OUT_OF_RANGE\", \"request.amount must fit a uint128\");\n }\n return ok(request);\n}\n\nexport const validateSettleRequest = validateChargeRequest;\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The hook seam of the proxy layer (R23.4).
2
+ * The hook seam of the proxy layer.
3
3
  *
4
4
  * A hook is a named pair of optional phases. `before` runs ahead of the proxied
5
5
  * request, in registration order; `after` runs once the response exists, in
@@ -24,12 +24,10 @@
24
24
  *
25
25
  * The context is one object per request, shared by both phases and every hook,
26
26
  * with two writable parts. `settlement` is where a hook that looked a Settlement
27
- * up on Monad attaches what it found (R23.5), and `state` is scratch a hook uses
27
+ * up on Monad attaches what it found, and `state` is scratch a hook uses
28
28
  * to hand something from its `before` to its `after` phase. A hook
29
29
  * cannot replace the request or the response through the context; only a
30
30
  * critical failure changes what goes out.
31
- *
32
- * Requirements: 23.4, 23.5
33
31
  */
34
32
  import type { Result } from "../_shared/index.js";
35
33
  import type { Logger } from "../logger.js";
@@ -68,7 +66,7 @@ export interface ProxyHookContext {
68
66
  readonly metering?: MeteringOutcome;
69
67
  /**
70
68
  * The Settlement attached to this request, if a hook found one.
71
- * Writable: attaching it is a lookup hook's job (R23.5).
69
+ * Writable: attaching it is a lookup hook's job.
72
70
  */
73
71
  settlement?: SettlementView;
74
72
  /** Scratch for the life of one request. Convention: keyed by hook name. */
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/proxy/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,KAAK,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/proxy/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,KAAK,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The hook seam of the proxy layer (R23.4).
2
+ * The hook seam of the proxy layer.
3
3
  *
4
4
  * A hook is a named pair of optional phases. `before` runs ahead of the proxied
5
5
  * request, in registration order; `after` runs once the response exists, in
@@ -24,12 +24,10 @@
24
24
  *
25
25
  * The context is one object per request, shared by both phases and every hook,
26
26
  * with two writable parts. `settlement` is where a hook that looked a Settlement
27
- * up on Monad attaches what it found (R23.5), and `state` is scratch a hook uses
27
+ * up on Monad attaches what it found, and `state` is scratch a hook uses
28
28
  * to hand something from its `before` to its `after` phase. A hook
29
29
  * cannot replace the request or the response through the context; only a
30
30
  * critical failure changes what goes out.
31
- *
32
- * Requirements: 23.4, 23.5
33
31
  */
34
32
  export {};
35
33
  //# sourceMappingURL=hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/proxy/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG","sourcesContent":["/**\n * The hook seam of the proxy layer (R23.4).\n *\n * A hook is a named pair of optional phases. `before` runs ahead of the proxied\n * request, in registration order; `after` runs once the response exists, in\n * reverse order, so the hook registered first is the last to see the response\n * on the way out. That is the same nesting a middleware stack has, expressed as\n * two lists rather than as recursion, because two lists are what a Service\n * reads back when it asks \"which hooks ran, and in what order\".\n *\n * ## A hook cannot fail a request unless it says so\n *\n * Every phase returns a `Result`. An `err` is logged with the hook's name and\n * the phase, and the request carries on. That is the default because a hook is\n * observation: it logs, it annotates, it looks something up. A Service whose\n * log shipper is down should still deliver work. The one exception is a hook\n * that declares `critical: true`, whose `err` replaces the response with the\n * error it returned, at the HTTP status its category maps to. A hook that\n * *throws* is treated exactly as one that returned an `INTERNAL` error, so the\n * distinction between \"misbehaved\" and \"reported a problem\" is the `critical`\n * flag and never the control flow.\n *\n * ## What a hook can see and what it can change\n *\n * The context is one object per request, shared by both phases and every hook,\n * with two writable parts. `settlement` is where a hook that looked a Settlement\n * up on Monad attaches what it found (R23.5), and `state` is scratch a hook uses\n * to hand something from its `before` to its `after` phase. A hook\n * cannot replace the request or the response through the context; only a\n * critical failure changes what goes out.\n *\n * Requirements: 23.4, 23.5\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { MeteredCharge, MeteringOutcome } from \"../server/post-paid.js\";\nimport type { Address, Bytes32, Hex } from \"../_shared/index.js\";\n\n/**\n * A Settlement as a hook may attach it to a request: the figures `TabBook`\n * recorded and the Monad transaction that carried them.\n */\nexport interface SettlementView {\n readonly settlementId: Bytes32;\n readonly txHash: Hex;\n readonly agent: Address;\n readonly serviceId: Bytes32;\n readonly asset: Address;\n readonly amount: bigint;\n readonly applied: bigint;\n readonly toPrepaid: bigint;\n readonly blockNumber?: number;\n}\n\nexport type ProxyPhase = \"before\" | \"after\";\n\nexport interface ProxyHookContext {\n readonly phase: ProxyPhase;\n /** The request as it reached the proxy, before any header was dropped for forwarding. */\n readonly request: Request;\n /** The response about to be returned. Present in the `after` phase only. */\n readonly response?: Response;\n /**\n * The delivery the metering plugin recorded for this request, when it recorded\n * one. Absent when the request was not metered, when metering refused it, and\n * under `release: \"before-metering\"`, where the recording is still pending\n * while the hooks run.\n */\n readonly charge?: MeteredCharge;\n /** The metering outcome in full, present whenever the plugin reached one before the hooks ran. */\n readonly metering?: MeteringOutcome;\n /**\n * The Settlement attached to this request, if a hook found one.\n * Writable: attaching it is a lookup hook's job (R23.5).\n */\n settlement?: SettlementView;\n /** Scratch for the life of one request. Convention: keyed by hook name. */\n readonly state: Map<string, unknown>;\n readonly logger: Logger;\n}\n\nexport interface ProxyHook {\n /** Names the hook in logs and in `state`. Unique within one proxy. */\n readonly name: string;\n /**\n * When true, an `err` from either phase fails the request with that error.\n * Defaults to false: a hook observes, and observation failing is not a reason\n * to withhold delivered work.\n */\n readonly critical?: boolean;\n before?(context: ProxyHookContext): Promise<Result<void>>;\n after?(context: ProxyHookContext): Promise<Result<void>>;\n}\n"]}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/proxy/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG","sourcesContent":["/**\n * The hook seam of the proxy layer.\n *\n * A hook is a named pair of optional phases. `before` runs ahead of the proxied\n * request, in registration order; `after` runs once the response exists, in\n * reverse order, so the hook registered first is the last to see the response\n * on the way out. That is the same nesting a middleware stack has, expressed as\n * two lists rather than as recursion, because two lists are what a Service\n * reads back when it asks \"which hooks ran, and in what order\".\n *\n * ## A hook cannot fail a request unless it says so\n *\n * Every phase returns a `Result`. An `err` is logged with the hook's name and\n * the phase, and the request carries on. That is the default because a hook is\n * observation: it logs, it annotates, it looks something up. A Service whose\n * log shipper is down should still deliver work. The one exception is a hook\n * that declares `critical: true`, whose `err` replaces the response with the\n * error it returned, at the HTTP status its category maps to. A hook that\n * *throws* is treated exactly as one that returned an `INTERNAL` error, so the\n * distinction between \"misbehaved\" and \"reported a problem\" is the `critical`\n * flag and never the control flow.\n *\n * ## What a hook can see and what it can change\n *\n * The context is one object per request, shared by both phases and every hook,\n * with two writable parts. `settlement` is where a hook that looked a Settlement\n * up on Monad attaches what it found, and `state` is scratch a hook uses\n * to hand something from its `before` to its `after` phase. A hook\n * cannot replace the request or the response through the context; only a\n * critical failure changes what goes out.\n */\n\nimport type { Result } from \"../_shared/index.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { MeteredCharge, MeteringOutcome } from \"../server/post-paid.js\";\nimport type { Address, Bytes32, Hex } from \"../_shared/index.js\";\n\n/**\n * A Settlement as a hook may attach it to a request: the figures `TabBook`\n * recorded and the Monad transaction that carried them.\n */\nexport interface SettlementView {\n readonly settlementId: Bytes32;\n readonly txHash: Hex;\n readonly agent: Address;\n readonly serviceId: Bytes32;\n readonly asset: Address;\n readonly amount: bigint;\n readonly applied: bigint;\n readonly toPrepaid: bigint;\n readonly blockNumber?: number;\n}\n\nexport type ProxyPhase = \"before\" | \"after\";\n\nexport interface ProxyHookContext {\n readonly phase: ProxyPhase;\n /** The request as it reached the proxy, before any header was dropped for forwarding. */\n readonly request: Request;\n /** The response about to be returned. Present in the `after` phase only. */\n readonly response?: Response;\n /**\n * The delivery the metering plugin recorded for this request, when it recorded\n * one. Absent when the request was not metered, when metering refused it, and\n * under `release: \"before-metering\"`, where the recording is still pending\n * while the hooks run.\n */\n readonly charge?: MeteredCharge;\n /** The metering outcome in full, present whenever the plugin reached one before the hooks ran. */\n readonly metering?: MeteringOutcome;\n /**\n * The Settlement attached to this request, if a hook found one.\n * Writable: attaching it is a lookup hook's job.\n */\n settlement?: SettlementView;\n /** Scratch for the life of one request. Convention: keyed by hook name. */\n readonly state: Map<string, unknown>;\n readonly logger: Logger;\n}\n\nexport interface ProxyHook {\n /** Names the hook in logs and in `state`. Unique within one proxy. */\n readonly name: string;\n /**\n * When true, an `err` from either phase fails the request with that error.\n * Defaults to false: a hook observes, and observation failing is not a reason\n * to withhold delivered work.\n */\n readonly critical?: boolean;\n before?(context: ProxyHookContext): Promise<Result<void>>;\n after?(context: ProxyHookContext): Promise<Result<void>>;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * The proxy layer: hooks around a forwarded, metered request (R23.4), with a
3
- * seam for attaching the Settlement that covers it (R23.5).
2
+ * The proxy layer: hooks around a forwarded, metered request, with a
3
+ * seam for attaching the Settlement that covers it.
4
4
  *
5
5
  * `hooks.ts` is the seam and `proxy.ts` the handler.
6
6
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
- * The proxy layer: hooks around a forwarded, metered request (R23.4), with a
3
- * seam for attaching the Settlement that covers it (R23.5).
2
+ * The proxy layer: hooks around a forwarded, metered request, with a
3
+ * seam for attaching the Settlement that covers it.
4
4
  *
5
5
  * `hooks.ts` is the seam and `proxy.ts` the handler.
6
6
  */