@adcp/sdk 14.0.0-beta.0 → 14.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/get-account-financials-request.json +610 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/get-account-financials-response.json +1055 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/list-accounts-request.json +629 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/list-accounts-response.json +1558 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/report-usage-request.json +702 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/report-usage-response.json +309 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/sync-accounts-request.json +1113 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/sync-accounts-response.json +1567 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/sync-governance-request.json +662 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/account/sync-governance-response.json +921 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/creative/list-creatives-request.json +992 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/creative/list-creatives-response.json +5965 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/creative/sync-creatives-request.json +3936 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/creative/sync-creatives-response.json +3859 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/manifest.json +206 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/accept-proposal-request.json +601 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/accept-proposal-response.json +4799 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/buy-products-request.json +4107 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/buy-products-response.json +4799 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/control-media-buy-request.json +3365 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/control-media-buy-response.json +656 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/decline-proposals-request.json +334 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/decline-proposals-response.json +271 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/get-media-buy-delivery-request.json +1236 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/get-media-buy-delivery-response.json +2861 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/get-media-buys-request.json +678 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/get-media-buys-response.json +10861 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/list-products-request.json +4229 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/list-products-response.json +3824 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/log-event-request.json +421 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/log-event-response.json +394 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/media-buy-delivery-webhook-result.json +1366 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/provide-performance-feedback-request.json +884 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/provide-performance-feedback-response.json +422 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/refine-proposals-request.json +4335 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/refine-proposals-response.json +7328 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/request-proposals-request.json +4307 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/request-proposals-response.json +7105 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-audiences-request.json +760 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-audiences-response.json +541 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-catalogs-request.json +1142 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-catalogs-response.json +1153 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-event-sources-request.json +743 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/media-buy/sync-event-sources-response.json +619 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/account/get-account-financials-request.json +544 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/account/list-accounts-request.json +557 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/account/report-usage-request.json +617 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/account/sync-accounts-request.json +984 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/account/sync-governance-request.json +581 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/creative/list-creatives-request.json +878 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/creative/sync-creatives-request.json +3456 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/manifest.json +175 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/accept-proposal-request.json +498 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/buy-products-request.json +3675 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/control-media-buy-request.json +3030 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/decline-proposals-request.json +282 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/get-media-buy-delivery-request.json +1136 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/get-media-buys-request.json +597 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/list-products-request.json +3780 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/log-event-request.json +386 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/provide-performance-feedback-request.json +784 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/refine-proposals-request.json +3878 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/request-proposals-request.json +3852 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/sync-audiences-request.json +682 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/sync-catalogs-request.json +1016 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/media-buy/sync-event-sources-request.json +660 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/protocol/get-adcp-capabilities-request.json +51 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/protocol/get-task-status-request.json +534 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/protocol/list-tasks-request.json +692 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/model-context/protocol/sync-agent-notification-configs-request.json +129 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/get-adcp-capabilities-request.json +58 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/get-adcp-capabilities-response.json +8069 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/get-task-status-request.json +601 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/get-task-status-response.json +612 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/list-tasks-request.json +775 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/list-tasks-response.json +483 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/sync-agent-notification-configs-request.json +155 -0
- package/dist/lib/schemas-data/3.2.0-beta.0/mcp/2026-07-28/profiles/media-buy/protocol/sync-agent-notification-configs-response.json +382 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +27 -0
- package/dist/lib/server/create-adcp-server.d.ts +27 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +120 -4
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +121 -6
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/context.d.mts +6 -0
- package/dist/lib/server/decisioning/context.d.ts +6 -0
- package/dist/lib/server/decisioning/context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/context.js.map +1 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -1
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/platform.d.mts +21 -6
- package/dist/lib/server/decisioning/platform.d.ts +21 -6
- package/dist/lib/server/decisioning/platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +201 -18
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +203 -19
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +6 -0
- package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.mjs +6 -0
- package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.js +35 -4
- package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs +35 -4
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +39 -0
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +39 -0
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/validation/schema-loader.d.mts +2 -0
- package/dist/lib/validation/schema-loader.d.ts +2 -0
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +31 -0
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +30 -0
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/guides/BUILD-AN-AGENT.md +10 -1
- package/docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md +119 -0
- package/docs/llms.txt +1 -1
- package/docs/migration-12-to-14.md +8 -0
- package/docs/migration-13-to-14.md +30 -4
- package/docs/releases/14.0.0-beta.0.md +19 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/specialisms/sales.ts"],"sourcesContent":["/**\n * SalesPlatform — sales specialism platform interface.\n *\n * **Unified hybrid shape.** `get_products`, `create_media_buy`, and `sync_creatives` use a\n * single method each. The method returns the wire success arm (sync fast\n * path) OR `ctx.handoffToTask(fn)` to promote the call to a background\n * task (HITL slow path). Branch per-call — the same method handles\n * programmatic remnant, guaranteed inventory, curated discovery, and hybrid\n * sellers. Every other tool is sync-only:\n *\n * - `get_products` — sync OR `ctx.handoffToTask(...)` for curated brief/refine flows.\n * - `create_media_buy` — sync OR `ctx.handoffToTask(...)`.\n * - `update_media_buy` — sync only. Re-approval flows that need HITL run\n * out-of-band; `publishStatusChange` carries the result.\n * - `sync_creatives` — sync OR `ctx.handoffToTask(...)`.\n * - `get_media_buy_delivery` — sync only.\n *\n * Sync-only tools that need long-running semantics use `publishStatusChange`\n * (see `status-changes.ts`) — that's the spec-aligned channel for tools\n * whose wire response unions don't define a Submitted arm.\n *\n * Each method either returns the value or throws `AdcpError` for structured\n * rejection. Generic thrown errors map to `SERVICE_UNAVAILABLE`.\n *\n * **Method groups** — implement the group(s) matching your specialism:\n *\n * | Group | Methods | Claim when |\n * |---|---|---|\n * | Core sales (required) | `getProducts`, `updateMediaBuy`, `getMediaBuyDelivery` | Any `sales-*` specialism |\n * | Core sales (unified hybrid) | `createMediaBuy` | Any `sales-*` specialism |\n * | Core sales (unified hybrid) | `syncCreatives` | Any `sales-*` specialism |\n * | Read / feedback | `getMediaBuys`, `providePerformanceFeedback`, `listCreativeFormats`, `listCreatives` | Most sellers; optional |\n * | Retail-media extensions | `syncCatalogs`, `logEvent`, `syncEventSources` | `sales-catalog-driven`, `sales-retail-media` |\n *\n * New adopters implementing a non-retail seller (GAM, FreeWheel, a social\n * platform) only need the three core-required methods plus `createMediaBuy`\n * and `syncCreatives`. The retail-media extension methods (`syncCatalogs`,\n * `logEvent`, `syncEventSources`) are unnecessary unless you claim\n * `sales-catalog-driven` or `sales-retail-media`.\n *\n * **No-account tools (`providePerformanceFeedback`, `listCreativeFormats`):**\n * the wire requests for these two tools don't carry an `account` field, so\n * `ctx.account` may be `undefined` when `accounts.resolution === 'explicit'`.\n * Three safe patterns:\n *\n * 1. **`'derived'` resolution** — `accounts.resolve(undefined)` returns a\n * singleton; `ctx.account` is always set. Best for single-tenant\n * deployers.\n * 2. **Don't implement the method** — the framework returns\n * `UNSUPPORTED_FEATURE`; buyers using the merge-seam custom handler or\n * external creative agents still receive a response.\n * 3. **Explicit-mode with defensive read** — cast `ctx.account as Account |\n * undefined` and derive the account from the request body (e.g., via a\n * `media_buy_id` lookup), or throw `AdcpError('ACCOUNT_NOT_FOUND')`.\n * Full `resolveAccount(undefined, { authInfo, toolName })` support for\n * explicit-mode lands in rc.1.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport type { Account, NoAccountCtx } from '../account';\nimport type { RequestContext } from '../context';\nimport type { TaskHandoff } from '../async-outcome';\nimport type { RequireCacheScopeWhenProducts, ServerPayload } from '../../../types/server-payload';\nimport type {\n GetProductsRequest,\n GetProductsResponse,\n CreateMediaBuyError,\n CreateMediaBuySuccess,\n UpdateMediaBuySuccess,\n GetMediaBuysRequest,\n GetMediaBuysResponse,\n GetMediaBuyDeliveryRequest,\n GetMediaBuyDeliveryResponse,\n ProvidePerformanceFeedbackRequest,\n ProvidePerformanceFeedbackSuccess,\n ListCreativeFormatsRequest,\n ListCreativeFormatsResponse,\n ListCreativesRequest,\n ListCreativesResponse,\n MediaBuyStatus,\n SyncCatalogsRequest,\n SyncCatalogsSuccess,\n LogEventRequest,\n LogEventSuccess,\n SyncEventSourcesRequest,\n SyncEventSourcesSuccess,\n SyncCreativesError,\n SyncCreativesSuccess,\n} from '../../../types/tools.generated';\nimport type {\n CanonicalSyncCreativeAsset,\n CanonicalCreateMediaBuyRequest,\n CanonicalCreativeResponse,\n CanonicalGetProductsRequest,\n CanonicalListCreativesRequest,\n CanonicalListCreativesResponse,\n CanonicalProduct,\n CanonicalUpdateMediaBuyRequest,\n} from '../../../v2/projection/creative-delivery';\n\ntype SyncCreative = CanonicalSyncCreativeAsset;\ntype Ctx<TCtxMeta> = RequestContext<Account<TCtxMeta>>;\ntype ExclusivePayload<TLeft, TRight> =\n | (TLeft & { [K in Exclude<keyof TRight, keyof TLeft>]?: never })\n | (TRight & { [K in Exclude<keyof TLeft, keyof TRight>]?: never });\ntype LegacyMediaBuyStatusInput<T> = T & { status?: MediaBuyStatus };\n\ntype CanonicalGetProductsPayload = Omit<ServerPayload<CanonicalCreativeResponse<GetProductsResponse>>, 'products'> & {\n products?: CanonicalProduct[];\n};\nexport type GetProductsPayload = RequireCacheScopeWhenProducts<CanonicalGetProductsPayload>;\ntype CreateMediaBuySuccessPayload = LegacyMediaBuyStatusInput<\n ServerPayload<CanonicalCreativeResponse<CreateMediaBuySuccess>>\n>;\ntype CreateMediaBuyErrorPayload = ServerPayload<CanonicalCreativeResponse<CreateMediaBuyError>>;\nexport type CreateMediaBuyPayload = ExclusivePayload<CreateMediaBuySuccessPayload, CreateMediaBuyErrorPayload>;\nexport type UpdateMediaBuyPayload = LegacyMediaBuyStatusInput<\n ServerPayload<CanonicalCreativeResponse<UpdateMediaBuySuccess>>\n>;\nexport type GetMediaBuyDeliveryPayload = ServerPayload<CanonicalCreativeResponse<GetMediaBuyDeliveryResponse>>;\nexport type GetMediaBuysPayload = ServerPayload<CanonicalCreativeResponse<GetMediaBuysResponse>>;\nexport type ProvidePerformanceFeedbackPayload = ServerPayload<ProvidePerformanceFeedbackSuccess>;\nexport type LegacyListCreativeFormatsPayload = ServerPayload<ListCreativeFormatsResponse>;\nexport type ListCreativesPayload = ServerPayload<CanonicalListCreativesResponse>;\nexport type LegacyGetProductsPayload = RequireCacheScopeWhenProducts<ServerPayload<GetProductsResponse>>;\nexport type LegacyCreateMediaBuyPayload = ExclusivePayload<\n LegacyMediaBuyStatusInput<ServerPayload<CreateMediaBuySuccess>>,\n ServerPayload<CreateMediaBuyError>\n>;\nexport type LegacyUpdateMediaBuyPayload = LegacyMediaBuyStatusInput<ServerPayload<UpdateMediaBuySuccess>>;\nexport type LegacyGetMediaBuyDeliveryPayload = ServerPayload<GetMediaBuyDeliveryResponse>;\nexport type LegacyGetMediaBuysPayload = ServerPayload<GetMediaBuysResponse>;\nexport type LegacyListCreativesPayload = ServerPayload<ListCreativesResponse>;\nexport type SyncCreativesSuccessPayload = ServerPayload<SyncCreativesSuccess>;\nexport type SyncCreativesErrorPayload = ServerPayload<SyncCreativesError>;\nexport type SyncCreativesPayload = SyncCreativesSuccessPayload | SyncCreativesErrorPayload;\nexport type SyncCatalogsPayload = ServerPayload<SyncCatalogsSuccess>;\nexport type LogEventPayload = ServerPayload<LogEventSuccess>;\nexport type SyncEventSourcesPayload = ServerPayload<SyncEventSourcesSuccess>;\n\n/**\n * Wire success-row shape for `sync_creatives`. Returning the array of these\n * rows from `syncCreatives` is what adopters write — the framework wraps\n * with `{ creatives: [...] }` to form `SyncCreativesSuccess`.\n */\nexport type SyncCreativesRow = SyncCreativesSuccess['creatives'][number];\nexport type GetProductsHandlerResult = GetProductsPayload | TaskHandoff<GetProductsPayload>;\nexport type CreateMediaBuyHandlerResult = CreateMediaBuyPayload | TaskHandoff<CreateMediaBuySuccessPayload>;\nexport type UpdateMediaBuyHandlerResult = UpdateMediaBuyPayload | TaskHandoff<UpdateMediaBuyPayload>;\nexport type SyncCreativesHandlerResult = SyncCreativesRow[] | TaskHandoff<SyncCreativesRow[]>;\n\nexport interface SalesPlatform<TCtxMeta = Record<string, unknown>> {\n // **Method shape — all optional, enforced per-specialism.** Every method on\n // `SalesPlatform` is declared optional so the type accommodates non-media-\n // buy walled gardens (sales-social, audience-sync, sales-proposal-mode)\n // that don't accept inbound media buys but compose ingestion methods on\n // this same surface. Compile-time enforcement of \"you claimed\n // sales-non-guaranteed, therefore you MUST implement getProducts /\n // createMediaBuy / updateMediaBuy / getMediaBuyDelivery / getMediaBuys\"\n // moves up to `RequiredPlatformsFor<S>` — see the {@link SalesCorePlatform}\n // type alias and the per-specialism mapping in `platform.ts`. Runtime\n // enforcement is preserved: the dispatcher returns `UNSUPPORTED_FEATURE`\n // for tools whose method is absent, and `validateSpecialismRequiredTools`\n // throws / warns when a specialism's required tools aren't implemented.\n //\n // Adopters who implement the full media-buy surface keep working — their\n // implementation is a superset of every per-specialism requirement.\n // Adopters who only do ingestion (e.g. a Meta CAPI integration claiming\n // `sales-social`) drop the 5 core stubs without compile errors.\n\n // ── get_products: unified hybrid shape ────────────────────────────\n // get_products is a CATALOG LOOKUP — fast read against the seller's\n // existing inventory. rc8 allows curated brief/refine lookups to return a\n // Submitted arm when the seller needs async enrichment. Adopters express\n // that by returning ctx.handoffToTask(fn); the framework owns task_id\n // allocation, polling state, and optional completion webhook delivery.\n //\n // Wholesale catalog dumps remain sync: if the seller cannot serve the\n // full catalog directly, it should maintain an internal cache and return\n // the current catalog view instead of turning wholesale discovery into a\n // long-running operation.\n /** Catalog discovery: return products directly or hand off curated discovery to a background task. */\n getProducts?(req: CanonicalGetProductsRequest, ctx: Ctx<TCtxMeta>): Promise<GetProductsHandlerResult>;\n\n // ── create_media_buy: unified hybrid shape ──────────────────────────\n\n /**\n * Create a media buy. Return the wire success-arm shape (sync fast path)\n * OR `ctx.handoffToTask(fn)` to promote the call to a background task\n * (HITL slow path). Adopters can branch per-call: hybrid sellers route\n * programmatic remnant sync, guaranteed inventory through HITL, all\n * from the same method.\n *\n * Buyers pattern-match on the wire response shape (`media_buy_id` on\n * the immediate response → sync; `task_id` + `status: 'submitted'` →\n * poll `tasks_get` or receive webhook). Predictable per request,\n * dynamic per call.\n *\n * Status changes flow via `publishStatusChange(...)` regardless of\n * which path was taken.\n *\n * For synchronous domain validation that produces multiple failures,\n * return the pure Error arm (`{ errors: [...] }`) with no success-only\n * fields. Handoff callbacks remain success-only; throw `AdcpError` inside\n * a handoff to transition the task to `failed`.\n *\n * The handoff function's return value is persisted as JSONB in the\n * task registry. Postgres-backed registries cap row size at 4MB —\n * offload large payloads to blob storage and return references.\n *\n * @example Sync-only adopter (no HITL inventory)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * return await this.commitSync(req);\n * }\n * ```\n *\n * @example HITL-only adopter (every call goes through trafficker review)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * return ctx.handoffToTask(async (taskCtx) => {\n * await taskCtx.update({ message: 'Awaiting trafficker' });\n * return await this.runHITL(req);\n * });\n * }\n * ```\n *\n * @example Hybrid adopter (programmatic + guaranteed in same tenant)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * if (this.requiresHITL(req)) {\n * return ctx.handoffToTask(async (taskCtx) => await this.runHITL(req));\n * }\n * return await this.commitSync(req);\n * }\n * ```\n */\n createMediaBuy?(req: CanonicalCreateMediaBuyRequest, ctx: Ctx<TCtxMeta>): Promise<CreateMediaBuyHandlerResult>;\n\n // ── update_media_buy: unified hybrid shape\n /**\n * Update a media buy. Return the patched buy immediately (sync fast path)\n * OR `ctx.handoffToTask(fn)` when the upstream activation or approval flow\n * must continue in the background. The framework owns task registration,\n * caller scoping, polling, and completion webhooks on the handoff path.\n */\n updateMediaBuy?(\n buyId: string,\n patch: CanonicalUpdateMediaBuyRequest,\n ctx: Ctx<TCtxMeta>\n ): Promise<UpdateMediaBuyHandlerResult>;\n\n // ── sync_creatives: unified hybrid shape ────────────────────────────\n\n /**\n * Push creatives. Return the array of wire success rows (sync fast\n * path) OR `ctx.handoffToTask(fn)` to defer to a background task\n * (HITL slow path — manual review, brand-suitability gates, etc.).\n * Hybrid: branch per-batch — auto-approve simple creatives sync,\n * route everything else to HITL.\n *\n * Each row carries `action` (CRUD outcome) and optional `status`\n * (review state). Buyers see mixed `approved` / `pending_review`\n * rows on the sync path; subsequent review changes flow via\n * `publishStatusChange(...)`.\n *\n * @example Hybrid adopter\n * ```ts\n * syncCreatives: async (creatives, ctx) => {\n * if (creatives.some(c => this.needsReview(c))) {\n * return ctx.handoffToTask(async (taskCtx) => {\n * return await this.reviewAndPersist(creatives);\n * });\n * }\n * return creatives.map(c => ({ creative_id: c.creative_id, action: 'created', status: 'approved' }));\n * }\n * ```\n */\n syncCreatives?(creatives: SyncCreative[], ctx: Ctx<TCtxMeta>): Promise<SyncCreativesHandlerResult>;\n\n // ── get_media_buy_delivery: sync only ───────────────────────────────\n\n /**\n * Per-media-buy delivery actuals (impressions, spend, pacing,\n * conversions). Sync — report-running platforms with manual report\n * cycles return the latest cached actuals and emit `delivery_report`\n * status changes via `publishStatusChange` when fresh reports are\n * available.\n *\n * **Multi-id contract.** `filter.media_buy_ids` is an array — buyers\n * routinely request delivery for multiple buys in one call. The\n * platform MUST iterate every id and return one element per id in\n * `media_buy_deliveries[]`. Implementations that read only\n * `media_buy_ids[0]` silently truncate the buyer's request — a\n * correctness bug that has bitten multiple adopters (closes #1342).\n *\n * Pass-through is the framework contract: the platform owns fan-out\n * because `aggregated_totals` requires platform-domain knowledge —\n * `reach` (cross-buy dedup capability), `new_to_brand_rate` (weighted\n * across buys, not a per-buy average), and `frequency` (depends on\n * dedup) cannot be synthesized correctly by a naive framework loop.\n * Sellers that can't compute the cross-buy fields omit them and emit\n * the safely-summable fields (`impressions`, `spend`, `clicks`,\n * `media_buy_count`); buyers fall back to per-buy values when needed.\n *\n * Recommended pattern — prefer the upstream's native multi-id query\n * over a per-id loop. Most reporting APIs (GAM ReportService's\n * `WHERE LINE_ITEM_ID IN (...)`, TTD, DV360, Magnite, PubMatic, retail\n * media) take an id list in one round-trip; iterating one-id-at-a-time\n * is an N-roundtrip pattern that triggers upstream rate limits on\n * 50-buy reports.\n *\n * ```ts\n * getMediaBuyDelivery: async (req, ctx) => {\n * const ids = req.media_buy_ids ?? [];\n * // Native multi-id: one upstream round-trip.\n * const rows = await this.upstream.report({\n * mediaBuyIds: ids,\n * start: req.start_date,\n * end: req.end_date,\n * });\n * return {\n * reporting_period: { start, end },\n * currency: 'USD',\n * media_buy_deliveries: rows,\n * aggregated_totals: this.upstream.aggregate(rows),\n * };\n * }\n * ```\n *\n * **Single-id fallback** — only if your upstream is genuinely single-id:\n *\n * ```ts\n * const deliveries = await Promise.all(ids.map(id => fetchOne(id, ctx)));\n * ```\n *\n * When `media_buy_ids` is omitted, return a paginated set of\n * accessible media buys per the wire schema. `status_filter`\n * defaults to `['active']` when omitted; honor the filter in your\n * iteration.\n */\n getMediaBuyDelivery?(filter: GetMediaBuyDeliveryRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuyDeliveryPayload>;\n\n // ── get_media_buys: sync only — REQUIRED ──────────────────────────────\n // Read tool — buyers fetch a list of their media buys (often filtered by\n // status / time window). Required because:\n // 1. Every seller needs to support reading back what they created.\n // 2. Idempotent retries depend on it (replay safe-by-design).\n // 3. The 6.2 patch-decomposition redesign needs single-id reads;\n // `getMediaBuys` is the foundation.\n // 4. Framework auto-stores returned media buys for hydration on\n // subsequent updateMediaBuy calls (see `hydratePackagesWithProducts`\n // pattern in `from-platform.ts`).\n //\n // Proposal-mode adopters (write-only via push channels) return an empty\n // `media_buys: []` array — that's a valid response.\n /**\n * List media buys this account owns. Filter + pagination per the wire shape.\n *\n * **Multi-id contract.** `req.media_buy_ids` is an array — buyers\n * routinely request a specific set of buys in one call. The platform\n * MUST iterate every id and return one element per id in the response\n * `media_buys[]` array. Reading only `media_buy_ids[0]` silently\n * truncates the buyer's request — same correctness bug that #1342\n * documented for `getMediaBuyDelivery`. Same recommended pattern: prefer\n * an upstream multi-id query (one round-trip), fall back to per-id loop\n * only when the upstream is single-id-only.\n *\n * When `media_buy_ids` is omitted, return a paginated set of accessible\n * buys filtered by `status_filter` (defaults to `['active']`).\n */\n getMediaBuys?(req: GetMediaBuysRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuysPayload>;\n\n // ── provide_performance_feedback: sync only ─────────────────────────\n // Write tool — buyers report aggregate creative-level performance\n // (impressions, clicks, conversions) to help the seller's optimizer learn.\n // Optional because not every sales agent runs an optimizer, but every\n // buyer expects to be able to call it. Framework returns UNSUPPORTED_FEATURE\n // when omitted.\n //\n // ⚠️ NO-ACCOUNT TOOL — `ctx: NoAccountCtx<TCtxMeta>`. The wire request\n // does not carry an `account` field. `ctx.account` may be `undefined` for\n // `'explicit'`-resolution adopters; narrow before reading\n // `ctx.account.ctx_metadata`. See {@link NoAccountCtx} and the\n // `SalesPlatform` JSDoc (\"No-account tools\") for safe patterns.\n /** Accept buyer-side performance signals on a media buy / creative. */\n providePerformanceFeedback?(\n req: ProvidePerformanceFeedbackRequest,\n ctx: NoAccountCtx<TCtxMeta>\n ): Promise<ProvidePerformanceFeedbackPayload>;\n\n // ── list_creative_formats: sync only ────────────────────────────────\n // Discovery tool — buyers query what creative formats this seller\n // accepts. Optional because sellers that delegate to external\n // `creative_agents` (declared in `capabilities.creative_agents[]`) don't\n // own format definitions; framework can resolve from the declared agents.\n // Self-hosted sellers (own creative library) implement this directly.\n //\n // ⚠️ NO-ACCOUNT TOOL — `ctx: NoAccountCtx<TCtxMeta>`. See\n // `providePerformanceFeedback` note above.\n listCreativeFormatsLegacy?(\n req: ListCreativeFormatsRequest,\n ctx: NoAccountCtx<TCtxMeta>\n ): Promise<LegacyListCreativeFormatsPayload>;\n\n // ── list_creatives: sync only ───────────────────────────────────────\n // Read tool — buyers query the seller's creative library. Optional\n // because most sales adopters delegate creative state to the\n // `creative_agents` declared in capabilities; ad-server-style sales\n // platforms implement directly. Note: also lives on `CreativeAdServerPlatform.listCreatives`\n // for the standalone-creative-agent shape.\n listCreatives?(req: CanonicalListCreativesRequest, ctx: Ctx<TCtxMeta>): Promise<ListCreativesPayload>;\n\n // ── sync_catalogs: sync only ────────────────────────────────────────\n // Retail-media catalog sync. Buyers push product catalogs (SKUs, ASINs,\n // store-ids) for `sales-catalog-driven` agents (Amazon, Criteo, Citrusad,\n // Walmart Connect, Shopify ad surfaces). Optional — non-retail sales\n // adopters omit. Idempotent on the buyer's `idempotency_key`.\n syncCatalogs?(req: SyncCatalogsRequest, ctx: Ctx<TCtxMeta>): Promise<SyncCatalogsPayload>;\n\n // ── log_event: sync only ────────────────────────────────────────────\n // Conversion / engagement event logging. Buyers post events tied to\n // a `media_buy_id` for performance attribution. Used by retail-media\n // (post-purchase events) and conversion-tracked sales (Snap pixel,\n // Meta CAPI, LinkedIn conversions API). Optional.\n logEvent?(req: LogEventRequest, ctx: Ctx<TCtxMeta>): Promise<LogEventPayload>;\n\n // ── sync_event_sources: sync only ──────────────────────────────────\n // Register conversion event sources (websites, apps, offline pixel\n // IDs) so subsequent `log_event` calls can be attributed correctly.\n // Optional — adopters who don't expose conversion tracking omit.\n syncEventSources?(req: SyncEventSourcesRequest, ctx: Ctx<TCtxMeta>): Promise<SyncEventSourcesPayload>;\n}\n\n/**\n * Names the **core sales surface** — bidding + media-buy lifecycle. Required\n * for `sales-*` specialisms that own pricing/pacing\n * (`sales-non-guaranteed`, `sales-guaranteed`, `sales-broadcast-tv`,\n * `sales-streaming-tv`, `sales-exchange`, `sales-catalog-driven`,\n * `sales-retail-media`).\n *\n * Walled-garden specialisms whose value surface is asset ingestion\n * (`sales-social`, the `audience-sync` track, pure conversion-tracking\n * adopters) DON'T need to implement these — see {@link SalesIngestionPlatform}.\n *\n * Used by `RequiredPlatformsFor<S>` to pick the right slice of `SalesPlatform`\n * per claimed specialism.\n *\n * @public\n */\nexport type SalesCorePlatform<TCtxMeta = Record<string, unknown>> = Required<\n Pick<\n SalesPlatform<TCtxMeta>,\n 'getProducts' | 'createMediaBuy' | 'updateMediaBuy' | 'getMediaBuyDelivery' | 'getMediaBuys'\n >\n>;\n\n/**\n * Names the **asset-ingestion surface** — sync surfaces for creatives,\n * audiences (via {@link import('./audiences').AudiencePlatform}), catalogs,\n * events, plus the read/feedback tools. Walled-garden specialisms\n * (`sales-social`) live here.\n *\n * Every method is optional individually. Adopters claiming `sales-social`\n * pick whichever ingestion surfaces apply (typically `syncCreatives` +\n * `logEvent` + `syncEventSources`); the rest stay omitted.\n *\n * Used by `RequiredPlatformsFor<S>` so claiming `sales-social` only requires\n * this slice of `SalesPlatform`, not the full {@link SalesCorePlatform}.\n *\n * @public\n */\nexport type SalesIngestionPlatform<TCtxMeta = Record<string, unknown>> = Pick<\n SalesPlatform<TCtxMeta>,\n | 'syncCreatives'\n | 'syncCatalogs'\n | 'syncEventSources'\n | 'logEvent'\n | 'listCreativeFormatsLegacy'\n | 'listCreatives'\n | 'providePerformanceFeedback'\n>;\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/specialisms/sales.ts"],"sourcesContent":["/**\n * SalesPlatform — sales specialism platform interface.\n *\n * **Unified hybrid shape.** `get_products`, `create_media_buy`, and `sync_creatives` use a\n * single method each. The method returns the wire success arm (sync fast\n * path) OR `ctx.handoffToTask(fn)` to promote the call to a background\n * task (HITL slow path). Branch per-call — the same method handles\n * programmatic remnant, guaranteed inventory, curated discovery, and hybrid\n * sellers. Every other tool is sync-only:\n *\n * - `get_products` — sync OR `ctx.handoffToTask(...)` for curated brief/refine flows.\n * - `create_media_buy` — sync OR `ctx.handoffToTask(...)`.\n * - `update_media_buy` — sync only. Re-approval flows that need HITL run\n * out-of-band; `publishStatusChange` carries the result.\n * - `sync_creatives` — sync OR `ctx.handoffToTask(...)`.\n * - `get_media_buy_delivery` — sync only.\n *\n * Sync-only tools that need long-running semantics use `publishStatusChange`\n * (see `status-changes.ts`) — that's the spec-aligned channel for tools\n * whose wire response unions don't define a Submitted arm.\n *\n * Each method either returns the value or throws `AdcpError` for structured\n * rejection. Generic thrown errors map to `SERVICE_UNAVAILABLE`.\n *\n * **Method groups** — implement the group(s) matching your specialism:\n *\n * | Group | Methods | Claim when |\n * |---|---|---|\n * | Core sales (required) | `getProducts`, `updateMediaBuy`, `getMediaBuyDelivery` | Any `sales-*` specialism |\n * | Core sales (unified hybrid) | `createMediaBuy` | Any `sales-*` specialism |\n * | Core sales (unified hybrid) | `syncCreatives` | Any `sales-*` specialism |\n * | Read / feedback | `getMediaBuys`, `providePerformanceFeedback`, `listCreativeFormats`, `listCreatives` | Most sellers; optional |\n * | Retail-media extensions | `syncCatalogs`, `logEvent`, `syncEventSources` | `sales-catalog-driven`, `sales-retail-media` |\n *\n * New adopters implementing a non-retail seller (GAM, FreeWheel, a social\n * platform) only need the three core-required methods plus `createMediaBuy`\n * and `syncCreatives`. The retail-media extension methods (`syncCatalogs`,\n * `logEvent`, `syncEventSources`) are unnecessary unless you claim\n * `sales-catalog-driven` or `sales-retail-media`.\n *\n * **No-account tools (`providePerformanceFeedback`, `listCreativeFormats`):**\n * the wire requests for these two tools don't carry an `account` field, so\n * `ctx.account` may be `undefined` when `accounts.resolution === 'explicit'`.\n * Three safe patterns:\n *\n * 1. **`'derived'` resolution** — `accounts.resolve(undefined)` returns a\n * singleton; `ctx.account` is always set. Best for single-tenant\n * deployers.\n * 2. **Don't implement the method** — the framework returns\n * `UNSUPPORTED_FEATURE`; buyers using the merge-seam custom handler or\n * external creative agents still receive a response.\n * 3. **Explicit-mode with defensive read** — cast `ctx.account as Account |\n * undefined` and derive the account from the request body (e.g., via a\n * `media_buy_id` lookup), or throw `AdcpError('ACCOUNT_NOT_FOUND')`.\n * Full `resolveAccount(undefined, { authInfo, toolName })` support for\n * explicit-mode lands in rc.1.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport type { Account, NoAccountCtx } from '../account';\nimport type { RequestContext } from '../context';\nimport type { TaskHandoff } from '../async-outcome';\nimport type { RequireCacheScopeWhenProducts, ServerPayload } from '../../../types/server-payload';\nimport type {\n GetProductsRequest,\n GetProductsResponse,\n CreateMediaBuyError,\n CreateMediaBuySuccess,\n UpdateMediaBuySuccess,\n GetMediaBuysRequest,\n GetMediaBuysResponse,\n GetMediaBuyDeliveryRequest,\n GetMediaBuyDeliveryResponse,\n ProvidePerformanceFeedbackRequest,\n ProvidePerformanceFeedbackSuccess,\n ListCreativeFormatsRequest,\n ListCreativeFormatsResponse,\n ListCreativesRequest,\n ListCreativesResponse,\n MediaBuyStatus,\n SyncCatalogsRequest,\n SyncCatalogsSuccess,\n LogEventRequest,\n LogEventSuccess,\n SyncEventSourcesRequest,\n SyncEventSourcesSuccess,\n SyncCreativesError,\n SyncCreativesSuccess,\n} from '../../../types/tools.generated';\nimport type { ProposalRefinementCapabilities } from '../../../negotiation/types';\nimport type { AdcpToolMap } from '../../create-adcp-server';\nimport type {\n CanonicalSyncCreativeAsset,\n CanonicalCreateMediaBuyRequest,\n CanonicalCreativeResponse,\n CanonicalGetProductsRequest,\n CanonicalListCreativesRequest,\n CanonicalListCreativesResponse,\n CanonicalProduct,\n CanonicalUpdateMediaBuyRequest,\n} from '../../../v2/projection/creative-delivery';\n\ntype SyncCreative = CanonicalSyncCreativeAsset;\ntype Ctx<TCtxMeta> = RequestContext<Account<TCtxMeta>>;\ntype ExclusivePayload<TLeft, TRight> =\n | (TLeft & { [K in Exclude<keyof TRight, keyof TLeft>]?: never })\n | (TRight & { [K in Exclude<keyof TLeft, keyof TRight>]?: never });\ntype LegacyMediaBuyStatusInput<T> = T & { status?: MediaBuyStatus };\n\ntype CanonicalGetProductsPayload = Omit<ServerPayload<CanonicalCreativeResponse<GetProductsResponse>>, 'products'> & {\n products?: CanonicalProduct[];\n};\nexport type GetProductsPayload = RequireCacheScopeWhenProducts<CanonicalGetProductsPayload>;\ntype CreateMediaBuySuccessPayload = LegacyMediaBuyStatusInput<\n ServerPayload<CanonicalCreativeResponse<CreateMediaBuySuccess>>\n>;\ntype CreateMediaBuyErrorPayload = ServerPayload<CanonicalCreativeResponse<CreateMediaBuyError>>;\nexport type CreateMediaBuyPayload = ExclusivePayload<CreateMediaBuySuccessPayload, CreateMediaBuyErrorPayload>;\nexport type UpdateMediaBuyPayload = LegacyMediaBuyStatusInput<\n ServerPayload<CanonicalCreativeResponse<UpdateMediaBuySuccess>>\n>;\nexport type GetMediaBuyDeliveryPayload = ServerPayload<CanonicalCreativeResponse<GetMediaBuyDeliveryResponse>>;\nexport type GetMediaBuysPayload = ServerPayload<CanonicalCreativeResponse<GetMediaBuysResponse>>;\nexport type ProvidePerformanceFeedbackPayload = ServerPayload<ProvidePerformanceFeedbackSuccess>;\nexport type LegacyListCreativeFormatsPayload = ServerPayload<ListCreativeFormatsResponse>;\nexport type ListCreativesPayload = ServerPayload<CanonicalListCreativesResponse>;\nexport type LegacyGetProductsPayload = RequireCacheScopeWhenProducts<ServerPayload<GetProductsResponse>>;\nexport type LegacyCreateMediaBuyPayload = ExclusivePayload<\n LegacyMediaBuyStatusInput<ServerPayload<CreateMediaBuySuccess>>,\n ServerPayload<CreateMediaBuyError>\n>;\nexport type LegacyUpdateMediaBuyPayload = LegacyMediaBuyStatusInput<ServerPayload<UpdateMediaBuySuccess>>;\nexport type LegacyGetMediaBuyDeliveryPayload = ServerPayload<GetMediaBuyDeliveryResponse>;\nexport type LegacyGetMediaBuysPayload = ServerPayload<GetMediaBuysResponse>;\nexport type LegacyListCreativesPayload = ServerPayload<ListCreativesResponse>;\nexport type SyncCreativesSuccessPayload = ServerPayload<SyncCreativesSuccess>;\nexport type SyncCreativesErrorPayload = ServerPayload<SyncCreativesError>;\nexport type SyncCreativesPayload = SyncCreativesSuccessPayload | SyncCreativesErrorPayload;\nexport type SyncCatalogsPayload = ServerPayload<SyncCatalogsSuccess>;\nexport type LogEventPayload = ServerPayload<LogEventSuccess>;\nexport type SyncEventSourcesPayload = ServerPayload<SyncEventSourcesSuccess>;\nexport type ListProductsPayload = AdcpToolMap['list_products']['result'];\nexport type RequestProposalsPayload = AdcpToolMap['request_proposals']['result'];\nexport type DeclineProposalsPayload = AdcpToolMap['decline_proposals']['result'];\nexport type BuyProductsPayload = AdcpToolMap['buy_products']['result'];\nexport type AcceptProposalPayload = AdcpToolMap['accept_proposal']['result'];\nexport type ControlMediaBuyPayload = AdcpToolMap['control_media_buy']['result'];\nexport type RefineProposalsPayload = AdcpToolMap['refine_proposals']['result'];\n\n/**\n * Wire success-row shape for `sync_creatives`. Returning the array of these\n * rows from `syncCreatives` is what adopters write — the framework wraps\n * with `{ creatives: [...] }` to form `SyncCreativesSuccess`.\n */\nexport type SyncCreativesRow = SyncCreativesSuccess['creatives'][number];\nexport type GetProductsHandlerResult = GetProductsPayload | TaskHandoff<GetProductsPayload>;\nexport type CreateMediaBuyHandlerResult = CreateMediaBuyPayload | TaskHandoff<CreateMediaBuySuccessPayload>;\nexport type UpdateMediaBuyHandlerResult = UpdateMediaBuyPayload | TaskHandoff<UpdateMediaBuyPayload>;\nexport type SyncCreativesHandlerResult = SyncCreativesRow[] | TaskHandoff<SyncCreativesRow[]>;\n\ntype CompactLifecycleHandlerResult<T> = T | TaskHandoff<T>;\n\n/**\n * Primary AdCP 3.2 media-buy lifecycle surface.\n *\n * This lives beside {@link SalesPlatform} so SDK 14 adopters can implement\n * the compact protocol without translating it back into deprecated\n * `get_products` / `create_media_buy` / `update_media_buy` methods. Keep a\n * `SalesPlatform` implementation as well when the same deployment must serve\n * legacy 3.0/3.1 buyers; the server advertises only the compact profile to\n * 3.2 MCP discovery while retaining those older call routes.\n *\n * `refineProposals` requires `proposalRefinement` so capability discovery can\n * declare the supported structured refinement dimensions truthfully.\n *\n * @public\n */\nexport interface MediaBuyLifecyclePlatform<TCtxMeta = Record<string, unknown>> {\n proposalRefinement?: ProposalRefinementCapabilities;\n listProducts?(req: AdcpToolMap['list_products']['params'], ctx: Ctx<TCtxMeta>): Promise<ListProductsPayload>;\n requestProposals?(\n req: AdcpToolMap['request_proposals']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<RequestProposalsPayload>>;\n refineProposals?(\n req: AdcpToolMap['refine_proposals']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<RefineProposalsPayload>>;\n declineProposals?(\n req: AdcpToolMap['decline_proposals']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<DeclineProposalsPayload>>;\n buyProducts?(\n req: AdcpToolMap['buy_products']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<BuyProductsPayload>>;\n acceptProposal?(\n req: AdcpToolMap['accept_proposal']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<AcceptProposalPayload>>;\n controlMediaBuy?(\n req: AdcpToolMap['control_media_buy']['params'],\n ctx: Ctx<TCtxMeta>\n ): Promise<CompactLifecycleHandlerResult<ControlMediaBuyPayload>>;\n getMediaBuys?(req: GetMediaBuysRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuysPayload>;\n getMediaBuyDelivery?(filter: GetMediaBuyDeliveryRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuyDeliveryPayload>;\n}\n\nexport type MediaBuyLifecycleCorePlatform<TCtxMeta = Record<string, unknown>> = Required<\n Pick<\n MediaBuyLifecyclePlatform<TCtxMeta>,\n 'listProducts' | 'buyProducts' | 'controlMediaBuy' | 'getMediaBuys' | 'getMediaBuyDelivery'\n >\n>;\n\nexport type MediaBuyLifecycleProposalPlatform<TCtxMeta = Record<string, unknown>> = Required<\n Pick<\n MediaBuyLifecyclePlatform<TCtxMeta>,\n | 'proposalRefinement'\n | 'listProducts'\n | 'requestProposals'\n | 'refineProposals'\n | 'declineProposals'\n | 'acceptProposal'\n | 'getMediaBuys'\n | 'getMediaBuyDelivery'\n >\n>;\n\nexport interface SalesPlatform<TCtxMeta = Record<string, unknown>> {\n // **Method shape — all optional, enforced per-specialism.** Every method on\n // `SalesPlatform` is declared optional so the type accommodates non-media-\n // buy walled gardens (sales-social, audience-sync, sales-proposal-mode)\n // that don't accept inbound media buys but compose ingestion methods on\n // this same surface. Compile-time enforcement of \"you claimed\n // sales-non-guaranteed, therefore you MUST implement getProducts /\n // createMediaBuy / updateMediaBuy / getMediaBuyDelivery / getMediaBuys\"\n // moves up to `RequiredPlatformsFor<S>` — see the {@link SalesCorePlatform}\n // type alias and the per-specialism mapping in `platform.ts`. Runtime\n // enforcement is preserved: the dispatcher returns `UNSUPPORTED_FEATURE`\n // for tools whose method is absent, and `validateSpecialismRequiredTools`\n // throws / warns when a specialism's required tools aren't implemented.\n //\n // Adopters who implement the full media-buy surface keep working — their\n // implementation is a superset of every per-specialism requirement.\n // Adopters who only do ingestion (e.g. a Meta CAPI integration claiming\n // `sales-social`) drop the 5 core stubs without compile errors.\n\n // ── get_products: unified hybrid shape ────────────────────────────\n // get_products is a CATALOG LOOKUP — fast read against the seller's\n // existing inventory. rc8 allows curated brief/refine lookups to return a\n // Submitted arm when the seller needs async enrichment. Adopters express\n // that by returning ctx.handoffToTask(fn); the framework owns task_id\n // allocation, polling state, and optional completion webhook delivery.\n //\n // Wholesale catalog dumps remain sync: if the seller cannot serve the\n // full catalog directly, it should maintain an internal cache and return\n // the current catalog view instead of turning wholesale discovery into a\n // long-running operation.\n /** Catalog discovery: return products directly or hand off curated discovery to a background task. */\n getProducts?(req: CanonicalGetProductsRequest, ctx: Ctx<TCtxMeta>): Promise<GetProductsHandlerResult>;\n\n // ── create_media_buy: unified hybrid shape ──────────────────────────\n\n /**\n * Create a media buy. Return the wire success-arm shape (sync fast path)\n * OR `ctx.handoffToTask(fn)` to promote the call to a background task\n * (HITL slow path). Adopters can branch per-call: hybrid sellers route\n * programmatic remnant sync, guaranteed inventory through HITL, all\n * from the same method.\n *\n * Buyers pattern-match on the wire response shape (`media_buy_id` on\n * the immediate response → sync; `task_id` + `status: 'submitted'` →\n * poll `tasks_get` or receive webhook). Predictable per request,\n * dynamic per call.\n *\n * Status changes flow via `publishStatusChange(...)` regardless of\n * which path was taken.\n *\n * For synchronous domain validation that produces multiple failures,\n * return the pure Error arm (`{ errors: [...] }`) with no success-only\n * fields. Handoff callbacks remain success-only; throw `AdcpError` inside\n * a handoff to transition the task to `failed`.\n *\n * The handoff function's return value is persisted as JSONB in the\n * task registry. Postgres-backed registries cap row size at 4MB —\n * offload large payloads to blob storage and return references.\n *\n * @example Sync-only adopter (no HITL inventory)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * return await this.commitSync(req);\n * }\n * ```\n *\n * @example HITL-only adopter (every call goes through trafficker review)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * return ctx.handoffToTask(async (taskCtx) => {\n * await taskCtx.update({ message: 'Awaiting trafficker' });\n * return await this.runHITL(req);\n * });\n * }\n * ```\n *\n * @example Hybrid adopter (programmatic + guaranteed in same tenant)\n * ```ts\n * createMediaBuy: async (req, ctx) => {\n * if (this.requiresHITL(req)) {\n * return ctx.handoffToTask(async (taskCtx) => await this.runHITL(req));\n * }\n * return await this.commitSync(req);\n * }\n * ```\n */\n createMediaBuy?(req: CanonicalCreateMediaBuyRequest, ctx: Ctx<TCtxMeta>): Promise<CreateMediaBuyHandlerResult>;\n\n // ── update_media_buy: unified hybrid shape\n /**\n * Update a media buy. Return the patched buy immediately (sync fast path)\n * OR `ctx.handoffToTask(fn)` when the upstream activation or approval flow\n * must continue in the background. The framework owns task registration,\n * caller scoping, polling, and completion webhooks on the handoff path.\n */\n updateMediaBuy?(\n buyId: string,\n patch: CanonicalUpdateMediaBuyRequest,\n ctx: Ctx<TCtxMeta>\n ): Promise<UpdateMediaBuyHandlerResult>;\n\n // ── sync_creatives: unified hybrid shape ────────────────────────────\n\n /**\n * Push creatives. Return the array of wire success rows (sync fast\n * path) OR `ctx.handoffToTask(fn)` to defer to a background task\n * (HITL slow path — manual review, brand-suitability gates, etc.).\n * Hybrid: branch per-batch — auto-approve simple creatives sync,\n * route everything else to HITL.\n *\n * Each row carries `action` (CRUD outcome) and optional `status`\n * (review state). Buyers see mixed `approved` / `pending_review`\n * rows on the sync path; subsequent review changes flow via\n * `publishStatusChange(...)`.\n *\n * @example Hybrid adopter\n * ```ts\n * syncCreatives: async (creatives, ctx) => {\n * if (creatives.some(c => this.needsReview(c))) {\n * return ctx.handoffToTask(async (taskCtx) => {\n * return await this.reviewAndPersist(creatives);\n * });\n * }\n * return creatives.map(c => ({ creative_id: c.creative_id, action: 'created', status: 'approved' }));\n * }\n * ```\n */\n syncCreatives?(creatives: SyncCreative[], ctx: Ctx<TCtxMeta>): Promise<SyncCreativesHandlerResult>;\n\n // ── get_media_buy_delivery: sync only ───────────────────────────────\n\n /**\n * Per-media-buy delivery actuals (impressions, spend, pacing,\n * conversions). Sync — report-running platforms with manual report\n * cycles return the latest cached actuals and emit `delivery_report`\n * status changes via `publishStatusChange` when fresh reports are\n * available.\n *\n * **Multi-id contract.** `filter.media_buy_ids` is an array — buyers\n * routinely request delivery for multiple buys in one call. The\n * platform MUST iterate every id and return one element per id in\n * `media_buy_deliveries[]`. Implementations that read only\n * `media_buy_ids[0]` silently truncate the buyer's request — a\n * correctness bug that has bitten multiple adopters (closes #1342).\n *\n * Pass-through is the framework contract: the platform owns fan-out\n * because `aggregated_totals` requires platform-domain knowledge —\n * `reach` (cross-buy dedup capability), `new_to_brand_rate` (weighted\n * across buys, not a per-buy average), and `frequency` (depends on\n * dedup) cannot be synthesized correctly by a naive framework loop.\n * Sellers that can't compute the cross-buy fields omit them and emit\n * the safely-summable fields (`impressions`, `spend`, `clicks`,\n * `media_buy_count`); buyers fall back to per-buy values when needed.\n *\n * Recommended pattern — prefer the upstream's native multi-id query\n * over a per-id loop. Most reporting APIs (GAM ReportService's\n * `WHERE LINE_ITEM_ID IN (...)`, TTD, DV360, Magnite, PubMatic, retail\n * media) take an id list in one round-trip; iterating one-id-at-a-time\n * is an N-roundtrip pattern that triggers upstream rate limits on\n * 50-buy reports.\n *\n * ```ts\n * getMediaBuyDelivery: async (req, ctx) => {\n * const ids = req.media_buy_ids ?? [];\n * // Native multi-id: one upstream round-trip.\n * const rows = await this.upstream.report({\n * mediaBuyIds: ids,\n * start: req.start_date,\n * end: req.end_date,\n * });\n * return {\n * reporting_period: { start, end },\n * currency: 'USD',\n * media_buy_deliveries: rows,\n * aggregated_totals: this.upstream.aggregate(rows),\n * };\n * }\n * ```\n *\n * **Single-id fallback** — only if your upstream is genuinely single-id:\n *\n * ```ts\n * const deliveries = await Promise.all(ids.map(id => fetchOne(id, ctx)));\n * ```\n *\n * When `media_buy_ids` is omitted, return a paginated set of\n * accessible media buys per the wire schema. `status_filter`\n * defaults to `['active']` when omitted; honor the filter in your\n * iteration.\n */\n getMediaBuyDelivery?(filter: GetMediaBuyDeliveryRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuyDeliveryPayload>;\n\n // ── get_media_buys: sync only — REQUIRED ──────────────────────────────\n // Read tool — buyers fetch a list of their media buys (often filtered by\n // status / time window). Required because:\n // 1. Every seller needs to support reading back what they created.\n // 2. Idempotent retries depend on it (replay safe-by-design).\n // 3. The 6.2 patch-decomposition redesign needs single-id reads;\n // `getMediaBuys` is the foundation.\n // 4. Framework auto-stores returned media buys for hydration on\n // subsequent updateMediaBuy calls (see `hydratePackagesWithProducts`\n // pattern in `from-platform.ts`).\n //\n // Proposal-mode adopters (write-only via push channels) return an empty\n // `media_buys: []` array — that's a valid response.\n /**\n * List media buys this account owns. Filter + pagination per the wire shape.\n *\n * **Multi-id contract.** `req.media_buy_ids` is an array — buyers\n * routinely request a specific set of buys in one call. The platform\n * MUST iterate every id and return one element per id in the response\n * `media_buys[]` array. Reading only `media_buy_ids[0]` silently\n * truncates the buyer's request — same correctness bug that #1342\n * documented for `getMediaBuyDelivery`. Same recommended pattern: prefer\n * an upstream multi-id query (one round-trip), fall back to per-id loop\n * only when the upstream is single-id-only.\n *\n * When `media_buy_ids` is omitted, return a paginated set of accessible\n * buys filtered by `status_filter` (defaults to `['active']`).\n */\n getMediaBuys?(req: GetMediaBuysRequest, ctx: Ctx<TCtxMeta>): Promise<GetMediaBuysPayload>;\n\n // ── provide_performance_feedback: sync only ─────────────────────────\n // Write tool — buyers report aggregate creative-level performance\n // (impressions, clicks, conversions) to help the seller's optimizer learn.\n // Optional because not every sales agent runs an optimizer, but every\n // buyer expects to be able to call it. Framework returns UNSUPPORTED_FEATURE\n // when omitted.\n //\n // ⚠️ NO-ACCOUNT TOOL — `ctx: NoAccountCtx<TCtxMeta>`. The wire request\n // does not carry an `account` field. `ctx.account` may be `undefined` for\n // `'explicit'`-resolution adopters; narrow before reading\n // `ctx.account.ctx_metadata`. See {@link NoAccountCtx} and the\n // `SalesPlatform` JSDoc (\"No-account tools\") for safe patterns.\n /** Accept buyer-side performance signals on a media buy / creative. */\n providePerformanceFeedback?(\n req: ProvidePerformanceFeedbackRequest,\n ctx: NoAccountCtx<TCtxMeta>\n ): Promise<ProvidePerformanceFeedbackPayload>;\n\n // ── list_creative_formats: sync only ────────────────────────────────\n // Discovery tool — buyers query what creative formats this seller\n // accepts. Optional because sellers that delegate to external\n // `creative_agents` (declared in `capabilities.creative_agents[]`) don't\n // own format definitions; framework can resolve from the declared agents.\n // Self-hosted sellers (own creative library) implement this directly.\n //\n // ⚠️ NO-ACCOUNT TOOL — `ctx: NoAccountCtx<TCtxMeta>`. See\n // `providePerformanceFeedback` note above.\n listCreativeFormatsLegacy?(\n req: ListCreativeFormatsRequest,\n ctx: NoAccountCtx<TCtxMeta>\n ): Promise<LegacyListCreativeFormatsPayload>;\n\n // ── list_creatives: sync only ───────────────────────────────────────\n // Read tool — buyers query the seller's creative library. Optional\n // because most sales adopters delegate creative state to the\n // `creative_agents` declared in capabilities; ad-server-style sales\n // platforms implement directly. Note: also lives on `CreativeAdServerPlatform.listCreatives`\n // for the standalone-creative-agent shape.\n listCreatives?(req: CanonicalListCreativesRequest, ctx: Ctx<TCtxMeta>): Promise<ListCreativesPayload>;\n\n // ── sync_catalogs: sync only ────────────────────────────────────────\n // Retail-media catalog sync. Buyers push product catalogs (SKUs, ASINs,\n // store-ids) for `sales-catalog-driven` agents (Amazon, Criteo, Citrusad,\n // Walmart Connect, Shopify ad surfaces). Optional — non-retail sales\n // adopters omit. Idempotent on the buyer's `idempotency_key`.\n syncCatalogs?(req: SyncCatalogsRequest, ctx: Ctx<TCtxMeta>): Promise<SyncCatalogsPayload>;\n\n // ── log_event: sync only ────────────────────────────────────────────\n // Conversion / engagement event logging. Buyers post events tied to\n // a `media_buy_id` for performance attribution. Used by retail-media\n // (post-purchase events) and conversion-tracked sales (Snap pixel,\n // Meta CAPI, LinkedIn conversions API). Optional.\n logEvent?(req: LogEventRequest, ctx: Ctx<TCtxMeta>): Promise<LogEventPayload>;\n\n // ── sync_event_sources: sync only ──────────────────────────────────\n // Register conversion event sources (websites, apps, offline pixel\n // IDs) so subsequent `log_event` calls can be attributed correctly.\n // Optional — adopters who don't expose conversion tracking omit.\n syncEventSources?(req: SyncEventSourcesRequest, ctx: Ctx<TCtxMeta>): Promise<SyncEventSourcesPayload>;\n}\n\n/**\n * Names the **core sales surface** — bidding + media-buy lifecycle. Required\n * for `sales-*` specialisms that own pricing/pacing\n * (`sales-non-guaranteed`, `sales-guaranteed`, `sales-broadcast-tv`,\n * `sales-streaming-tv`, `sales-exchange`, `sales-catalog-driven`,\n * `sales-retail-media`).\n *\n * Walled-garden specialisms whose value surface is asset ingestion\n * (`sales-social`, the `audience-sync` track, pure conversion-tracking\n * adopters) DON'T need to implement these — see {@link SalesIngestionPlatform}.\n *\n * Used by `RequiredPlatformsFor<S>` to pick the right slice of `SalesPlatform`\n * per claimed specialism.\n *\n * @public\n */\nexport type SalesCorePlatform<TCtxMeta = Record<string, unknown>> = Required<\n Pick<\n SalesPlatform<TCtxMeta>,\n 'getProducts' | 'createMediaBuy' | 'updateMediaBuy' | 'getMediaBuyDelivery' | 'getMediaBuys'\n >\n>;\n\n/**\n * Names the **asset-ingestion surface** — sync surfaces for creatives,\n * audiences (via {@link import('./audiences').AudiencePlatform}), catalogs,\n * events, plus the read/feedback tools. Walled-garden specialisms\n * (`sales-social`) live here.\n *\n * Every method is optional individually. Adopters claiming `sales-social`\n * pick whichever ingestion surfaces apply (typically `syncCreatives` +\n * `logEvent` + `syncEventSources`); the rest stay omitted.\n *\n * Used by `RequiredPlatformsFor<S>` so claiming `sales-social` only requires\n * this slice of `SalesPlatform`, not the full {@link SalesCorePlatform}.\n *\n * @public\n */\nexport type SalesIngestionPlatform<TCtxMeta = Record<string, unknown>> = Pick<\n SalesPlatform<TCtxMeta>,\n | 'syncCreatives'\n | 'syncCatalogs'\n | 'syncEventSources'\n | 'logEvent'\n | 'listCreativeFormatsLegacy'\n | 'listCreatives'\n | 'providePerformanceFeedback'\n>;\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -195,7 +195,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
195
195
|
*/
|
|
196
196
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
197
197
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
198
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.
|
|
198
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.1";
|
|
199
199
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
200
200
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
201
201
|
/**
|
|
@@ -195,7 +195,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
195
195
|
*/
|
|
196
196
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
197
197
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
198
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.
|
|
198
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.1";
|
|
199
199
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
200
200
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
201
201
|
/**
|
|
@@ -126,6 +126,8 @@ export { SCHEMA_FILENAME_SUFFIX };
|
|
|
126
126
|
* we don't have schemas for.
|
|
127
127
|
*/
|
|
128
128
|
export declare function hasSchemaBundle(version: string): boolean;
|
|
129
|
+
/** Load the exact self-contained request projection from an MCP role profile. */
|
|
130
|
+
export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
|
|
129
131
|
/**
|
|
130
132
|
* Test hook: reset cached state. With no argument, clears every version's
|
|
131
133
|
* loader state; with a version, clears only the bundle that version
|
|
@@ -126,6 +126,8 @@ export { SCHEMA_FILENAME_SUFFIX };
|
|
|
126
126
|
* we don't have schemas for.
|
|
127
127
|
*/
|
|
128
128
|
export declare function hasSchemaBundle(version: string): boolean;
|
|
129
|
+
/** Load the exact self-contained request projection from an MCP role profile. */
|
|
130
|
+
export declare function getMcpProfileInputSchema(toolName: string, profile: string, version?: string): Readonly<Record<string, unknown>> | undefined;
|
|
129
131
|
/**
|
|
130
132
|
* Test hook: reset cached state. With no argument, clears every version's
|
|
131
133
|
* loader state; with a version, clears only the bundle that version
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAQjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;AAOpD,QAAA,MAAM,sBAAsB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAMrD,CAAC;AAeF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgCxD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAgB/E;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAsBzE;AAkPD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAanG;AA6ND;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAoC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CA6C9B;AAuCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAG1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,MAAqB,GAAG,SAAS,MAAM,EAAE,CAMxF;AAED,8DAA8D;AAC9D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAQjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;AAOpD,QAAA,MAAM,sBAAsB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAMrD,CAAC;AAeF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgCxD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAgB/E;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAsBzE;AAkPD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAanG;AA6ND;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAoC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CA6C9B;AAuCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAG1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,MAAqB,GAAG,SAAS,MAAM,EAAE,CAMxF;AAED,8DAA8D;AAC9D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOxD;AAID,iFAAiF;AACjF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAqB,GAC7B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAiC/C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAO7D;AAkDD,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAqB,GAC7B,SAAS,gBAAgB,EAAE,CAuI7B"}
|
|
@@ -30,6 +30,7 @@ var schema_loader_exports = {};
|
|
|
30
30
|
__export(schema_loader_exports, {
|
|
31
31
|
SCHEMA_FILENAME_SUFFIX: () => SCHEMA_FILENAME_SUFFIX,
|
|
32
32
|
_resetValidationLoader: () => _resetValidationLoader,
|
|
33
|
+
getMcpProfileInputSchema: () => getMcpProfileInputSchema,
|
|
33
34
|
getRegisteredSchemaIds: () => getRegisteredSchemaIds,
|
|
34
35
|
getRequestSchemaEntityPaths: () => getRequestSchemaEntityPaths,
|
|
35
36
|
getSchemaDefaultByPath: () => getSchemaDefaultByPath,
|
|
@@ -521,7 +522,36 @@ function hasSchemaBundle(version) {
|
|
|
521
522
|
return false;
|
|
522
523
|
}
|
|
523
524
|
}
|
|
525
|
+
const mcpProfileInputSchemaCache = /* @__PURE__ */ new Map();
|
|
526
|
+
function getMcpProfileInputSchema(toolName, profile, version = import_version.ADCP_VERSION) {
|
|
527
|
+
const root = resolveSchemaRoot(version);
|
|
528
|
+
const cacheKey = `${root}${profile}${toolName}`;
|
|
529
|
+
const cached = mcpProfileInputSchemaCache.get(cacheKey);
|
|
530
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
531
|
+
const mcpRoot = import_path.default.join(root, "mcp");
|
|
532
|
+
if (!(0, import_fs.existsSync)(mcpRoot)) {
|
|
533
|
+
mcpProfileInputSchemaCache.set(cacheKey, null);
|
|
534
|
+
return void 0;
|
|
535
|
+
}
|
|
536
|
+
const protocolVersions = (0, import_fs.readdirSync)(mcpRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
|
|
537
|
+
for (const protocolVersion of protocolVersions) {
|
|
538
|
+
const profileRoot = import_path.default.resolve(mcpRoot, protocolVersion, "profiles", profile);
|
|
539
|
+
const manifestFile = import_path.default.join(profileRoot, "manifest.json");
|
|
540
|
+
if (!(0, import_fs.existsSync)(manifestFile)) continue;
|
|
541
|
+
const manifest = loadJson(manifestFile);
|
|
542
|
+
const schemaRef = manifest.tools?.[toolName]?.inputSchema;
|
|
543
|
+
if (typeof schemaRef !== "string") continue;
|
|
544
|
+
const schemaFile = import_path.default.resolve(profileRoot, schemaRef);
|
|
545
|
+
if (!schemaFile.startsWith(`${profileRoot}${import_path.default.sep}`) || !(0, import_fs.existsSync)(schemaFile)) continue;
|
|
546
|
+
const schema = Object.freeze(loadJson(schemaFile));
|
|
547
|
+
mcpProfileInputSchemaCache.set(cacheKey, schema);
|
|
548
|
+
return schema;
|
|
549
|
+
}
|
|
550
|
+
mcpProfileInputSchemaCache.set(cacheKey, null);
|
|
551
|
+
return void 0;
|
|
552
|
+
}
|
|
524
553
|
function _resetValidationLoader(version) {
|
|
554
|
+
mcpProfileInputSchemaCache.clear();
|
|
525
555
|
if (version === void 0) {
|
|
526
556
|
states.clear();
|
|
527
557
|
} else {
|
|
@@ -697,6 +727,7 @@ function cloneJsonValue(value) {
|
|
|
697
727
|
0 && (module.exports = {
|
|
698
728
|
SCHEMA_FILENAME_SUFFIX,
|
|
699
729
|
_resetValidationLoader,
|
|
730
|
+
getMcpProfileInputSchema,
|
|
700
731
|
getRegisteredSchemaIds,
|
|
701
732
|
getRequestSchemaEntityPaths,
|
|
702
733
|
getSchemaDefaultByPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/validation/schema-loader.ts"],"sourcesContent":["/**\n * JSON Schema loader for AdCP tool request/response validation.\n *\n * Loads the bundled per-tool schemas shipped with the SDK plus the\n * `core/` schemas that async response variants `$ref`, then compiles\n * AJV validators lazily by `(toolName, direction)`.\n *\n * Stage 3: state is per-AdCP-version. The same SDK instance can hold\n * compiled validators for `3.0.0`, `3.0.1`, `3.1.0-beta.1`, etc. side by\n * side; callers pass the version they're validating against. Default is\n * the SDK-pinned `ADCP_VERSION` so callers that don't care about\n * cross-version selection (most internal call sites) keep working\n * unchanged.\n */\n\nimport Ajv, { type ValidateFunction } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { readdirSync, readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { ADCP_VERSION } from '../version';\nimport { ConfigurationError } from '../errors';\n\nexport type ResponseVariant = 'sync' | 'submitted' | 'working' | 'input-required';\nexport type Direction = 'request' | ResponseVariant;\n\ninterface LoadedSchema {\n $id?: string;\n [k: string]: unknown;\n}\n\nconst SCHEMA_FILENAME_SUFFIX: Record<Direction, string> = {\n request: 'request',\n sync: 'response',\n submitted: 'async-response-submitted',\n working: 'async-response-working',\n 'input-required': 'async-response-input-required',\n};\n\n// Protocol bundles may ship transport-specific schema projections alongside\n// the canonical AdCP schemas. They are not runtime validation sources: the\n// official clients own transport framing, while this loader validates the\n// canonical tool arguments/results. AdCP 3.2's `mcp/2026-07-28` projection\n// also uses JSON Schema 2020-12, whereas the canonical bundle remains\n// Draft-07. Mixing it into the canonical AJV registry both indexes duplicate\n// tools and makes a Draft-07 instance attempt to register another dialect.\nconst TRANSPORT_PROJECTION_DIRECTORIES = new Set(['mcp']);\n\nfunction isRuntimeSchemaDirectory(name: string): boolean {\n return name !== 'bundled' && !TRANSPORT_PROJECTION_DIRECTORIES.has(name);\n}\n\n/**\n * Map a consumer-provided version pin to the loader's bundle key.\n *\n * - Stable semver `'3.0.0'` / `'3.0.1'` → `'3.0'` (latest patch in minor)\n * - Bare minor `'3.0'` → `'3.0'` (already the bundle key)\n * - Release-precision prerelease `'3.1-beta'` / `'3.1-beta.0'` →\n * returned verbatim. {@link resolveSchemaRoot} fuzzy-resolves to the\n * highest cached prerelease directory whose own release-precision form\n * matches (e.g. `'3.1-beta'` matches `schemas/cache/3.1.0-beta.0/`).\n * Accepted because sellers advertise `supported_versions` in this\n * shape (`[\"3.1-beta\"]`), and a buyer reading that off the wire must\n * be able to pin to it.\n * - Full prerelease semver `'3.1.0-beta.1'` → `'3.1.0-beta.1'`\n * (exact-version, intentional pin)\n * - Legacy alias `'v3'` / `'v2.5'` / `'v2.6'` → returned verbatim (cache\n * historically keyed these directories by the alias name)\n *\n * Per the AdCP spec convention patches don't change wire shape, so collapsing\n * stable patches into the minor is functionally equivalent for any validator\n * consumer. Prereleases are kept exact because pinning a beta is intentional\n * and bit-fidelity matters for cross-version interop tests.\n *\n * Throws `ConfigurationError` for any input that doesn't match one of the\n * recognized shapes. Strings reach `path.join` via `resolveSchemaRoot`, and\n * pass-through of arbitrary garbage (`'../etc'`, `'3foo'`) lets a non-version\n * directory probe leak through `hasSchemaBundle`'s boolean. The throw is\n * caught by `hasSchemaBundle`'s try/catch (still returns false) and surfaces\n * with a useful field name from `resolveAdcpVersion`.\n */\nexport function resolveBundleKey(version: string): string {\n // Bare 'MAJOR.MINOR' (no patch).\n const minorOnly = version.match(/^(\\d+)\\.(\\d+)$/);\n if (minorOnly) return `${minorOnly[1]}.${minorOnly[2]}`;\n // Release-precision prerelease 'MAJOR.MINOR-PRE' (no patch). Same SemVer §9\n // prerelease constraint as the full-semver branch — `'3.1-/../etc'`-style\n // strings can't slip through. Returns verbatim; resolveSchemaRoot does the\n // fuzzy directory match.\n const releasePrecisionPre = version.match(/^(\\d+)\\.(\\d+)-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*$/);\n if (releasePrecisionPre) return version;\n // Full 'MAJOR.MINOR.PATCH' with optional prerelease. Prerelease group\n // restricted to SemVer §9 identifiers (alphanumerics + hyphen,\n // dot-separated) so `'3.0.0-/../etc'`-style strings can't slip through\n // and reach `path.join` as a directory component. The full version is\n // returned verbatim for prereleases, so this is the last line of defense\n // before that string becomes a path segment.\n const semver = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$/);\n if (semver) {\n const [, major, minor, , prerelease] = semver;\n if (prerelease !== undefined) return version;\n return `${major}.${minor}`;\n }\n // Legacy alias: 'v' followed by a major and optional minor. Restricted to\n // this exact shape so non-version garbage can't reach the filesystem.\n const legacyAlias = version.match(/^v\\d+(\\.\\d+)?$/);\n if (legacyAlias) return version;\n throw new ConfigurationError(\n `AdCP version ${JSON.stringify(version)} is not a recognized version format. ` +\n `Expected semver (e.g. '3.0.1', '3.1.0-beta.1'), bare minor ('3.0'), ` +\n `release-precision ('3.1-beta'), or legacy alias ('v3', 'v2.5').`,\n 'adcpVersion'\n );\n}\n\n/**\n * Collapse a bundle key to the release-precision string the AdCP wire schema\n * accepts for the `adcp_version` envelope field (spec PR\n * `adcontextprotocol/adcp#3493`). The wire pattern is\n * `^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$` — release-precision (MAJOR.MINOR with\n * optional prerelease), never full MAJOR.MINOR.PATCH semver.\n *\n * - Stable bundle key `'3.0'` / `'3.1'` → returned verbatim.\n * - Prerelease bundle key `'3.1.0-beta.0'` → `'3.1-beta.0'` (PATCH segment\n * dropped; the prerelease tag is the wire-meaningful release identifier,\n * PATCH is implementation-internal).\n * - Full stable semver `'3.0.11'` → `'3.0'` (patches don't change wire\n * shape; surface them via `build_version` on capabilities instead).\n * - Legacy alias `'v3'` / `'v2.5'` — returned verbatim. The wire spec\n * predates the envelope field, so legacy-aliased clients won't emit\n * `adcp_version` anyway (gated by `bundleSupportsAdcpVersionField`).\n *\n * The normalization rule is declared in `core/version-envelope.json`:\n *\n * > SDKs that read full-semver values from bundle metadata (e.g.\n * > ComplianceIndex.published_version = \"3.1.0-beta.1\") MUST normalize to\n * > release-precision (\"3.1-beta.1\") before emitting on the wire —\n * > meta-field values are NOT valid wire values.\n *\n * **Idempotent.** Re-applying to an already-wire-shaped value is a no-op:\n * `toReleasePrecisionWire('3.1-beta.0') === '3.1-beta.0'`. Safe to call\n * defensively on values a caller read off the wire and is passing back.\n *\n * **Prerelease regex is stricter than the wire pattern by design.** The wire\n * pattern allows `[a-zA-Z0-9.-]+` (any mix of dots and hyphens), but this\n * function only accepts SemVer §9-shaped prerelease tags\n * (`[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*`) — disallowing leading dots, double\n * dots, or trailing dots. Mirrors the path-traversal hardening on\n * {@link resolveBundleKey} (`'3.0.0-/../etc'`-style strings can't reach the\n * filesystem there, and shouldn't be silently mirrored to the wire here).\n * A future reader who wants to \"fix\" this to match the wire regex\n * character-for-character should NOT — the strictness is intentional.\n *\n * Defense: rejecting unrecognized shapes here surfaces SDK-internal misuse\n * (someone calling this with raw garbage) loudly instead of silently\n * emitting a non-spec wire string.\n */\n/**\n * The exact pattern `core/version-envelope.json` applies to `adcp_version`\n * on the wire. Kept verbatim so {@link validateAdcpVersionWire} doesn't\n * drift from the spec — bump only when the spec itself bumps.\n */\nconst ADCP_VERSION_WIRE_PATTERN = /^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n\n/**\n * Validate a string against the AdCP 3.1 `adcp_version` wire pattern.\n * Throws `ConfigurationError` with a hint that points at\n * {@link toReleasePrecisionWire} when the value would be sent on the wire\n * but doesn't satisfy `core/version-envelope.json`'s pattern.\n *\n * Use this when you're constructing a request envelope by hand (storyboard\n * fixtures, conformance harnesses, custom transports) and want a clear\n * error rather than a downstream AJV pattern-mismatch from the seller —\n * by the time the seller rejects the request, the buyer's stack frame is\n * long gone and `core/version-envelope.json/properties/adcp_version/pattern`\n * is the only clue.\n *\n * The SDK's own `buildVersionEnvelope` calls this as a postcondition after\n * normalizing the bundle key — should never throw in well-formed SDK code,\n * but if a future refactor breaks the normalization the assertion fires\n * with a message that names the helper to call.\n *\n * Returns the value with the type narrowed to `string` via assertion.\n */\nexport function validateAdcpVersionWire(value: unknown): asserts value is string {\n if (typeof value !== 'string') {\n throw new ConfigurationError(\n `adcp_version must be a string. Got ${typeof value}. ` +\n `Use toReleasePrecisionWire() to convert a bundle key or full-semver pin to a wire-shaped string.`,\n 'adcp_version'\n );\n }\n if (!ADCP_VERSION_WIRE_PATTERN.test(value)) {\n throw new ConfigurationError(\n `adcp_version ${JSON.stringify(value)} doesn't match the AdCP 3.1 wire pattern ${ADCP_VERSION_WIRE_PATTERN}. ` +\n `Full-semver bundle keys (e.g. \"3.1.0-beta.0\") are NOT valid wire values — ` +\n `call toReleasePrecisionWire() to normalize (e.g. \"3.1.0-beta.0\" → \"3.1-beta.0\").`,\n 'adcp_version'\n );\n }\n}\n\nexport function toReleasePrecisionWire(bundleKeyOrVersion: string): string {\n // Bare release-precision (MAJOR.MINOR or MAJOR.MINOR-PRE) — already wire-shaped.\n const releasePrecision = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (releasePrecision) {\n const [, major, minor, prerelease = ''] = releasePrecision;\n return `${major}.${minor}${prerelease}`;\n }\n // Full semver — collapse PATCH segment. Prerelease (if any) is preserved.\n const fullSemver = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)\\.\\d+(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (fullSemver) {\n const [, major, minor, prerelease = ''] = fullSemver;\n return `${major}.${minor}${prerelease}`;\n }\n // Legacy alias passthrough. Callers that reach here with a legacy alias\n // shouldn't be emitting `adcp_version` (no version-envelope support), but\n // returning the input verbatim is least-surprise.\n if (/^v\\d+(\\.\\d+)?$/.test(bundleKeyOrVersion)) return bundleKeyOrVersion;\n throw new ConfigurationError(\n `Cannot normalize ${JSON.stringify(bundleKeyOrVersion)} to release-precision wire format. ` +\n `Expected a bundle key or AdCP version string.`,\n 'adcpVersion'\n );\n}\n\n/**\n * Resolve the directory that holds the bundled + core schemas for a given\n * AdCP version. Source layout (dev):\n * schemas/cache/<exact-version>/{bundled,core}\n * Built layout (dist):\n * dist/lib/schemas-data/<bundle-key>/{bundled,core}\n *\n * Stable releases use minor-name keys (`3.0/`); prereleases use full-version\n * keys (`3.1.0-beta.1/`). See {@link resolveBundleKey}.\n *\n * Falls back to the source-tree cache when dist isn't built (dev workflow\n * before `npm run build:lib`). For stable pins, the cache fallback scans\n * for the highest-patch sibling in the requested minor — `'3.0.0'` resolves\n * to `schemas/cache/3.0.1/` when only `3.0.1` is cached, matching dist's\n * collapse behavior.\n *\n * Throws when no bundle exists. Callers pinning a specific prerelease\n * surface the error; the construction-time fence in `resolveAdcpVersion`\n * catches most cross-major mistakes before this point.\n */\nfunction resolveSchemaRoot(version: string): string {\n const key = resolveBundleKey(version);\n const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);\n if (scopedRoot && existsSync(scopedRoot)) return scopedRoot;\n\n const externalRoot = externalSchemaRoots.get(key);\n if (externalRoot && existsSync(externalRoot)) return externalRoot;\n\n const distCandidate = path.join(__dirname, '..', 'schemas-data', key);\n if (existsSync(distCandidate)) return distCandidate;\n\n // Published builds carry exact prerelease bundle directories\n // (`3.1.0-rc.1/`), while callers may pin the release-precision family\n // alias (`3.1-rc`). Resolve that alias before falling back to source cache.\n const releasePrecisionMatch = /^\\d+\\.\\d+-/.test(key);\n if (releasePrecisionMatch) {\n const distPrereleaseCandidate = findPrereleaseBundle(path.join(__dirname, '..', 'schemas-data'), key);\n if (distPrereleaseCandidate) return distPrereleaseCandidate;\n }\n\n // Source-tree fallback: cache stays exact-version-named, so map the key\n // back to the highest-patch cache directory in the same minor for stable\n // pins. Prereleases need an exact match.\n const cacheRoot = path.join(__dirname, '..', '..', '..', 'schemas', 'cache');\n const exactCandidate = path.join(cacheRoot, version);\n if (existsSync(exactCandidate)) return exactCandidate;\n\n // For minor-only or stable-patch pins, find the highest stable patch in\n // the cache that matches the resolved minor. Skip `*.previous` snapshots\n // — `sync-schemas` writes those as transient backups during replaceTree;\n // a partially-written snapshot whose patch number happens to be highest\n // would otherwise win the sort.\n const minorMatch = key.match(/^(\\d+)\\.(\\d+)$/);\n if (minorMatch && existsSync(cacheRoot)) {\n const [, major, minor] = minorMatch;\n const prefix = `${major}.${minor}.`;\n const cached = readdirSync(cacheRoot, { withFileTypes: true })\n .filter(\n e =>\n e.isDirectory() &&\n e.name.startsWith(prefix) &&\n !e.name.endsWith('.previous') &&\n /^\\d+\\.\\d+\\.\\d+$/.test(e.name)\n )\n .map(e => ({\n name: e.name,\n patch: parseInt(e.name.slice(prefix.length), 10),\n }))\n .filter(c => Number.isFinite(c.patch))\n .sort((a, b) => b.patch - a.patch);\n if (cached.length > 0) return path.join(cacheRoot, cached[0]!.name);\n }\n\n // For release-precision prerelease pins (`'3.1-beta'`, `'3.1-beta.0'`),\n // find the highest cached prerelease directory whose own release-precision\n // form starts with the requested key. A pin of `'3.1-beta'` matches any\n // directory whose `toReleasePrecisionWire` form is `'3.1-beta'` or\n // `'3.1-beta.*'`. A pin of `'3.1-beta.0'` matches `'3.1-beta.0'` or\n // `'3.1-beta.0.*'`. Sort newest-first by directory name with numeric\n // collation so rc.10 wins over rc.9.\n if (releasePrecisionMatch) {\n const cachePrereleaseCandidate = findPrereleaseBundle(cacheRoot, key);\n if (cachePrereleaseCandidate) return cachePrereleaseCandidate;\n }\n\n throw new Error(\n `AdCP schema data for version \"${version}\" not found. ` +\n `Looked for bundle key \"${key}\" in ${distCandidate}, exact path ${exactCandidate}, ` +\n `and the latest-patch fallback in ${cacheRoot}. ` +\n `Run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the bundle.`\n );\n}\n\nfunction findPrereleaseBundle(root: string, key: string): string | undefined {\n if (!existsSync(root)) return undefined;\n const cached = readdirSync(root, { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.endsWith('.previous'))\n .map(e => {\n try {\n return { name: e.name, rp: toReleasePrecisionWire(e.name) };\n } catch {\n return null;\n }\n })\n .filter((c): c is { name: string; rp: string } => c !== null)\n .filter(c => c.rp === key || c.rp.startsWith(`${key}.`))\n .sort((a, b) => compareBundleNamesDesc(a.name, b.name));\n if (cached.length === 0) return undefined;\n return path.join(root, cached[0]!.name);\n}\n\nfunction compareBundleNamesDesc(a: string, b: string): number {\n return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' });\n}\n\ninterface LoaderState {\n ajv: Ajv;\n fileIndex: Map<string, string>;\n validators: Map<string, ValidateFunction>;\n rawSchemas: Map<string, Record<string, unknown>>;\n entityPaths: Map<string, SchemaEntityPath[]>;\n schemaIdFiles?: Map<string, string>;\n root: string;\n coreLoaded: boolean;\n version: string;\n}\n\nconst states: Map<string, LoaderState> = new Map();\nconst externalSchemaRoots: Map<string, string> = new Map();\nconst scopedExternalSchemaRoots = new AsyncLocalStorage<Map<string, string>>();\n\nfunction stateCacheKey(bundleKey: string, root: string): string {\n return `${bundleKey}\\0${root}`;\n}\n\nfunction clearStatesForBundle(bundleKey: string): void {\n for (const [stateKey, state] of states) {\n if (state.version === bundleKey) states.delete(stateKey);\n }\n}\n\nfunction hasSchemaRootShape(root: string): boolean {\n if (!existsSync(root)) return false;\n const bundledRoot = path.join(root, 'bundled');\n const files = existsSync(bundledRoot) ? walkJsonFiles(bundledRoot) : walkJsonFiles(root);\n return files.some(file => {\n try {\n const schema = loadJson(file);\n return typeof schema.$id === 'string' || typeof schema.$schema === 'string';\n } catch {\n return false;\n }\n });\n}\n\nfunction schemaIdVersionHint(schemaId: string): string | undefined {\n return schemaId.match(/\\/schemas\\/([^/]+)\\//)?.[1];\n}\n\nfunction collectSchemaRootVersionAliases(root: string): Set<string> {\n const aliases = new Set<string>();\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n for (const alias of schemaRootVersionAliases(hint)) aliases.add(alias);\n }\n return aliases;\n}\n\nfunction schemaRootVersionAliases(version: string): Set<string> {\n const aliases = new Set<string>([version]);\n try {\n aliases.add(resolveBundleKey(version));\n } catch {\n // Keep the raw value only; callers that care will throw separately.\n }\n try {\n const releasePrecision = toReleasePrecisionWire(version);\n aliases.add(releasePrecision);\n const family = prereleaseFamilyAlias(releasePrecision);\n if (family) aliases.add(family);\n } catch {\n // Keep any aliases already collected.\n }\n return aliases;\n}\n\nfunction prereleaseFamilyAlias(releasePrecisionVersion: string): string | undefined {\n return releasePrecisionVersion.match(/^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/)?.[1];\n}\n\nfunction collectSchemaRootVersionAliasGroups(root: string): Array<{ hint: string; aliases: Set<string> }> {\n const groups: Array<{ hint: string; aliases: Set<string> }> = [];\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n groups.push({ hint, aliases: schemaRootVersionAliases(hint) });\n }\n return groups;\n}\n\nfunction assertSchemaRootMatchesVersion(version: string, root: string): Set<string> {\n const expectedAliases = schemaRootVersionAliases(version);\n const rootGroups = collectSchemaRootVersionAliasGroups(root);\n const rootAliases = collectSchemaRootVersionAliases(root);\n if (\n rootGroups.length > 0 &&\n rootGroups.every(group => [...group.aliases].some(alias => expectedAliases.has(alias)))\n ) {\n return new Set([...expectedAliases, ...rootAliases]);\n }\n const found =\n rootGroups.length === 0\n ? 'no AdCP schema ids'\n : rootGroups\n .map(group => `${group.hint} (${Array.from(group.aliases).sort().join(', ')})`)\n .sort()\n .join(', ');\n throw new Error(\n `External AdCP schema root for version \"${version}\" at ${root} does not match the requested version and ` +\n `must contain only schema ids matching ${Array.from(expectedAliases).sort().join(', ')}; found ${found}.`\n );\n}\n\nconst externalSchemaRootAliases: Map<string, Set<string>> = new Map();\n\n/**\n * Register a schema bundle supplied outside the installed SDK package.\n *\n * Compliance runners use this when `--compliance-dir` points at another\n * package/check-out whose storyboards and schema bundle should be used\n * together. The root must be the schema-data directory itself, e.g.\n * `.../dist/lib/schemas-data/3.0`.\n */\nexport function registerExternalSchemaRoot(version: string, root: string): void {\n const key = resolveBundleKey(version);\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n externalSchemaRootAliases.set(key, aliases);\n for (const alias of aliases) {\n const previous = externalSchemaRoots.get(alias);\n externalSchemaRoots.set(alias, root);\n if (previous !== root) clearStatesForBundle(alias);\n }\n}\n\n/** Test/helper hook for unregistering an external schema bundle. */\nexport function unregisterExternalSchemaRoot(version: string): void {\n const key = resolveBundleKey(version);\n const aliases = new Set(schemaRootVersionAliases(version));\n for (const [registeredKey, registeredAliases] of externalSchemaRootAliases) {\n if (\n registeredKey === key ||\n registeredAliases.has(key) ||\n [...aliases].some(alias => registeredAliases.has(alias))\n ) {\n for (const alias of registeredAliases) aliases.add(alias);\n externalSchemaRootAliases.delete(registeredKey);\n }\n }\n for (const alias of aliases) {\n externalSchemaRoots.delete(alias);\n clearStatesForBundle(alias);\n }\n}\n\n/**\n * Run a callback with an external schema root scoped to the current async\n * execution chain. Unlike `registerExternalSchemaRoot`, this does not poison\n * process-global validation state for later hosted/compliance runs.\n */\nexport function withExternalSchemaRoot<T>(version: string, root: string | undefined, fn: () => T): T {\n if (root === undefined) return fn();\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n const parent = scopedExternalSchemaRoots.getStore();\n const next = new Map(parent);\n for (const alias of aliases) {\n next.set(alias, root);\n clearStatesForBundle(alias);\n }\n return scopedExternalSchemaRoots.run(next, fn);\n}\n\nfunction walkJsonFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkJsonFiles(full));\n else if (entry.isFile() && entry.name.endsWith('.json')) out.push(full);\n }\n return out;\n}\n\nfunction loadJson(file: string): LoadedSchema {\n return JSON.parse(readFileSync(file, 'utf-8')) as LoadedSchema;\n}\n\n/**\n * Clear `additionalProperties: false` at the response root so envelope\n * fields (`replayed`, `context`, `ext`, and future envelope additions)\n * can ride alongside the tool-specific body — per security.mdx the\n * envelope is always extensible. Upstream bundled schemas pin\n * `additionalProperties: false` at the root on a handful of mutating\n * tools (the property-list family), which rejects envelope fields like\n * `replayed` that aren't declared in the tool-specific body.\n *\n * Scope is deliberately narrow: only the top-level object, plus each\n * direct branch of a root-level `oneOf` / `anyOf` / `allOf`. Nested\n * bodies stay strict so response-side drift detection still catches\n * typos inside `Product`, `Package`, `MediaBuy` etc. Applied only to\n * response variants; request schemas stay strict so outgoing drift\n * fails at the edge.\n */\nfunction relaxResponseRoot(schema: LoadedSchema): LoadedSchema {\n const clone = { ...schema };\n if (clone.additionalProperties === false) {\n clone.additionalProperties = true;\n }\n for (const key of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = clone[key];\n if (Array.isArray(branches)) {\n clone[key] = branches.map(branch => {\n if (!branch || typeof branch !== 'object') return branch;\n const branchClone = { ...(branch as Record<string, unknown>) };\n if (branchClone.additionalProperties === false) {\n branchClone.additionalProperties = true;\n }\n return branchClone;\n });\n }\n }\n return clone;\n}\n\nfunction getAjvRegisteredIds(ajv: Ajv): Set<string> {\n const internals = ajv as unknown as {\n schemas?: Record<string, unknown>;\n refs?: Record<string, unknown>;\n };\n return new Set([...Object.keys(internals.schemas ?? {}), ...Object.keys(internals.refs ?? {})]);\n}\n\n/**\n * Build the (toolName, direction) → file path index by scanning the schema\n * tree once. Runs eagerly at first validator lookup.\n */\nfunction buildFileIndex(root: string): Map<string, string> {\n const index = new Map<string, string>();\n const record = (toolName: string, direction: Direction, file: string): void => {\n index.set(`${toolName}::${direction}`, file);\n };\n\n // Sync request/response live in the pre-resolved bundled/ tree.\n const bundledRoot = path.join(root, 'bundled');\n for (const file of walkJsonFiles(bundledRoot)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n record(tool, 'sync', file);\n }\n }\n\n // Async variants AND domain schemas that ship flat (not pre-bundled) both\n // live in the per-domain directories. Walk each for sync request/response\n // files and async variant files. Skip `bundled/` (already indexed above)\n // and `core/` (pure $ref targets, no tools).\n //\n // Flat-tree domains include `governance/`, `brand/`, `account/`,\n // `content-standards/`, `property/`, `collection/` — their schemas are\n // NOT pre-resolved into `bundled/`, so a bundled-only walk would miss\n // every `check_governance` / `acquire_rights` / `creative_approval` /\n // `sync_governance` / `*_property_list` request-response pair. That gap\n // (flagged by the ad-tech-protocol reviewer on PR #831) would leave\n // protocol-wide-requirement-bearing tasks (idempotency_key pattern,\n // `format: uri` on `caller`) invisible to the strict-validation signal.\n // Register flat-tree sync pairs only when `bundled/` didn't already\n // index them, so pre-resolved schemas (with $refs already inlined) win\n // for any domain that ships both.\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (!isRuntimeSchemaDirectory(entry.name) || entry.name === 'core') continue;\n const domainDir = path.join(root, entry.name);\n for (const file of walkJsonFiles(domainDir)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-async-response-submitted')) {\n const tool = base.slice(0, -'-async-response-submitted'.length).replace(/-/g, '_');\n record(tool, 'submitted', file);\n } else if (base.endsWith('-async-response-working')) {\n const tool = base.slice(0, -'-async-response-working'.length).replace(/-/g, '_');\n record(tool, 'working', file);\n } else if (base.endsWith('-async-response-input-required')) {\n const tool = base.slice(0, -'-async-response-input-required'.length).replace(/-/g, '_');\n record(tool, 'input-required', file);\n } else if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::request`)) record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::sync`)) record(tool, 'sync', file);\n }\n }\n }\n\n return index;\n}\n\nfunction ensureInit(version: string): LoaderState {\n // States are keyed by bundle key, not by raw version string, so\n // `getValidator('foo', 'request', '3.0.0')` and the same call with\n // `'3.0.1'` share state — both resolve to bundle key `'3.0'` and the\n // same compiled AJV instance.\n const key = resolveBundleKey(version);\n const root = resolveSchemaRoot(version);\n const cacheKey = stateCacheKey(key, root);\n const cached = states.get(cacheKey);\n if (cached) return cached;\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n\n const state: LoaderState = {\n ajv,\n fileIndex: buildFileIndex(root),\n validators: new Map(),\n rawSchemas: new Map(),\n entityPaths: new Map(),\n root,\n coreLoaded: false,\n version: key,\n };\n states.set(cacheKey, state);\n return state;\n}\n\n/**\n * Lazily pre-register every non-tool JSON schema shipped with the SDK so\n * cross-domain `$ref`s compile. Async response variants and flat-tree\n * domain schemas `$ref` out to three classes of building-block schemas:\n *\n * - `core/` + `enums/` — shared primitives referenced by every domain.\n * - `pricing-options/`, `error-details/`, `extensions/` — stand-alone\n * fragment trees.\n * - Sibling fragments inside each domain directory — e.g.\n * `governance/audience-constraints.json` referenced by\n * `governance/sync-plans-request.json`, or `signals/*` fragments\n * referenced by `signals/activate-signal-*.json`.\n *\n * Walk every directory except `bundled/` (pre-resolved schemas with refs\n * already inlined). Response files that `buildFileIndex` registered as tools\n * are registered with `relaxResponseRoot` applied, matching `getValidator`.\n * The fileIndex check is stricter than a filename-suffix match:\n * building-block fragments like `core/pagination-response.json` end in\n * `-response.json` but aren't tools, so suffix-matching would wrongly treat\n * them as relaxable response roots.\n */\nfunction ensureCoreLoaded(s: LoaderState): void {\n if (s.coreLoaded) return;\n // Tool response files are pre-registered with the same response-root\n // relaxation `getValidator` would apply. This matters for the async response\n // union: `core/async-response-data.json` can `$ref` both async variants and\n // sync responses, so callers must not have to prewarm response validators\n // before compiling a request that references the union.\n //\n // Why this matters: bundles whose source tree doesn't include a `bundled/`\n // pre-resolved subtree (e.g. v2.5, where the spec ships flat schemas with\n // unresolved `$ref`s) classify fragments like `media-buy/package-request.json`\n // as tool `package::request` via the filename-suffix heuristic in\n // `buildFileIndex`. Skipping all tool files would leave that fragment\n // unregistered, so a later compile of `create_media_buy` fails on\n // `MissingRefError: can't resolve /schemas/media-buy/package-request.json`.\n //\n const responseToolFiles = new Map<string, Direction>();\n for (const [key, file] of s.fileIndex) {\n if (key.endsWith('::request')) continue;\n const direction = key.slice(key.indexOf('::') + 2) as Direction;\n responseToolFiles.set(file, direction);\n }\n const registeredIds = getAjvRegisteredIds(s.ajv);\n for (const entry of readdirSync(s.root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (!isRuntimeSchemaDirectory(entry.name)) continue;\n const abs = path.join(s.root, entry.name);\n for (const file of walkJsonFiles(abs)) {\n const responseDirection = responseToolFiles.get(file);\n const schema = loadJson(file);\n const schemaToRegister = responseDirection === undefined ? schema : relaxResponseRoot(schema);\n if (typeof schemaToRegister.$id === 'string' && !registeredIds.has(schemaToRegister.$id)) {\n s.ajv.addSchema(schemaToRegister);\n registeredIds.add(schemaToRegister.$id);\n }\n }\n }\n s.coreLoaded = true;\n}\n\n/**\n * Look up the compiled AJV validator for a given tool + direction in the\n * specified AdCP version's schema bundle. Returns `undefined` when no\n * schema exists for the pair — callers can skip validation cleanly (e.g.,\n * custom tools outside the AdCP spec).\n *\n * `version` defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance\n * `getAdcpVersion()` value when the validator should track the client/server's\n * configured pin (Stage 3+).\n */\nexport function getValidator(\n toolName: string,\n direction: Direction,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::${direction}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = s.fileIndex.get(cacheKey);\n if (!file) return undefined;\n\n // Schemas that $ref into core/ and enums/ need those trees registered\n // before compile. Async response variants always do; flat-tree domain\n // schemas (anything outside `bundled/`) do too — their $refs weren't\n // pre-resolved at spec-publish time.\n const fromBundled = file.includes(`${path.sep}bundled${path.sep}`);\n if (direction === 'request' || !fromBundled) ensureCoreLoaded(s);\n\n const rawSchema = loadJson(file);\n // Bundled files inline every referenced subschema with the original\n // canonical `$id` (e.g. `core/version-envelope.json` appears nested\n // inside every bundled tool response). Bundled files carry NO\n // internal `$ref`s — the spec publishes them fully resolved, see\n // the `note: \"This is a bundled schema with all $ref resolved inline\"`\n // tag on every bundled file. Once `ensureCoreLoaded` has registered\n // any of those core schemas standalone (which it does for the flat-\n // tree governance / brand / property domains), Ajv's compile of a\n // bundled file trips the ambiguous-ref check on every nested $id.\n //\n // The fix: strip nested `$id` fields before compile on bundled\n // schemas. The root `$id` is kept (it's the validator's lookup key);\n // every other `$id` in the tree was just metadata anyway.\n const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;\n const schema = direction === 'request' ? prepared : relaxResponseRoot(prepared);\n const existing = typeof schema.$id === 'string' ? s.ajv.getSchema(schema.$id) : undefined;\n const compiled = existing ?? s.ajv.compile(schema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\n/**\n * Compile an arbitrary schema from the cached bundle by path, e.g.\n * `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions\n * whose payload schema is not tied to a tool request/response pair.\n */\nexport function getSchemaValidatorByRef(\n schemaRef: string,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n // Use an isolated AJV instance for arbitrary schema refs. Tool response\n // validators deliberately relax some roots for SDK back-compat; webhook\n // payload schemas need strict raw JSON Schema behavior without polluting the\n // shared tool-validator registry with unrelaxed response schemas.\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n const dependencySchemas: LoadedSchema[] = [];\n const registeredIds = new Set<string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n if (schemaFile.includes(`${path.sep}bundled${path.sep}`)) continue;\n if (\n [...TRANSPORT_PROJECTION_DIRECTORIES].some(directory => schemaFile.includes(`${path.sep}${directory}${path.sep}`))\n ) {\n continue;\n }\n if (schemaFile === file) continue;\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string' && !registeredIds.has(schema.$id)) {\n registeredIds.add(schema.$id);\n dependencySchemas.push(schema);\n }\n }\n if (dependencySchemas.length > 0) {\n ajv.addSchema(dependencySchemas);\n }\n const rawSchema = loadJson(file);\n const compiled = ajv.compile(rawSchema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\nfunction normalizeSchemaRef(schemaRef: string): string | undefined {\n const trimmed = schemaRef.replace(/^\\/+/, '');\n if (trimmed.length === 0) return undefined;\n const normalized = path.normalize(trimmed);\n if (normalized.startsWith('..') || path.isAbsolute(normalized)) return undefined;\n return normalized;\n}\n\n/**\n * Strip `$id` from every subschema of a bundled response file, preserving\n * the root `$id`. Bundled files are fully inlined (no internal `$ref`s),\n * so the nested `$id`s are vestigial metadata — Ajv only cares about the\n * root `$id` for validator lookup. Without this strip, Ajv's\n * `checkAmbiguousRef` throws when an inlined nested `$id` matches one\n * already registered standalone via `ensureCoreLoaded`.\n *\n * Returns a deep-copied tree; the input is not mutated.\n */\nfunction stripNestedIds(schema: LoadedSchema): LoadedSchema {\n const root = JSON.parse(JSON.stringify(schema)) as LoadedSchema;\n const rootId = typeof root.$id === 'string' ? root.$id : undefined;\n const walk = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n if (!node || typeof node !== 'object') return;\n const obj = node as Record<string, unknown>;\n if (typeof obj.$id === 'string' && obj.$id !== rootId) {\n delete obj.$id;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(root);\n return root;\n}\n\n/** List of (toolName, direction) pairs that have schemas. Used by tests. */\nexport function listValidatorKeys(version: string = ADCP_VERSION): string[] {\n const s = ensureInit(version);\n return [...s.fileIndex.keys()].sort();\n}\n\n/**\n * `$id`s of every schema currently registered with the AdCP validator's AJV\n * instance for `version`. Used by the schema-validator to extract the\n * rejecting sub-schema's `$id` from an Ajv error's `schemaPath`: when a\n * `$ref` is followed, Ajv prefixes the schemaPath with the target schema's\n * `$id`, so the longest registered `$id` that prefixes a schemaPath is the\n * sub-schema responsible for the failure.\n *\n * The set grows as `getValidator` calls trigger `ensureCoreLoaded` and\n * compile new tool roots — callers should read it AFTER the validate call\n * they're projecting errors from.\n */\nexport function getRegisteredSchemaIds(version: string = ADCP_VERSION): readonly string[] {\n const s = ensureInit(version);\n // Ajv 8 keeps registered schemas at `ajv.schemas` (URI → SchemaEnv). Returning\n // the keys is enough for prefix matching; we don't expose the SchemaEnv values.\n const registry = (s.ajv as unknown as { schemas?: Record<string, unknown> }).schemas;\n return registry ? Object.keys(registry) : [];\n}\n\n/** Suffix used in the suffix table — exported for testing. */\nexport { SCHEMA_FILENAME_SUFFIX };\n\n/**\n * Returns true when the schema bundle for `version` is reachable from the\n * dist build or the source-tree fallback. Cheap synchronous check; safe\n * to call at construction time of clients/servers to fail fast on a pin\n * we don't have schemas for.\n */\nexport function hasSchemaBundle(version: string): boolean {\n try {\n resolveSchemaRoot(version);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Test hook: reset cached state. With no argument, clears every version's\n * loader state; with a version, clears only the bundle that version\n * resolves to (so passing `'3.0.0'` and `'3.0.1'` both clear the `'3.0'`\n * bundle).\n */\nexport function _resetValidationLoader(version?: string): void {\n if (version === undefined) {\n states.clear();\n } else {\n clearStatesForBundle(resolveBundleKey(version));\n }\n}\n\n/**\n * Returns true when `field` is **explicitly declared** as a top-level property\n * in the request schema for `toolName`, or when no schema is available\n * (fail-open). Used by the storyboard runner to decide whether to inject\n * envelope fields that aren't universally present across tools (e.g. `brand`,\n * `account`, `ext`).\n *\n * Reads the raw JSON schema file without compiling — avoids coupling to AJV\n * internals. Only inspects the top-level `properties` map; nested sub-schemas\n * are not traversed. Results are memoized in `LoaderState.rawSchemas` so\n * multi-step storyboard runs don't re-read the same file on each step.\n *\n * **Semantic note**: AdCP 3.1.0-beta.3 set `additionalProperties: true` on\n * mutating request schemas (vendor-extension friendly). Before that flip, the\n * helper used `additionalProperties: false` as the gate — \"if the schema is\n * strict, only `properties` keys are allowed.\" Now requests are universally\n * permissive at the schema level, so that gate would say `true` for any field\n * on any request — defeating the storyboard runner's intent (\"only inject\n * envelope fields the tool's schema declares it expects to see\"). The helper\n * now checks `field in properties` directly: the question we actually care\n * about is **\"does the schema declare this field at top level?\"**, not\n * \"does the schema permit this field at top level?\" (it permits everything).\n *\n * Fails open (returns `true`) when:\n * - No schema file is indexed for the tool (custom tool, schema not synced)\n * - The schema root is not reachable (schemas not built/synced yet)\n * - Any I/O / parse error during the read\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function schemaAllowsTopLevelField(toolName: string, field: string, version: string = ADCP_VERSION): boolean {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return true;\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n const props = schema.properties as Record<string, unknown> | undefined;\n return props !== undefined && field in props;\n } catch {\n return true;\n }\n}\n\nexport interface SchemaEntityPath {\n /** Property path from the tool request root. `*` addresses every array item. */\n path: string[];\n /** AdCP `x-entity` annotation found on the identity-bearing leaf. */\n xEntity: string;\n}\n\n/**\n * Return every request field carrying an `x-entity` annotation. Unlike the\n * server hydration map this walks nested arrays/objects, because storyboard\n * fixture handles commonly live at `packages[*].product_id` and\n * `packages[*].pricing_option_id`.\n *\n * Missing schemas fail closed with an empty list: handle substitution must\n * never guess from a field name alone.\n */\nexport function getRequestSchemaEntityPaths(\n toolName: string,\n version: string = ADCP_VERSION\n): readonly SchemaEntityPath[] {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const cached = s.entityPaths.get(cacheKey);\n if (cached) return cached;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return [];\n\n const root = loadJson(file) as Record<string, unknown>;\n const found = new Map<string, SchemaEntityPath>();\n const stack = new Set<string>();\n\n const resolvePointer = (document: unknown, fragment: string): unknown => {\n if (!fragment || fragment === '#') return document;\n if (!fragment.startsWith('#/')) return undefined;\n let current = document;\n for (const encoded of fragment.slice(2).split('/')) {\n if (!current || typeof current !== 'object') return undefined;\n const key = encoded.replace(/~1/g, '/').replace(/~0/g, '~');\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n };\n\n const resolveRef = (\n ref: string,\n currentFile: string,\n currentDocument: Record<string, unknown>\n ): { node: unknown; file: string; document: Record<string, unknown>; key: string } | undefined => {\n const hash = ref.indexOf('#');\n const refPath = hash >= 0 ? ref.slice(0, hash) : ref;\n const fragment = hash >= 0 ? ref.slice(hash) : '';\n if (!refPath) {\n return {\n node: resolvePointer(currentDocument, fragment),\n file: currentFile,\n document: currentDocument,\n key: `${currentFile}${fragment}`,\n };\n }\n\n const schemaRelative = refPath.match(/\\/schemas\\/[^/]+\\/(.+)$/)?.[1];\n const candidates = [\n schemaRelative ? path.join(s.root, schemaRelative) : undefined,\n path.resolve(path.dirname(currentFile), refPath),\n ].filter((candidate): candidate is string => candidate !== undefined);\n let targetFile = candidates.find(candidate => existsSync(candidate));\n // Standard AdCP refs encode their schema-root-relative file path, so\n // they resolve without parsing every JSON file in the bundle. Build the\n // expensive $id index only for an unusual ref that cannot be resolved\n // by path.\n if (!targetFile) {\n if (!s.schemaIdFiles) {\n const idToFile = new Map<string, string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n try {\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string') idToFile.set(schema.$id, schemaFile);\n } catch {\n // A malformed unrelated schema is not a usable ref target.\n }\n }\n s.schemaIdFiles = idToFile;\n }\n targetFile = s.schemaIdFiles.get(refPath);\n }\n if (!targetFile) return undefined;\n const document = loadJson(targetFile) as Record<string, unknown>;\n return {\n node: resolvePointer(document, fragment),\n file: targetFile,\n document,\n key: `${targetFile}${fragment}`,\n };\n };\n\n const walk = (\n node: unknown,\n propertyPath: string[],\n currentFile: string,\n currentDocument: Record<string, unknown>,\n depth: number\n ): void => {\n if (!node || typeof node !== 'object' || depth > 48) return;\n const obj = node as Record<string, unknown>;\n if (typeof obj['x-entity'] === 'string' && propertyPath.length > 0) {\n const entityPath = { path: [...propertyPath], xEntity: obj['x-entity'] as string };\n found.set(`${entityPath.path.join('.')}\\0${entityPath.xEntity}`, entityPath);\n }\n\n if (typeof obj.$ref === 'string') {\n const target = resolveRef(obj.$ref, currentFile, currentDocument);\n if (target && target.node !== undefined) {\n const guard = `${target.key}\\0${propertyPath.join('.')}`;\n if (!stack.has(guard)) {\n stack.add(guard);\n walk(target.node, propertyPath, target.file, target.document, depth + 1);\n stack.delete(guard);\n }\n }\n }\n\n const properties = obj.properties;\n if (properties && typeof properties === 'object' && !Array.isArray(properties)) {\n for (const [key, child] of Object.entries(properties as Record<string, unknown>)) {\n walk(child, [...propertyPath, key], currentFile, currentDocument, depth + 1);\n }\n }\n if (obj.items !== undefined) {\n walk(obj.items, [...propertyPath, '*'], currentFile, currentDocument, depth + 1);\n }\n for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = obj[keyword];\n if (Array.isArray(branches)) {\n for (const branch of branches) walk(branch, propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n for (const keyword of ['if', 'then', 'else', 'not'] as const) {\n if (obj[keyword] !== undefined) {\n walk(obj[keyword], propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n };\n\n walk(root, [], file, root, 0);\n const result = [...found.values()].sort((a, b) => {\n const byPath = a.path.join('.').localeCompare(b.path.join('.'));\n return byPath || a.xEntity.localeCompare(b.xEntity);\n });\n s.entityPaths.set(cacheKey, result);\n return result;\n } catch {\n return [];\n }\n}\n\n/**\n * Resolve a JSON Schema `default` value by walking a dot-separated property\n * path through a schema's nested `properties` maps.\n *\n * This intentionally does not instantiate AJV's `useDefaults` mutation mode.\n * Callers decide when a schema default is semantically meaningful for their\n * runtime object; this helper only reports what the bundled schema declares.\n *\n * Fails closed (`undefined`) when the schema is unavailable, the path is not a\n * concrete properties path, or the target schema node has no `default`.\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function getSchemaDefaultByPath(schemaRef: string, dottedPath: string, version: string = ADCP_VERSION): unknown {\n try {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n\n const node = resolveSchemaPropertyPath(schema, dottedPath);\n if (!node || !Object.prototype.hasOwnProperty.call(node, 'default')) return undefined;\n return cloneJsonValue((node as { default: unknown }).default);\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSchemaPropertyPath(\n schema: Record<string, unknown>,\n dottedPath: string\n): Record<string, unknown> | undefined {\n let current: unknown = schema;\n for (const key of dottedPath.split('.')) {\n if (!current || typeof current !== 'object') return undefined;\n const props = (current as Record<string, unknown>).properties;\n if (!props || typeof props !== 'object') return undefined;\n if (!Object.prototype.hasOwnProperty.call(props, key)) return undefined;\n current = (props as Record<string, unknown>)[key];\n }\n return current && typeof current === 'object' ? (current as Record<string, unknown>) : undefined;\n}\n\nfunction cloneJsonValue(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n return JSON.parse(JSON.stringify(value)) as unknown;\n}\n"],"mappings":"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","names":["path","Ajv","addFormats"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/validation/schema-loader.ts"],"sourcesContent":["/**\n * JSON Schema loader for AdCP tool request/response validation.\n *\n * Loads the bundled per-tool schemas shipped with the SDK plus the\n * `core/` schemas that async response variants `$ref`, then compiles\n * AJV validators lazily by `(toolName, direction)`.\n *\n * Stage 3: state is per-AdCP-version. The same SDK instance can hold\n * compiled validators for `3.0.0`, `3.0.1`, `3.1.0-beta.1`, etc. side by\n * side; callers pass the version they're validating against. Default is\n * the SDK-pinned `ADCP_VERSION` so callers that don't care about\n * cross-version selection (most internal call sites) keep working\n * unchanged.\n */\n\nimport Ajv, { type ValidateFunction } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { readdirSync, readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { ADCP_VERSION } from '../version';\nimport { ConfigurationError } from '../errors';\n\nexport type ResponseVariant = 'sync' | 'submitted' | 'working' | 'input-required';\nexport type Direction = 'request' | ResponseVariant;\n\ninterface LoadedSchema {\n $id?: string;\n [k: string]: unknown;\n}\n\nconst SCHEMA_FILENAME_SUFFIX: Record<Direction, string> = {\n request: 'request',\n sync: 'response',\n submitted: 'async-response-submitted',\n working: 'async-response-working',\n 'input-required': 'async-response-input-required',\n};\n\n// Protocol bundles may ship transport-specific schema projections alongside\n// the canonical AdCP schemas. They are not runtime validation sources: the\n// official clients own transport framing, while this loader validates the\n// canonical tool arguments/results. AdCP 3.2's `mcp/2026-07-28` projection\n// also uses JSON Schema 2020-12, whereas the canonical bundle remains\n// Draft-07. Mixing it into the canonical AJV registry both indexes duplicate\n// tools and makes a Draft-07 instance attempt to register another dialect.\nconst TRANSPORT_PROJECTION_DIRECTORIES = new Set(['mcp']);\n\nfunction isRuntimeSchemaDirectory(name: string): boolean {\n return name !== 'bundled' && !TRANSPORT_PROJECTION_DIRECTORIES.has(name);\n}\n\n/**\n * Map a consumer-provided version pin to the loader's bundle key.\n *\n * - Stable semver `'3.0.0'` / `'3.0.1'` → `'3.0'` (latest patch in minor)\n * - Bare minor `'3.0'` → `'3.0'` (already the bundle key)\n * - Release-precision prerelease `'3.1-beta'` / `'3.1-beta.0'` →\n * returned verbatim. {@link resolveSchemaRoot} fuzzy-resolves to the\n * highest cached prerelease directory whose own release-precision form\n * matches (e.g. `'3.1-beta'` matches `schemas/cache/3.1.0-beta.0/`).\n * Accepted because sellers advertise `supported_versions` in this\n * shape (`[\"3.1-beta\"]`), and a buyer reading that off the wire must\n * be able to pin to it.\n * - Full prerelease semver `'3.1.0-beta.1'` → `'3.1.0-beta.1'`\n * (exact-version, intentional pin)\n * - Legacy alias `'v3'` / `'v2.5'` / `'v2.6'` → returned verbatim (cache\n * historically keyed these directories by the alias name)\n *\n * Per the AdCP spec convention patches don't change wire shape, so collapsing\n * stable patches into the minor is functionally equivalent for any validator\n * consumer. Prereleases are kept exact because pinning a beta is intentional\n * and bit-fidelity matters for cross-version interop tests.\n *\n * Throws `ConfigurationError` for any input that doesn't match one of the\n * recognized shapes. Strings reach `path.join` via `resolveSchemaRoot`, and\n * pass-through of arbitrary garbage (`'../etc'`, `'3foo'`) lets a non-version\n * directory probe leak through `hasSchemaBundle`'s boolean. The throw is\n * caught by `hasSchemaBundle`'s try/catch (still returns false) and surfaces\n * with a useful field name from `resolveAdcpVersion`.\n */\nexport function resolveBundleKey(version: string): string {\n // Bare 'MAJOR.MINOR' (no patch).\n const minorOnly = version.match(/^(\\d+)\\.(\\d+)$/);\n if (minorOnly) return `${minorOnly[1]}.${minorOnly[2]}`;\n // Release-precision prerelease 'MAJOR.MINOR-PRE' (no patch). Same SemVer §9\n // prerelease constraint as the full-semver branch — `'3.1-/../etc'`-style\n // strings can't slip through. Returns verbatim; resolveSchemaRoot does the\n // fuzzy directory match.\n const releasePrecisionPre = version.match(/^(\\d+)\\.(\\d+)-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*$/);\n if (releasePrecisionPre) return version;\n // Full 'MAJOR.MINOR.PATCH' with optional prerelease. Prerelease group\n // restricted to SemVer §9 identifiers (alphanumerics + hyphen,\n // dot-separated) so `'3.0.0-/../etc'`-style strings can't slip through\n // and reach `path.join` as a directory component. The full version is\n // returned verbatim for prereleases, so this is the last line of defense\n // before that string becomes a path segment.\n const semver = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$/);\n if (semver) {\n const [, major, minor, , prerelease] = semver;\n if (prerelease !== undefined) return version;\n return `${major}.${minor}`;\n }\n // Legacy alias: 'v' followed by a major and optional minor. Restricted to\n // this exact shape so non-version garbage can't reach the filesystem.\n const legacyAlias = version.match(/^v\\d+(\\.\\d+)?$/);\n if (legacyAlias) return version;\n throw new ConfigurationError(\n `AdCP version ${JSON.stringify(version)} is not a recognized version format. ` +\n `Expected semver (e.g. '3.0.1', '3.1.0-beta.1'), bare minor ('3.0'), ` +\n `release-precision ('3.1-beta'), or legacy alias ('v3', 'v2.5').`,\n 'adcpVersion'\n );\n}\n\n/**\n * Collapse a bundle key to the release-precision string the AdCP wire schema\n * accepts for the `adcp_version` envelope field (spec PR\n * `adcontextprotocol/adcp#3493`). The wire pattern is\n * `^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$` — release-precision (MAJOR.MINOR with\n * optional prerelease), never full MAJOR.MINOR.PATCH semver.\n *\n * - Stable bundle key `'3.0'` / `'3.1'` → returned verbatim.\n * - Prerelease bundle key `'3.1.0-beta.0'` → `'3.1-beta.0'` (PATCH segment\n * dropped; the prerelease tag is the wire-meaningful release identifier,\n * PATCH is implementation-internal).\n * - Full stable semver `'3.0.11'` → `'3.0'` (patches don't change wire\n * shape; surface them via `build_version` on capabilities instead).\n * - Legacy alias `'v3'` / `'v2.5'` — returned verbatim. The wire spec\n * predates the envelope field, so legacy-aliased clients won't emit\n * `adcp_version` anyway (gated by `bundleSupportsAdcpVersionField`).\n *\n * The normalization rule is declared in `core/version-envelope.json`:\n *\n * > SDKs that read full-semver values from bundle metadata (e.g.\n * > ComplianceIndex.published_version = \"3.1.0-beta.1\") MUST normalize to\n * > release-precision (\"3.1-beta.1\") before emitting on the wire —\n * > meta-field values are NOT valid wire values.\n *\n * **Idempotent.** Re-applying to an already-wire-shaped value is a no-op:\n * `toReleasePrecisionWire('3.1-beta.0') === '3.1-beta.0'`. Safe to call\n * defensively on values a caller read off the wire and is passing back.\n *\n * **Prerelease regex is stricter than the wire pattern by design.** The wire\n * pattern allows `[a-zA-Z0-9.-]+` (any mix of dots and hyphens), but this\n * function only accepts SemVer §9-shaped prerelease tags\n * (`[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*`) — disallowing leading dots, double\n * dots, or trailing dots. Mirrors the path-traversal hardening on\n * {@link resolveBundleKey} (`'3.0.0-/../etc'`-style strings can't reach the\n * filesystem there, and shouldn't be silently mirrored to the wire here).\n * A future reader who wants to \"fix\" this to match the wire regex\n * character-for-character should NOT — the strictness is intentional.\n *\n * Defense: rejecting unrecognized shapes here surfaces SDK-internal misuse\n * (someone calling this with raw garbage) loudly instead of silently\n * emitting a non-spec wire string.\n */\n/**\n * The exact pattern `core/version-envelope.json` applies to `adcp_version`\n * on the wire. Kept verbatim so {@link validateAdcpVersionWire} doesn't\n * drift from the spec — bump only when the spec itself bumps.\n */\nconst ADCP_VERSION_WIRE_PATTERN = /^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n\n/**\n * Validate a string against the AdCP 3.1 `adcp_version` wire pattern.\n * Throws `ConfigurationError` with a hint that points at\n * {@link toReleasePrecisionWire} when the value would be sent on the wire\n * but doesn't satisfy `core/version-envelope.json`'s pattern.\n *\n * Use this when you're constructing a request envelope by hand (storyboard\n * fixtures, conformance harnesses, custom transports) and want a clear\n * error rather than a downstream AJV pattern-mismatch from the seller —\n * by the time the seller rejects the request, the buyer's stack frame is\n * long gone and `core/version-envelope.json/properties/adcp_version/pattern`\n * is the only clue.\n *\n * The SDK's own `buildVersionEnvelope` calls this as a postcondition after\n * normalizing the bundle key — should never throw in well-formed SDK code,\n * but if a future refactor breaks the normalization the assertion fires\n * with a message that names the helper to call.\n *\n * Returns the value with the type narrowed to `string` via assertion.\n */\nexport function validateAdcpVersionWire(value: unknown): asserts value is string {\n if (typeof value !== 'string') {\n throw new ConfigurationError(\n `adcp_version must be a string. Got ${typeof value}. ` +\n `Use toReleasePrecisionWire() to convert a bundle key or full-semver pin to a wire-shaped string.`,\n 'adcp_version'\n );\n }\n if (!ADCP_VERSION_WIRE_PATTERN.test(value)) {\n throw new ConfigurationError(\n `adcp_version ${JSON.stringify(value)} doesn't match the AdCP 3.1 wire pattern ${ADCP_VERSION_WIRE_PATTERN}. ` +\n `Full-semver bundle keys (e.g. \"3.1.0-beta.0\") are NOT valid wire values — ` +\n `call toReleasePrecisionWire() to normalize (e.g. \"3.1.0-beta.0\" → \"3.1-beta.0\").`,\n 'adcp_version'\n );\n }\n}\n\nexport function toReleasePrecisionWire(bundleKeyOrVersion: string): string {\n // Bare release-precision (MAJOR.MINOR or MAJOR.MINOR-PRE) — already wire-shaped.\n const releasePrecision = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (releasePrecision) {\n const [, major, minor, prerelease = ''] = releasePrecision;\n return `${major}.${minor}${prerelease}`;\n }\n // Full semver — collapse PATCH segment. Prerelease (if any) is preserved.\n const fullSemver = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)\\.\\d+(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (fullSemver) {\n const [, major, minor, prerelease = ''] = fullSemver;\n return `${major}.${minor}${prerelease}`;\n }\n // Legacy alias passthrough. Callers that reach here with a legacy alias\n // shouldn't be emitting `adcp_version` (no version-envelope support), but\n // returning the input verbatim is least-surprise.\n if (/^v\\d+(\\.\\d+)?$/.test(bundleKeyOrVersion)) return bundleKeyOrVersion;\n throw new ConfigurationError(\n `Cannot normalize ${JSON.stringify(bundleKeyOrVersion)} to release-precision wire format. ` +\n `Expected a bundle key or AdCP version string.`,\n 'adcpVersion'\n );\n}\n\n/**\n * Resolve the directory that holds the bundled + core schemas for a given\n * AdCP version. Source layout (dev):\n * schemas/cache/<exact-version>/{bundled,core}\n * Built layout (dist):\n * dist/lib/schemas-data/<bundle-key>/{bundled,core}\n *\n * Stable releases use minor-name keys (`3.0/`); prereleases use full-version\n * keys (`3.1.0-beta.1/`). See {@link resolveBundleKey}.\n *\n * Falls back to the source-tree cache when dist isn't built (dev workflow\n * before `npm run build:lib`). For stable pins, the cache fallback scans\n * for the highest-patch sibling in the requested minor — `'3.0.0'` resolves\n * to `schemas/cache/3.0.1/` when only `3.0.1` is cached, matching dist's\n * collapse behavior.\n *\n * Throws when no bundle exists. Callers pinning a specific prerelease\n * surface the error; the construction-time fence in `resolveAdcpVersion`\n * catches most cross-major mistakes before this point.\n */\nfunction resolveSchemaRoot(version: string): string {\n const key = resolveBundleKey(version);\n const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);\n if (scopedRoot && existsSync(scopedRoot)) return scopedRoot;\n\n const externalRoot = externalSchemaRoots.get(key);\n if (externalRoot && existsSync(externalRoot)) return externalRoot;\n\n const distCandidate = path.join(__dirname, '..', 'schemas-data', key);\n if (existsSync(distCandidate)) return distCandidate;\n\n // Published builds carry exact prerelease bundle directories\n // (`3.1.0-rc.1/`), while callers may pin the release-precision family\n // alias (`3.1-rc`). Resolve that alias before falling back to source cache.\n const releasePrecisionMatch = /^\\d+\\.\\d+-/.test(key);\n if (releasePrecisionMatch) {\n const distPrereleaseCandidate = findPrereleaseBundle(path.join(__dirname, '..', 'schemas-data'), key);\n if (distPrereleaseCandidate) return distPrereleaseCandidate;\n }\n\n // Source-tree fallback: cache stays exact-version-named, so map the key\n // back to the highest-patch cache directory in the same minor for stable\n // pins. Prereleases need an exact match.\n const cacheRoot = path.join(__dirname, '..', '..', '..', 'schemas', 'cache');\n const exactCandidate = path.join(cacheRoot, version);\n if (existsSync(exactCandidate)) return exactCandidate;\n\n // For minor-only or stable-patch pins, find the highest stable patch in\n // the cache that matches the resolved minor. Skip `*.previous` snapshots\n // — `sync-schemas` writes those as transient backups during replaceTree;\n // a partially-written snapshot whose patch number happens to be highest\n // would otherwise win the sort.\n const minorMatch = key.match(/^(\\d+)\\.(\\d+)$/);\n if (minorMatch && existsSync(cacheRoot)) {\n const [, major, minor] = minorMatch;\n const prefix = `${major}.${minor}.`;\n const cached = readdirSync(cacheRoot, { withFileTypes: true })\n .filter(\n e =>\n e.isDirectory() &&\n e.name.startsWith(prefix) &&\n !e.name.endsWith('.previous') &&\n /^\\d+\\.\\d+\\.\\d+$/.test(e.name)\n )\n .map(e => ({\n name: e.name,\n patch: parseInt(e.name.slice(prefix.length), 10),\n }))\n .filter(c => Number.isFinite(c.patch))\n .sort((a, b) => b.patch - a.patch);\n if (cached.length > 0) return path.join(cacheRoot, cached[0]!.name);\n }\n\n // For release-precision prerelease pins (`'3.1-beta'`, `'3.1-beta.0'`),\n // find the highest cached prerelease directory whose own release-precision\n // form starts with the requested key. A pin of `'3.1-beta'` matches any\n // directory whose `toReleasePrecisionWire` form is `'3.1-beta'` or\n // `'3.1-beta.*'`. A pin of `'3.1-beta.0'` matches `'3.1-beta.0'` or\n // `'3.1-beta.0.*'`. Sort newest-first by directory name with numeric\n // collation so rc.10 wins over rc.9.\n if (releasePrecisionMatch) {\n const cachePrereleaseCandidate = findPrereleaseBundle(cacheRoot, key);\n if (cachePrereleaseCandidate) return cachePrereleaseCandidate;\n }\n\n throw new Error(\n `AdCP schema data for version \"${version}\" not found. ` +\n `Looked for bundle key \"${key}\" in ${distCandidate}, exact path ${exactCandidate}, ` +\n `and the latest-patch fallback in ${cacheRoot}. ` +\n `Run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the bundle.`\n );\n}\n\nfunction findPrereleaseBundle(root: string, key: string): string | undefined {\n if (!existsSync(root)) return undefined;\n const cached = readdirSync(root, { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.endsWith('.previous'))\n .map(e => {\n try {\n return { name: e.name, rp: toReleasePrecisionWire(e.name) };\n } catch {\n return null;\n }\n })\n .filter((c): c is { name: string; rp: string } => c !== null)\n .filter(c => c.rp === key || c.rp.startsWith(`${key}.`))\n .sort((a, b) => compareBundleNamesDesc(a.name, b.name));\n if (cached.length === 0) return undefined;\n return path.join(root, cached[0]!.name);\n}\n\nfunction compareBundleNamesDesc(a: string, b: string): number {\n return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' });\n}\n\ninterface LoaderState {\n ajv: Ajv;\n fileIndex: Map<string, string>;\n validators: Map<string, ValidateFunction>;\n rawSchemas: Map<string, Record<string, unknown>>;\n entityPaths: Map<string, SchemaEntityPath[]>;\n schemaIdFiles?: Map<string, string>;\n root: string;\n coreLoaded: boolean;\n version: string;\n}\n\nconst states: Map<string, LoaderState> = new Map();\nconst externalSchemaRoots: Map<string, string> = new Map();\nconst scopedExternalSchemaRoots = new AsyncLocalStorage<Map<string, string>>();\n\nfunction stateCacheKey(bundleKey: string, root: string): string {\n return `${bundleKey}\\0${root}`;\n}\n\nfunction clearStatesForBundle(bundleKey: string): void {\n for (const [stateKey, state] of states) {\n if (state.version === bundleKey) states.delete(stateKey);\n }\n}\n\nfunction hasSchemaRootShape(root: string): boolean {\n if (!existsSync(root)) return false;\n const bundledRoot = path.join(root, 'bundled');\n const files = existsSync(bundledRoot) ? walkJsonFiles(bundledRoot) : walkJsonFiles(root);\n return files.some(file => {\n try {\n const schema = loadJson(file);\n return typeof schema.$id === 'string' || typeof schema.$schema === 'string';\n } catch {\n return false;\n }\n });\n}\n\nfunction schemaIdVersionHint(schemaId: string): string | undefined {\n return schemaId.match(/\\/schemas\\/([^/]+)\\//)?.[1];\n}\n\nfunction collectSchemaRootVersionAliases(root: string): Set<string> {\n const aliases = new Set<string>();\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n for (const alias of schemaRootVersionAliases(hint)) aliases.add(alias);\n }\n return aliases;\n}\n\nfunction schemaRootVersionAliases(version: string): Set<string> {\n const aliases = new Set<string>([version]);\n try {\n aliases.add(resolveBundleKey(version));\n } catch {\n // Keep the raw value only; callers that care will throw separately.\n }\n try {\n const releasePrecision = toReleasePrecisionWire(version);\n aliases.add(releasePrecision);\n const family = prereleaseFamilyAlias(releasePrecision);\n if (family) aliases.add(family);\n } catch {\n // Keep any aliases already collected.\n }\n return aliases;\n}\n\nfunction prereleaseFamilyAlias(releasePrecisionVersion: string): string | undefined {\n return releasePrecisionVersion.match(/^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/)?.[1];\n}\n\nfunction collectSchemaRootVersionAliasGroups(root: string): Array<{ hint: string; aliases: Set<string> }> {\n const groups: Array<{ hint: string; aliases: Set<string> }> = [];\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n groups.push({ hint, aliases: schemaRootVersionAliases(hint) });\n }\n return groups;\n}\n\nfunction assertSchemaRootMatchesVersion(version: string, root: string): Set<string> {\n const expectedAliases = schemaRootVersionAliases(version);\n const rootGroups = collectSchemaRootVersionAliasGroups(root);\n const rootAliases = collectSchemaRootVersionAliases(root);\n if (\n rootGroups.length > 0 &&\n rootGroups.every(group => [...group.aliases].some(alias => expectedAliases.has(alias)))\n ) {\n return new Set([...expectedAliases, ...rootAliases]);\n }\n const found =\n rootGroups.length === 0\n ? 'no AdCP schema ids'\n : rootGroups\n .map(group => `${group.hint} (${Array.from(group.aliases).sort().join(', ')})`)\n .sort()\n .join(', ');\n throw new Error(\n `External AdCP schema root for version \"${version}\" at ${root} does not match the requested version and ` +\n `must contain only schema ids matching ${Array.from(expectedAliases).sort().join(', ')}; found ${found}.`\n );\n}\n\nconst externalSchemaRootAliases: Map<string, Set<string>> = new Map();\n\n/**\n * Register a schema bundle supplied outside the installed SDK package.\n *\n * Compliance runners use this when `--compliance-dir` points at another\n * package/check-out whose storyboards and schema bundle should be used\n * together. The root must be the schema-data directory itself, e.g.\n * `.../dist/lib/schemas-data/3.0`.\n */\nexport function registerExternalSchemaRoot(version: string, root: string): void {\n const key = resolveBundleKey(version);\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n externalSchemaRootAliases.set(key, aliases);\n for (const alias of aliases) {\n const previous = externalSchemaRoots.get(alias);\n externalSchemaRoots.set(alias, root);\n if (previous !== root) clearStatesForBundle(alias);\n }\n}\n\n/** Test/helper hook for unregistering an external schema bundle. */\nexport function unregisterExternalSchemaRoot(version: string): void {\n const key = resolveBundleKey(version);\n const aliases = new Set(schemaRootVersionAliases(version));\n for (const [registeredKey, registeredAliases] of externalSchemaRootAliases) {\n if (\n registeredKey === key ||\n registeredAliases.has(key) ||\n [...aliases].some(alias => registeredAliases.has(alias))\n ) {\n for (const alias of registeredAliases) aliases.add(alias);\n externalSchemaRootAliases.delete(registeredKey);\n }\n }\n for (const alias of aliases) {\n externalSchemaRoots.delete(alias);\n clearStatesForBundle(alias);\n }\n}\n\n/**\n * Run a callback with an external schema root scoped to the current async\n * execution chain. Unlike `registerExternalSchemaRoot`, this does not poison\n * process-global validation state for later hosted/compliance runs.\n */\nexport function withExternalSchemaRoot<T>(version: string, root: string | undefined, fn: () => T): T {\n if (root === undefined) return fn();\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n const parent = scopedExternalSchemaRoots.getStore();\n const next = new Map(parent);\n for (const alias of aliases) {\n next.set(alias, root);\n clearStatesForBundle(alias);\n }\n return scopedExternalSchemaRoots.run(next, fn);\n}\n\nfunction walkJsonFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkJsonFiles(full));\n else if (entry.isFile() && entry.name.endsWith('.json')) out.push(full);\n }\n return out;\n}\n\nfunction loadJson(file: string): LoadedSchema {\n return JSON.parse(readFileSync(file, 'utf-8')) as LoadedSchema;\n}\n\n/**\n * Clear `additionalProperties: false` at the response root so envelope\n * fields (`replayed`, `context`, `ext`, and future envelope additions)\n * can ride alongside the tool-specific body — per security.mdx the\n * envelope is always extensible. Upstream bundled schemas pin\n * `additionalProperties: false` at the root on a handful of mutating\n * tools (the property-list family), which rejects envelope fields like\n * `replayed` that aren't declared in the tool-specific body.\n *\n * Scope is deliberately narrow: only the top-level object, plus each\n * direct branch of a root-level `oneOf` / `anyOf` / `allOf`. Nested\n * bodies stay strict so response-side drift detection still catches\n * typos inside `Product`, `Package`, `MediaBuy` etc. Applied only to\n * response variants; request schemas stay strict so outgoing drift\n * fails at the edge.\n */\nfunction relaxResponseRoot(schema: LoadedSchema): LoadedSchema {\n const clone = { ...schema };\n if (clone.additionalProperties === false) {\n clone.additionalProperties = true;\n }\n for (const key of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = clone[key];\n if (Array.isArray(branches)) {\n clone[key] = branches.map(branch => {\n if (!branch || typeof branch !== 'object') return branch;\n const branchClone = { ...(branch as Record<string, unknown>) };\n if (branchClone.additionalProperties === false) {\n branchClone.additionalProperties = true;\n }\n return branchClone;\n });\n }\n }\n return clone;\n}\n\nfunction getAjvRegisteredIds(ajv: Ajv): Set<string> {\n const internals = ajv as unknown as {\n schemas?: Record<string, unknown>;\n refs?: Record<string, unknown>;\n };\n return new Set([...Object.keys(internals.schemas ?? {}), ...Object.keys(internals.refs ?? {})]);\n}\n\n/**\n * Build the (toolName, direction) → file path index by scanning the schema\n * tree once. Runs eagerly at first validator lookup.\n */\nfunction buildFileIndex(root: string): Map<string, string> {\n const index = new Map<string, string>();\n const record = (toolName: string, direction: Direction, file: string): void => {\n index.set(`${toolName}::${direction}`, file);\n };\n\n // Sync request/response live in the pre-resolved bundled/ tree.\n const bundledRoot = path.join(root, 'bundled');\n for (const file of walkJsonFiles(bundledRoot)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n record(tool, 'sync', file);\n }\n }\n\n // Async variants AND domain schemas that ship flat (not pre-bundled) both\n // live in the per-domain directories. Walk each for sync request/response\n // files and async variant files. Skip `bundled/` (already indexed above)\n // and `core/` (pure $ref targets, no tools).\n //\n // Flat-tree domains include `governance/`, `brand/`, `account/`,\n // `content-standards/`, `property/`, `collection/` — their schemas are\n // NOT pre-resolved into `bundled/`, so a bundled-only walk would miss\n // every `check_governance` / `acquire_rights` / `creative_approval` /\n // `sync_governance` / `*_property_list` request-response pair. That gap\n // (flagged by the ad-tech-protocol reviewer on PR #831) would leave\n // protocol-wide-requirement-bearing tasks (idempotency_key pattern,\n // `format: uri` on `caller`) invisible to the strict-validation signal.\n // Register flat-tree sync pairs only when `bundled/` didn't already\n // index them, so pre-resolved schemas (with $refs already inlined) win\n // for any domain that ships both.\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (!isRuntimeSchemaDirectory(entry.name) || entry.name === 'core') continue;\n const domainDir = path.join(root, entry.name);\n for (const file of walkJsonFiles(domainDir)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-async-response-submitted')) {\n const tool = base.slice(0, -'-async-response-submitted'.length).replace(/-/g, '_');\n record(tool, 'submitted', file);\n } else if (base.endsWith('-async-response-working')) {\n const tool = base.slice(0, -'-async-response-working'.length).replace(/-/g, '_');\n record(tool, 'working', file);\n } else if (base.endsWith('-async-response-input-required')) {\n const tool = base.slice(0, -'-async-response-input-required'.length).replace(/-/g, '_');\n record(tool, 'input-required', file);\n } else if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::request`)) record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::sync`)) record(tool, 'sync', file);\n }\n }\n }\n\n return index;\n}\n\nfunction ensureInit(version: string): LoaderState {\n // States are keyed by bundle key, not by raw version string, so\n // `getValidator('foo', 'request', '3.0.0')` and the same call with\n // `'3.0.1'` share state — both resolve to bundle key `'3.0'` and the\n // same compiled AJV instance.\n const key = resolveBundleKey(version);\n const root = resolveSchemaRoot(version);\n const cacheKey = stateCacheKey(key, root);\n const cached = states.get(cacheKey);\n if (cached) return cached;\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n\n const state: LoaderState = {\n ajv,\n fileIndex: buildFileIndex(root),\n validators: new Map(),\n rawSchemas: new Map(),\n entityPaths: new Map(),\n root,\n coreLoaded: false,\n version: key,\n };\n states.set(cacheKey, state);\n return state;\n}\n\n/**\n * Lazily pre-register every non-tool JSON schema shipped with the SDK so\n * cross-domain `$ref`s compile. Async response variants and flat-tree\n * domain schemas `$ref` out to three classes of building-block schemas:\n *\n * - `core/` + `enums/` — shared primitives referenced by every domain.\n * - `pricing-options/`, `error-details/`, `extensions/` — stand-alone\n * fragment trees.\n * - Sibling fragments inside each domain directory — e.g.\n * `governance/audience-constraints.json` referenced by\n * `governance/sync-plans-request.json`, or `signals/*` fragments\n * referenced by `signals/activate-signal-*.json`.\n *\n * Walk every directory except `bundled/` (pre-resolved schemas with refs\n * already inlined). Response files that `buildFileIndex` registered as tools\n * are registered with `relaxResponseRoot` applied, matching `getValidator`.\n * The fileIndex check is stricter than a filename-suffix match:\n * building-block fragments like `core/pagination-response.json` end in\n * `-response.json` but aren't tools, so suffix-matching would wrongly treat\n * them as relaxable response roots.\n */\nfunction ensureCoreLoaded(s: LoaderState): void {\n if (s.coreLoaded) return;\n // Tool response files are pre-registered with the same response-root\n // relaxation `getValidator` would apply. This matters for the async response\n // union: `core/async-response-data.json` can `$ref` both async variants and\n // sync responses, so callers must not have to prewarm response validators\n // before compiling a request that references the union.\n //\n // Why this matters: bundles whose source tree doesn't include a `bundled/`\n // pre-resolved subtree (e.g. v2.5, where the spec ships flat schemas with\n // unresolved `$ref`s) classify fragments like `media-buy/package-request.json`\n // as tool `package::request` via the filename-suffix heuristic in\n // `buildFileIndex`. Skipping all tool files would leave that fragment\n // unregistered, so a later compile of `create_media_buy` fails on\n // `MissingRefError: can't resolve /schemas/media-buy/package-request.json`.\n //\n const responseToolFiles = new Map<string, Direction>();\n for (const [key, file] of s.fileIndex) {\n if (key.endsWith('::request')) continue;\n const direction = key.slice(key.indexOf('::') + 2) as Direction;\n responseToolFiles.set(file, direction);\n }\n const registeredIds = getAjvRegisteredIds(s.ajv);\n for (const entry of readdirSync(s.root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (!isRuntimeSchemaDirectory(entry.name)) continue;\n const abs = path.join(s.root, entry.name);\n for (const file of walkJsonFiles(abs)) {\n const responseDirection = responseToolFiles.get(file);\n const schema = loadJson(file);\n const schemaToRegister = responseDirection === undefined ? schema : relaxResponseRoot(schema);\n if (typeof schemaToRegister.$id === 'string' && !registeredIds.has(schemaToRegister.$id)) {\n s.ajv.addSchema(schemaToRegister);\n registeredIds.add(schemaToRegister.$id);\n }\n }\n }\n s.coreLoaded = true;\n}\n\n/**\n * Look up the compiled AJV validator for a given tool + direction in the\n * specified AdCP version's schema bundle. Returns `undefined` when no\n * schema exists for the pair — callers can skip validation cleanly (e.g.,\n * custom tools outside the AdCP spec).\n *\n * `version` defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance\n * `getAdcpVersion()` value when the validator should track the client/server's\n * configured pin (Stage 3+).\n */\nexport function getValidator(\n toolName: string,\n direction: Direction,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::${direction}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = s.fileIndex.get(cacheKey);\n if (!file) return undefined;\n\n // Schemas that $ref into core/ and enums/ need those trees registered\n // before compile. Async response variants always do; flat-tree domain\n // schemas (anything outside `bundled/`) do too — their $refs weren't\n // pre-resolved at spec-publish time.\n const fromBundled = file.includes(`${path.sep}bundled${path.sep}`);\n if (direction === 'request' || !fromBundled) ensureCoreLoaded(s);\n\n const rawSchema = loadJson(file);\n // Bundled files inline every referenced subschema with the original\n // canonical `$id` (e.g. `core/version-envelope.json` appears nested\n // inside every bundled tool response). Bundled files carry NO\n // internal `$ref`s — the spec publishes them fully resolved, see\n // the `note: \"This is a bundled schema with all $ref resolved inline\"`\n // tag on every bundled file. Once `ensureCoreLoaded` has registered\n // any of those core schemas standalone (which it does for the flat-\n // tree governance / brand / property domains), Ajv's compile of a\n // bundled file trips the ambiguous-ref check on every nested $id.\n //\n // The fix: strip nested `$id` fields before compile on bundled\n // schemas. The root `$id` is kept (it's the validator's lookup key);\n // every other `$id` in the tree was just metadata anyway.\n const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;\n const schema = direction === 'request' ? prepared : relaxResponseRoot(prepared);\n const existing = typeof schema.$id === 'string' ? s.ajv.getSchema(schema.$id) : undefined;\n const compiled = existing ?? s.ajv.compile(schema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\n/**\n * Compile an arbitrary schema from the cached bundle by path, e.g.\n * `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions\n * whose payload schema is not tied to a tool request/response pair.\n */\nexport function getSchemaValidatorByRef(\n schemaRef: string,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n // Use an isolated AJV instance for arbitrary schema refs. Tool response\n // validators deliberately relax some roots for SDK back-compat; webhook\n // payload schemas need strict raw JSON Schema behavior without polluting the\n // shared tool-validator registry with unrelaxed response schemas.\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n const dependencySchemas: LoadedSchema[] = [];\n const registeredIds = new Set<string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n if (schemaFile.includes(`${path.sep}bundled${path.sep}`)) continue;\n if (\n [...TRANSPORT_PROJECTION_DIRECTORIES].some(directory => schemaFile.includes(`${path.sep}${directory}${path.sep}`))\n ) {\n continue;\n }\n if (schemaFile === file) continue;\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string' && !registeredIds.has(schema.$id)) {\n registeredIds.add(schema.$id);\n dependencySchemas.push(schema);\n }\n }\n if (dependencySchemas.length > 0) {\n ajv.addSchema(dependencySchemas);\n }\n const rawSchema = loadJson(file);\n const compiled = ajv.compile(rawSchema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\nfunction normalizeSchemaRef(schemaRef: string): string | undefined {\n const trimmed = schemaRef.replace(/^\\/+/, '');\n if (trimmed.length === 0) return undefined;\n const normalized = path.normalize(trimmed);\n if (normalized.startsWith('..') || path.isAbsolute(normalized)) return undefined;\n return normalized;\n}\n\n/**\n * Strip `$id` from every subschema of a bundled response file, preserving\n * the root `$id`. Bundled files are fully inlined (no internal `$ref`s),\n * so the nested `$id`s are vestigial metadata — Ajv only cares about the\n * root `$id` for validator lookup. Without this strip, Ajv's\n * `checkAmbiguousRef` throws when an inlined nested `$id` matches one\n * already registered standalone via `ensureCoreLoaded`.\n *\n * Returns a deep-copied tree; the input is not mutated.\n */\nfunction stripNestedIds(schema: LoadedSchema): LoadedSchema {\n const root = JSON.parse(JSON.stringify(schema)) as LoadedSchema;\n const rootId = typeof root.$id === 'string' ? root.$id : undefined;\n const walk = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n if (!node || typeof node !== 'object') return;\n const obj = node as Record<string, unknown>;\n if (typeof obj.$id === 'string' && obj.$id !== rootId) {\n delete obj.$id;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(root);\n return root;\n}\n\n/** List of (toolName, direction) pairs that have schemas. Used by tests. */\nexport function listValidatorKeys(version: string = ADCP_VERSION): string[] {\n const s = ensureInit(version);\n return [...s.fileIndex.keys()].sort();\n}\n\n/**\n * `$id`s of every schema currently registered with the AdCP validator's AJV\n * instance for `version`. Used by the schema-validator to extract the\n * rejecting sub-schema's `$id` from an Ajv error's `schemaPath`: when a\n * `$ref` is followed, Ajv prefixes the schemaPath with the target schema's\n * `$id`, so the longest registered `$id` that prefixes a schemaPath is the\n * sub-schema responsible for the failure.\n *\n * The set grows as `getValidator` calls trigger `ensureCoreLoaded` and\n * compile new tool roots — callers should read it AFTER the validate call\n * they're projecting errors from.\n */\nexport function getRegisteredSchemaIds(version: string = ADCP_VERSION): readonly string[] {\n const s = ensureInit(version);\n // Ajv 8 keeps registered schemas at `ajv.schemas` (URI → SchemaEnv). Returning\n // the keys is enough for prefix matching; we don't expose the SchemaEnv values.\n const registry = (s.ajv as unknown as { schemas?: Record<string, unknown> }).schemas;\n return registry ? Object.keys(registry) : [];\n}\n\n/** Suffix used in the suffix table — exported for testing. */\nexport { SCHEMA_FILENAME_SUFFIX };\n\n/**\n * Returns true when the schema bundle for `version` is reachable from the\n * dist build or the source-tree fallback. Cheap synchronous check; safe\n * to call at construction time of clients/servers to fail fast on a pin\n * we don't have schemas for.\n */\nexport function hasSchemaBundle(version: string): boolean {\n try {\n resolveSchemaRoot(version);\n return true;\n } catch {\n return false;\n }\n}\n\nconst mcpProfileInputSchemaCache = new Map<string, Readonly<Record<string, unknown>> | null>();\n\n/** Load the exact self-contained request projection from an MCP role profile. */\nexport function getMcpProfileInputSchema(\n toolName: string,\n profile: string,\n version: string = ADCP_VERSION\n): Readonly<Record<string, unknown>> | undefined {\n const root = resolveSchemaRoot(version);\n const cacheKey = `${root}\\u001f${profile}\\u001f${toolName}`;\n const cached = mcpProfileInputSchemaCache.get(cacheKey);\n if (cached !== undefined) return cached ?? undefined;\n\n const mcpRoot = path.join(root, 'mcp');\n if (!existsSync(mcpRoot)) {\n mcpProfileInputSchemaCache.set(cacheKey, null);\n return undefined;\n }\n const protocolVersions = readdirSync(mcpRoot, { withFileTypes: true })\n .filter(entry => entry.isDirectory())\n .map(entry => entry.name)\n .sort()\n .reverse();\n for (const protocolVersion of protocolVersions) {\n const profileRoot = path.resolve(mcpRoot, protocolVersion, 'profiles', profile);\n const manifestFile = path.join(profileRoot, 'manifest.json');\n if (!existsSync(manifestFile)) continue;\n const manifest = loadJson(manifestFile) as {\n tools?: Record<string, { inputSchema?: unknown }>;\n };\n const schemaRef = manifest.tools?.[toolName]?.inputSchema;\n if (typeof schemaRef !== 'string') continue;\n const schemaFile = path.resolve(profileRoot, schemaRef);\n if (!schemaFile.startsWith(`${profileRoot}${path.sep}`) || !existsSync(schemaFile)) continue;\n const schema = Object.freeze(loadJson(schemaFile));\n mcpProfileInputSchemaCache.set(cacheKey, schema);\n return schema;\n }\n mcpProfileInputSchemaCache.set(cacheKey, null);\n return undefined;\n}\n\n/**\n * Test hook: reset cached state. With no argument, clears every version's\n * loader state; with a version, clears only the bundle that version\n * resolves to (so passing `'3.0.0'` and `'3.0.1'` both clear the `'3.0'`\n * bundle).\n */\nexport function _resetValidationLoader(version?: string): void {\n mcpProfileInputSchemaCache.clear();\n if (version === undefined) {\n states.clear();\n } else {\n clearStatesForBundle(resolveBundleKey(version));\n }\n}\n\n/**\n * Returns true when `field` is **explicitly declared** as a top-level property\n * in the request schema for `toolName`, or when no schema is available\n * (fail-open). Used by the storyboard runner to decide whether to inject\n * envelope fields that aren't universally present across tools (e.g. `brand`,\n * `account`, `ext`).\n *\n * Reads the raw JSON schema file without compiling — avoids coupling to AJV\n * internals. Only inspects the top-level `properties` map; nested sub-schemas\n * are not traversed. Results are memoized in `LoaderState.rawSchemas` so\n * multi-step storyboard runs don't re-read the same file on each step.\n *\n * **Semantic note**: AdCP 3.1.0-beta.3 set `additionalProperties: true` on\n * mutating request schemas (vendor-extension friendly). Before that flip, the\n * helper used `additionalProperties: false` as the gate — \"if the schema is\n * strict, only `properties` keys are allowed.\" Now requests are universally\n * permissive at the schema level, so that gate would say `true` for any field\n * on any request — defeating the storyboard runner's intent (\"only inject\n * envelope fields the tool's schema declares it expects to see\"). The helper\n * now checks `field in properties` directly: the question we actually care\n * about is **\"does the schema declare this field at top level?\"**, not\n * \"does the schema permit this field at top level?\" (it permits everything).\n *\n * Fails open (returns `true`) when:\n * - No schema file is indexed for the tool (custom tool, schema not synced)\n * - The schema root is not reachable (schemas not built/synced yet)\n * - Any I/O / parse error during the read\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function schemaAllowsTopLevelField(toolName: string, field: string, version: string = ADCP_VERSION): boolean {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return true;\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n const props = schema.properties as Record<string, unknown> | undefined;\n return props !== undefined && field in props;\n } catch {\n return true;\n }\n}\n\nexport interface SchemaEntityPath {\n /** Property path from the tool request root. `*` addresses every array item. */\n path: string[];\n /** AdCP `x-entity` annotation found on the identity-bearing leaf. */\n xEntity: string;\n}\n\n/**\n * Return every request field carrying an `x-entity` annotation. Unlike the\n * server hydration map this walks nested arrays/objects, because storyboard\n * fixture handles commonly live at `packages[*].product_id` and\n * `packages[*].pricing_option_id`.\n *\n * Missing schemas fail closed with an empty list: handle substitution must\n * never guess from a field name alone.\n */\nexport function getRequestSchemaEntityPaths(\n toolName: string,\n version: string = ADCP_VERSION\n): readonly SchemaEntityPath[] {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const cached = s.entityPaths.get(cacheKey);\n if (cached) return cached;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return [];\n\n const root = loadJson(file) as Record<string, unknown>;\n const found = new Map<string, SchemaEntityPath>();\n const stack = new Set<string>();\n\n const resolvePointer = (document: unknown, fragment: string): unknown => {\n if (!fragment || fragment === '#') return document;\n if (!fragment.startsWith('#/')) return undefined;\n let current = document;\n for (const encoded of fragment.slice(2).split('/')) {\n if (!current || typeof current !== 'object') return undefined;\n const key = encoded.replace(/~1/g, '/').replace(/~0/g, '~');\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n };\n\n const resolveRef = (\n ref: string,\n currentFile: string,\n currentDocument: Record<string, unknown>\n ): { node: unknown; file: string; document: Record<string, unknown>; key: string } | undefined => {\n const hash = ref.indexOf('#');\n const refPath = hash >= 0 ? ref.slice(0, hash) : ref;\n const fragment = hash >= 0 ? ref.slice(hash) : '';\n if (!refPath) {\n return {\n node: resolvePointer(currentDocument, fragment),\n file: currentFile,\n document: currentDocument,\n key: `${currentFile}${fragment}`,\n };\n }\n\n const schemaRelative = refPath.match(/\\/schemas\\/[^/]+\\/(.+)$/)?.[1];\n const candidates = [\n schemaRelative ? path.join(s.root, schemaRelative) : undefined,\n path.resolve(path.dirname(currentFile), refPath),\n ].filter((candidate): candidate is string => candidate !== undefined);\n let targetFile = candidates.find(candidate => existsSync(candidate));\n // Standard AdCP refs encode their schema-root-relative file path, so\n // they resolve without parsing every JSON file in the bundle. Build the\n // expensive $id index only for an unusual ref that cannot be resolved\n // by path.\n if (!targetFile) {\n if (!s.schemaIdFiles) {\n const idToFile = new Map<string, string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n try {\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string') idToFile.set(schema.$id, schemaFile);\n } catch {\n // A malformed unrelated schema is not a usable ref target.\n }\n }\n s.schemaIdFiles = idToFile;\n }\n targetFile = s.schemaIdFiles.get(refPath);\n }\n if (!targetFile) return undefined;\n const document = loadJson(targetFile) as Record<string, unknown>;\n return {\n node: resolvePointer(document, fragment),\n file: targetFile,\n document,\n key: `${targetFile}${fragment}`,\n };\n };\n\n const walk = (\n node: unknown,\n propertyPath: string[],\n currentFile: string,\n currentDocument: Record<string, unknown>,\n depth: number\n ): void => {\n if (!node || typeof node !== 'object' || depth > 48) return;\n const obj = node as Record<string, unknown>;\n if (typeof obj['x-entity'] === 'string' && propertyPath.length > 0) {\n const entityPath = { path: [...propertyPath], xEntity: obj['x-entity'] as string };\n found.set(`${entityPath.path.join('.')}\\0${entityPath.xEntity}`, entityPath);\n }\n\n if (typeof obj.$ref === 'string') {\n const target = resolveRef(obj.$ref, currentFile, currentDocument);\n if (target && target.node !== undefined) {\n const guard = `${target.key}\\0${propertyPath.join('.')}`;\n if (!stack.has(guard)) {\n stack.add(guard);\n walk(target.node, propertyPath, target.file, target.document, depth + 1);\n stack.delete(guard);\n }\n }\n }\n\n const properties = obj.properties;\n if (properties && typeof properties === 'object' && !Array.isArray(properties)) {\n for (const [key, child] of Object.entries(properties as Record<string, unknown>)) {\n walk(child, [...propertyPath, key], currentFile, currentDocument, depth + 1);\n }\n }\n if (obj.items !== undefined) {\n walk(obj.items, [...propertyPath, '*'], currentFile, currentDocument, depth + 1);\n }\n for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = obj[keyword];\n if (Array.isArray(branches)) {\n for (const branch of branches) walk(branch, propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n for (const keyword of ['if', 'then', 'else', 'not'] as const) {\n if (obj[keyword] !== undefined) {\n walk(obj[keyword], propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n };\n\n walk(root, [], file, root, 0);\n const result = [...found.values()].sort((a, b) => {\n const byPath = a.path.join('.').localeCompare(b.path.join('.'));\n return byPath || a.xEntity.localeCompare(b.xEntity);\n });\n s.entityPaths.set(cacheKey, result);\n return result;\n } catch {\n return [];\n }\n}\n\n/**\n * Resolve a JSON Schema `default` value by walking a dot-separated property\n * path through a schema's nested `properties` maps.\n *\n * This intentionally does not instantiate AJV's `useDefaults` mutation mode.\n * Callers decide when a schema default is semantically meaningful for their\n * runtime object; this helper only reports what the bundled schema declares.\n *\n * Fails closed (`undefined`) when the schema is unavailable, the path is not a\n * concrete properties path, or the target schema node has no `default`.\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function getSchemaDefaultByPath(schemaRef: string, dottedPath: string, version: string = ADCP_VERSION): unknown {\n try {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n\n const node = resolveSchemaPropertyPath(schema, dottedPath);\n if (!node || !Object.prototype.hasOwnProperty.call(node, 'default')) return undefined;\n return cloneJsonValue((node as { default: unknown }).default);\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSchemaPropertyPath(\n schema: Record<string, unknown>,\n dottedPath: string\n): Record<string, unknown> | undefined {\n let current: unknown = schema;\n for (const key of dottedPath.split('.')) {\n if (!current || typeof current !== 'object') return undefined;\n const props = (current as Record<string, unknown>).properties;\n if (!props || typeof props !== 'object') return undefined;\n if (!Object.prototype.hasOwnProperty.call(props, key)) return undefined;\n current = (props as Record<string, unknown>)[key];\n }\n return current && typeof current === 'object' ? (current as Record<string, unknown>) : undefined;\n}\n\nfunction cloneJsonValue(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n return JSON.parse(JSON.stringify(value)) as unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,iBAA2C;AAC3C,yBAAuB;AACvB,yBAAkC;AAClC,gBAAsD;AACtD,kBAAiB;AACjB,qBAA6B;AAC7B,oBAAmC;AAUnC,MAAM,yBAAoD;AAAA,EACxD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,kBAAkB;AACpB;AASA,MAAM,mCAAmC,oBAAI,IAAI,CAAC,KAAK,CAAC;AAExD,SAAS,yBAAyB,MAAuB;AACvD,SAAO,SAAS,aAAa,CAAC,iCAAiC,IAAI,IAAI;AACzE;AA+BO,SAAS,iBAAiB,SAAyB;AAExD,QAAM,YAAY,QAAQ,MAAM,gBAAgB;AAChD,MAAI,UAAW,QAAO,GAAG,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;AAKrD,QAAM,sBAAsB,QAAQ,MAAM,kDAAkD;AAC5F,MAAI,oBAAqB,QAAO;AAOhC,QAAM,SAAS,QAAQ,MAAM,gEAAgE;AAC7F,MAAI,QAAQ;AACV,UAAM,CAAC,EAAE,OAAO,OAAO,EAAE,UAAU,IAAI;AACvC,QAAI,eAAe,OAAW,QAAO;AACrC,WAAO,GAAG,KAAK,IAAI,KAAK;AAAA,EAC1B;AAGA,QAAM,cAAc,QAAQ,MAAM,gBAAgB;AAClD,MAAI,YAAa,QAAO;AACxB,QAAM,IAAI;AAAA,IACR,gBAAgB,KAAK,UAAU,OAAO,CAAC;AAAA,IAGvC;AAAA,EACF;AACF;AAiDA,MAAM,4BAA4B;AAsB3B,SAAS,wBAAwB,OAAyC;AAC/E,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,IAAI;AAAA,MACR,sCAAsC,OAAO,KAAK;AAAA,MAElD;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,0BAA0B,KAAK,KAAK,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,gBAAgB,KAAK,UAAU,KAAK,CAAC,4CAA4C,yBAAyB;AAAA,MAG1G;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,uBAAuB,oBAAoC;AAEzE,QAAM,mBAAmB,mBAAmB,MAAM,qDAAqD;AACvG,MAAI,kBAAkB;AACpB,UAAM,CAAC,EAAE,OAAO,OAAO,aAAa,EAAE,IAAI;AAC1C,WAAO,GAAG,KAAK,IAAI,KAAK,GAAG,UAAU;AAAA,EACvC;AAEA,QAAM,aAAa,mBAAmB,MAAM,0DAA0D;AACtG,MAAI,YAAY;AACd,UAAM,CAAC,EAAE,OAAO,OAAO,aAAa,EAAE,IAAI;AAC1C,WAAO,GAAG,KAAK,IAAI,KAAK,GAAG,UAAU;AAAA,EACvC;AAIA,MAAI,iBAAiB,KAAK,kBAAkB,EAAG,QAAO;AACtD,QAAM,IAAI;AAAA,IACR,oBAAoB,KAAK,UAAU,kBAAkB,CAAC;AAAA,IAEtD;AAAA,EACF;AACF;AAsBA,SAAS,kBAAkB,SAAyB;AAClD,QAAM,MAAM,iBAAiB,OAAO;AACpC,QAAM,aAAa,0BAA0B,SAAS,GAAG,IAAI,GAAG;AAChE,MAAI,kBAAc,sBAAW,UAAU,EAAG,QAAO;AAEjD,QAAM,eAAe,oBAAoB,IAAI,GAAG;AAChD,MAAI,oBAAgB,sBAAW,YAAY,EAAG,QAAO;AAErD,QAAM,gBAAgB,YAAAA,QAAK,KAAK,WAAW,MAAM,gBAAgB,GAAG;AACpE,UAAI,sBAAW,aAAa,EAAG,QAAO;AAKtC,QAAM,wBAAwB,aAAa,KAAK,GAAG;AACnD,MAAI,uBAAuB;AACzB,UAAM,0BAA0B,qBAAqB,YAAAA,QAAK,KAAK,WAAW,MAAM,cAAc,GAAG,GAAG;AACpG,QAAI,wBAAyB,QAAO;AAAA,EACtC;AAKA,QAAM,YAAY,YAAAA,QAAK,KAAK,WAAW,MAAM,MAAM,MAAM,WAAW,OAAO;AAC3E,QAAM,iBAAiB,YAAAA,QAAK,KAAK,WAAW,OAAO;AACnD,UAAI,sBAAW,cAAc,EAAG,QAAO;AAOvC,QAAM,aAAa,IAAI,MAAM,gBAAgB;AAC7C,MAAI,kBAAc,sBAAW,SAAS,GAAG;AACvC,UAAM,CAAC,EAAE,OAAO,KAAK,IAAI;AACzB,UAAM,SAAS,GAAG,KAAK,IAAI,KAAK;AAChC,UAAM,aAAS,uBAAY,WAAW,EAAE,eAAe,KAAK,CAAC,EAC1D;AAAA,MACC,OACE,EAAE,YAAY,KACd,EAAE,KAAK,WAAW,MAAM,KACxB,CAAC,EAAE,KAAK,SAAS,WAAW,KAC5B,kBAAkB,KAAK,EAAE,IAAI;AAAA,IACjC,EACC,IAAI,QAAM;AAAA,MACT,MAAM,EAAE;AAAA,MACR,OAAO,SAAS,EAAE,KAAK,MAAM,OAAO,MAAM,GAAG,EAAE;AAAA,IACjD,EAAE,EACD,OAAO,OAAK,OAAO,SAAS,EAAE,KAAK,CAAC,EACpC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACnC,QAAI,OAAO,SAAS,EAAG,QAAO,YAAAA,QAAK,KAAK,WAAW,OAAO,CAAC,EAAG,IAAI;AAAA,EACpE;AASA,MAAI,uBAAuB;AACzB,UAAM,2BAA2B,qBAAqB,WAAW,GAAG;AACpE,QAAI,yBAA0B,QAAO;AAAA,EACvC;AAEA,QAAM,IAAI;AAAA,IACR,iCAAiC,OAAO,uCACZ,GAAG,QAAQ,aAAa,gBAAgB,cAAc,sCAC5C,SAAS;AAAA,EAEjD;AACF;AAEA,SAAS,qBAAqB,MAAc,KAAiC;AAC3E,MAAI,KAAC,sBAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,aAAS,uBAAY,MAAM,EAAE,eAAe,KAAK,CAAC,EACrD,OAAO,OAAK,EAAE,YAAY,KAAK,CAAC,EAAE,KAAK,SAAS,WAAW,CAAC,EAC5D,IAAI,OAAK;AACR,QAAI;AACF,aAAO,EAAE,MAAM,EAAE,MAAM,IAAI,uBAAuB,EAAE,IAAI,EAAE;AAAA,IAC5D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC,EACA,OAAO,CAAC,MAAyC,MAAM,IAAI,EAC3D,OAAO,OAAK,EAAE,OAAO,OAAO,EAAE,GAAG,WAAW,GAAG,GAAG,GAAG,CAAC,EACtD,KAAK,CAAC,GAAG,MAAM,uBAAuB,EAAE,MAAM,EAAE,IAAI,CAAC;AACxD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SAAO,YAAAA,QAAK,KAAK,MAAM,OAAO,CAAC,EAAG,IAAI;AACxC;AAEA,SAAS,uBAAuB,GAAW,GAAmB;AAC5D,SAAO,EAAE,cAAc,GAAG,QAAW,EAAE,SAAS,MAAM,aAAa,OAAO,CAAC;AAC7E;AAcA,MAAM,SAAmC,oBAAI,IAAI;AACjD,MAAM,sBAA2C,oBAAI,IAAI;AACzD,MAAM,4BAA4B,IAAI,qCAAuC;AAE7E,SAAS,cAAc,WAAmB,MAAsB;AAC9D,SAAO,GAAG,SAAS,KAAK,IAAI;AAC9B;AAEA,SAAS,qBAAqB,WAAyB;AACrD,aAAW,CAAC,UAAU,KAAK,KAAK,QAAQ;AACtC,QAAI,MAAM,YAAY,UAAW,QAAO,OAAO,QAAQ;AAAA,EACzD;AACF;AAEA,SAAS,mBAAmB,MAAuB;AACjD,MAAI,KAAC,sBAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,cAAc,YAAAA,QAAK,KAAK,MAAM,SAAS;AAC7C,QAAM,YAAQ,sBAAW,WAAW,IAAI,cAAc,WAAW,IAAI,cAAc,IAAI;AACvF,SAAO,MAAM,KAAK,UAAQ;AACxB,QAAI;AACF,YAAM,SAAS,SAAS,IAAI;AAC5B,aAAO,OAAO,OAAO,QAAQ,YAAY,OAAO,OAAO,YAAY;AAAA,IACrE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;AAEA,SAAS,oBAAoB,UAAsC;AACjE,SAAO,SAAS,MAAM,sBAAsB,IAAI,CAAC;AACnD;AAEA,SAAS,gCAAgC,MAA2B;AAClE,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,QAAQ,cAAc,IAAI,GAAG;AACtC,QAAI;AACJ,QAAI;AACF,eAAS,SAAS,IAAI;AAAA,IACxB,QAAQ;AACN;AAAA,IACF;AACA,QAAI,OAAO,OAAO,QAAQ,SAAU;AACpC,UAAM,OAAO,oBAAoB,OAAO,GAAG;AAC3C,QAAI,CAAC,KAAM;AACX,eAAW,SAAS,yBAAyB,IAAI,EAAG,SAAQ,IAAI,KAAK;AAAA,EACvE;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,SAA8B;AAC9D,QAAM,UAAU,oBAAI,IAAY,CAAC,OAAO,CAAC;AACzC,MAAI;AACF,YAAQ,IAAI,iBAAiB,OAAO,CAAC;AAAA,EACvC,QAAQ;AAAA,EAER;AACA,MAAI;AACF,UAAM,mBAAmB,uBAAuB,OAAO;AACvD,YAAQ,IAAI,gBAAgB;AAC5B,UAAM,SAAS,sBAAsB,gBAAgB;AACrD,QAAI,OAAQ,SAAQ,IAAI,MAAM;AAAA,EAChC,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,yBAAqD;AAClF,SAAO,wBAAwB,MAAM,iCAAiC,IAAI,CAAC;AAC7E;AAEA,SAAS,oCAAoC,MAA6D;AACxG,QAAM,SAAwD,CAAC;AAC/D,aAAW,QAAQ,cAAc,IAAI,GAAG;AACtC,QAAI;AACJ,QAAI;AACF,eAAS,SAAS,IAAI;AAAA,IACxB,QAAQ;AACN;AAAA,IACF;AACA,QAAI,OAAO,OAAO,QAAQ,SAAU;AACpC,UAAM,OAAO,oBAAoB,OAAO,GAAG;AAC3C,QAAI,CAAC,KAAM;AACX,WAAO,KAAK,EAAE,MAAM,SAAS,yBAAyB,IAAI,EAAE,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,+BAA+B,SAAiB,MAA2B;AAClF,QAAM,kBAAkB,yBAAyB,OAAO;AACxD,QAAM,aAAa,oCAAoC,IAAI;AAC3D,QAAM,cAAc,gCAAgC,IAAI;AACxD,MACE,WAAW,SAAS,KACpB,WAAW,MAAM,WAAS,CAAC,GAAG,MAAM,OAAO,EAAE,KAAK,WAAS,gBAAgB,IAAI,KAAK,CAAC,CAAC,GACtF;AACA,WAAO,oBAAI,IAAI,CAAC,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAAA,EACrD;AACA,QAAM,QACJ,WAAW,WAAW,IAClB,uBACA,WACG,IAAI,WAAS,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,MAAM,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,GAAG,EAC7E,KAAK,EACL,KAAK,IAAI;AAClB,QAAM,IAAI;AAAA,IACR,0CAA0C,OAAO,QAAQ,IAAI,mFAClB,MAAM,KAAK,eAAe,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,WAAW,KAAK;AAAA,EAC1G;AACF;AAEA,MAAM,4BAAsD,oBAAI,IAAI;AAU7D,SAAS,2BAA2B,SAAiB,MAAoB;AAC9E,QAAM,MAAM,iBAAiB,OAAO;AACpC,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI,MAAM,0CAA0C,OAAO,2BAA2B,IAAI,EAAE;AAAA,EACpG;AACA,QAAM,UAAU,+BAA+B,SAAS,IAAI;AAC5D,4BAA0B,IAAI,KAAK,OAAO;AAC1C,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,oBAAoB,IAAI,KAAK;AAC9C,wBAAoB,IAAI,OAAO,IAAI;AACnC,QAAI,aAAa,KAAM,sBAAqB,KAAK;AAAA,EACnD;AACF;AAGO,SAAS,6BAA6B,SAAuB;AAClE,QAAM,MAAM,iBAAiB,OAAO;AACpC,QAAM,UAAU,IAAI,IAAI,yBAAyB,OAAO,CAAC;AACzD,aAAW,CAAC,eAAe,iBAAiB,KAAK,2BAA2B;AAC1E,QACE,kBAAkB,OAClB,kBAAkB,IAAI,GAAG,KACzB,CAAC,GAAG,OAAO,EAAE,KAAK,WAAS,kBAAkB,IAAI,KAAK,CAAC,GACvD;AACA,iBAAW,SAAS,kBAAmB,SAAQ,IAAI,KAAK;AACxD,gCAA0B,OAAO,aAAa;AAAA,IAChD;AAAA,EACF;AACA,aAAW,SAAS,SAAS;AAC3B,wBAAoB,OAAO,KAAK;AAChC,yBAAqB,KAAK;AAAA,EAC5B;AACF;AAOO,SAAS,uBAA0B,SAAiB,MAA0B,IAAgB;AACnG,MAAI,SAAS,OAAW,QAAO,GAAG;AAClC,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI,MAAM,0CAA0C,OAAO,2BAA2B,IAAI,EAAE;AAAA,EACpG;AACA,QAAM,UAAU,+BAA+B,SAAS,IAAI;AAC5D,QAAM,SAAS,0BAA0B,SAAS;AAClD,QAAM,OAAO,IAAI,IAAI,MAAM;AAC3B,aAAW,SAAS,SAAS;AAC3B,SAAK,IAAI,OAAO,IAAI;AACpB,yBAAqB,KAAK;AAAA,EAC5B;AACA,SAAO,0BAA0B,IAAI,MAAM,EAAE;AAC/C;AAEA,SAAS,cAAc,KAAuB;AAC5C,MAAI,KAAC,sBAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,QAAM,MAAgB,CAAC;AACvB,aAAW,aAAS,uBAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,UAAM,OAAO,YAAAA,QAAK,KAAK,KAAK,MAAM,IAAI;AACtC,QAAI,MAAM,YAAY,EAAG,KAAI,KAAK,GAAG,cAAc,IAAI,CAAC;AAAA,aAC/C,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,OAAO,EAAG,KAAI,KAAK,IAAI;AAAA,EACxE;AACA,SAAO;AACT;AAEA,SAAS,SAAS,MAA4B;AAC5C,SAAO,KAAK,UAAM,wBAAa,MAAM,OAAO,CAAC;AAC/C;AAkBA,SAAS,kBAAkB,QAAoC;AAC7D,QAAM,QAAQ,EAAE,GAAG,OAAO;AAC1B,MAAI,MAAM,yBAAyB,OAAO;AACxC,UAAM,uBAAuB;AAAA,EAC/B;AACA,aAAW,OAAO,CAAC,SAAS,SAAS,OAAO,GAAY;AACtD,UAAM,WAAW,MAAM,GAAG;AAC1B,QAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,YAAM,GAAG,IAAI,SAAS,IAAI,YAAU;AAClC,YAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,cAAM,cAAc,EAAE,GAAI,OAAmC;AAC7D,YAAI,YAAY,yBAAyB,OAAO;AAC9C,sBAAY,uBAAuB;AAAA,QACrC;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAuB;AAClD,QAAM,YAAY;AAIlB,SAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,UAAU,WAAW,CAAC,CAAC,GAAG,GAAG,OAAO,KAAK,UAAU,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChG;AAMA,SAAS,eAAe,MAAmC;AACzD,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,SAAS,CAAC,UAAkB,WAAsB,SAAuB;AAC7E,UAAM,IAAI,GAAG,QAAQ,KAAK,SAAS,IAAI,IAAI;AAAA,EAC7C;AAGA,QAAM,cAAc,YAAAA,QAAK,KAAK,MAAM,SAAS;AAC7C,aAAW,QAAQ,cAAc,WAAW,GAAG;AAC7C,UAAM,OAAO,YAAAA,QAAK,SAAS,MAAM,OAAO;AACxC,QAAI,KAAK,SAAS,UAAU,GAAG;AAC7B,YAAM,OAAO,KAAK,MAAM,GAAG,CAAC,WAAW,MAAM,EAAE,QAAQ,MAAM,GAAG;AAChE,aAAO,MAAM,WAAW,IAAI;AAAA,IAC9B,WAAW,KAAK,SAAS,WAAW,GAAG;AACrC,YAAM,OAAO,KAAK,MAAM,GAAG,CAAC,YAAY,MAAM,EAAE,QAAQ,MAAM,GAAG;AACjE,aAAO,MAAM,QAAQ,IAAI;AAAA,IAC3B;AAAA,EACF;AAkBA,aAAW,aAAS,uBAAY,MAAM,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9D,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,QAAI,CAAC,yBAAyB,MAAM,IAAI,KAAK,MAAM,SAAS,OAAQ;AACpE,UAAM,YAAY,YAAAA,QAAK,KAAK,MAAM,MAAM,IAAI;AAC5C,eAAW,QAAQ,cAAc,SAAS,GAAG;AAC3C,YAAM,OAAO,YAAAA,QAAK,SAAS,MAAM,OAAO;AACxC,UAAI,KAAK,SAAS,2BAA2B,GAAG;AAC9C,cAAM,OAAO,KAAK,MAAM,GAAG,CAAC,4BAA4B,MAAM,EAAE,QAAQ,MAAM,GAAG;AACjF,eAAO,MAAM,aAAa,IAAI;AAAA,MAChC,WAAW,KAAK,SAAS,yBAAyB,GAAG;AACnD,cAAM,OAAO,KAAK,MAAM,GAAG,CAAC,0BAA0B,MAAM,EAAE,QAAQ,MAAM,GAAG;AAC/E,eAAO,MAAM,WAAW,IAAI;AAAA,MAC9B,WAAW,KAAK,SAAS,gCAAgC,GAAG;AAC1D,cAAM,OAAO,KAAK,MAAM,GAAG,CAAC,iCAAiC,MAAM,EAAE,QAAQ,MAAM,GAAG;AACtF,eAAO,MAAM,kBAAkB,IAAI;AAAA,MACrC,WAAW,KAAK,SAAS,UAAU,GAAG;AACpC,cAAM,OAAO,KAAK,MAAM,GAAG,CAAC,WAAW,MAAM,EAAE,QAAQ,MAAM,GAAG;AAChE,YAAI,CAAC,MAAM,IAAI,GAAG,IAAI,WAAW,EAAG,QAAO,MAAM,WAAW,IAAI;AAAA,MAClE,WAAW,KAAK,SAAS,WAAW,GAAG;AACrC,cAAM,OAAO,KAAK,MAAM,GAAG,CAAC,YAAY,MAAM,EAAE,QAAQ,MAAM,GAAG;AACjE,YAAI,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAG,QAAO,MAAM,QAAQ,IAAI;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,WAAW,SAA8B;AAKhD,QAAM,MAAM,iBAAiB,OAAO;AACpC,QAAM,OAAO,kBAAkB,OAAO;AACtC,QAAM,WAAW,cAAc,KAAK,IAAI;AACxC,QAAM,SAAS,OAAO,IAAI,QAAQ;AAClC,MAAI,OAAQ,QAAO;AACnB,QAAM,MAAM,IAAI,WAAAC,QAAI;AAAA,IAClB,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,iBAAiB;AAAA,EACnB,CAAC;AACD,yBAAAC,SAAW,GAAG;AAEd,QAAM,QAAqB;AAAA,IACzB;AAAA,IACA,WAAW,eAAe,IAAI;AAAA,IAC9B,YAAY,oBAAI,IAAI;AAAA,IACpB,YAAY,oBAAI,IAAI;AAAA,IACpB,aAAa,oBAAI,IAAI;AAAA,IACrB;AAAA,IACA,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACA,SAAO,IAAI,UAAU,KAAK;AAC1B,SAAO;AACT;AAuBA,SAAS,iBAAiB,GAAsB;AAC9C,MAAI,EAAE,WAAY;AAelB,QAAM,oBAAoB,oBAAI,IAAuB;AACrD,aAAW,CAAC,KAAK,IAAI,KAAK,EAAE,WAAW;AACrC,QAAI,IAAI,SAAS,WAAW,EAAG;AAC/B,UAAM,YAAY,IAAI,MAAM,IAAI,QAAQ,IAAI,IAAI,CAAC;AACjD,sBAAkB,IAAI,MAAM,SAAS;AAAA,EACvC;AACA,QAAM,gBAAgB,oBAAoB,EAAE,GAAG;AAC/C,aAAW,aAAS,uBAAY,EAAE,MAAM,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,QAAI,CAAC,yBAAyB,MAAM,IAAI,EAAG;AAC3C,UAAM,MAAM,YAAAF,QAAK,KAAK,EAAE,MAAM,MAAM,IAAI;AACxC,eAAW,QAAQ,cAAc,GAAG,GAAG;AACrC,YAAM,oBAAoB,kBAAkB,IAAI,IAAI;AACpD,YAAM,SAAS,SAAS,IAAI;AAC5B,YAAM,mBAAmB,sBAAsB,SAAY,SAAS,kBAAkB,MAAM;AAC5F,UAAI,OAAO,iBAAiB,QAAQ,YAAY,CAAC,cAAc,IAAI,iBAAiB,GAAG,GAAG;AACxF,UAAE,IAAI,UAAU,gBAAgB;AAChC,sBAAc,IAAI,iBAAiB,GAAG;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AACA,IAAE,aAAa;AACjB;AAYO,SAAS,aACd,UACA,WACA,UAAkB,6BACY;AAC9B,QAAM,IAAI,WAAW,OAAO;AAC5B,QAAM,WAAW,GAAG,QAAQ,KAAK,SAAS;AAC1C,QAAM,SAAS,EAAE,WAAW,IAAI,QAAQ;AACxC,MAAI,OAAQ,QAAO;AAEnB,QAAM,OAAO,EAAE,UAAU,IAAI,QAAQ;AACrC,MAAI,CAAC,KAAM,QAAO;AAMlB,QAAM,cAAc,KAAK,SAAS,GAAG,YAAAA,QAAK,GAAG,UAAU,YAAAA,QAAK,GAAG,EAAE;AACjE,MAAI,cAAc,aAAa,CAAC,YAAa,kBAAiB,CAAC;AAE/D,QAAM,YAAY,SAAS,IAAI;AAc/B,QAAM,WAAW,cAAc,eAAe,SAAS,IAAI;AAC3D,QAAM,SAAS,cAAc,YAAY,WAAW,kBAAkB,QAAQ;AAC9E,QAAM,WAAW,OAAO,OAAO,QAAQ,WAAW,EAAE,IAAI,UAAU,OAAO,GAAG,IAAI;AAChF,QAAM,WAAW,YAAY,EAAE,IAAI,QAAQ,MAAM;AACjD,IAAE,WAAW,IAAI,UAAU,QAAQ;AACnC,SAAO;AACT;AAOO,SAAS,wBACd,WACA,UAAkB,6BACY;AAC9B,QAAM,IAAI,WAAW,OAAO;AAC5B,QAAM,aAAa,mBAAmB,SAAS;AAC/C,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,WAAW,eAAe,UAAU;AAC1C,QAAM,SAAS,EAAE,WAAW,IAAI,QAAQ;AACxC,MAAI,OAAQ,QAAO;AAEnB,QAAM,OAAO,YAAAA,QAAK,KAAK,EAAE,MAAM,UAAU;AACzC,MAAI,KAAC,sBAAW,IAAI,EAAG,QAAO;AAM9B,QAAM,MAAM,IAAI,WAAAC,QAAI;AAAA,IAClB,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,iBAAiB;AAAA,EACnB,CAAC;AACD,yBAAAC,SAAW,GAAG;AACd,QAAM,oBAAoC,CAAC;AAC3C,QAAM,gBAAgB,oBAAI,IAAY;AACtC,aAAW,cAAc,cAAc,EAAE,IAAI,GAAG;AAC9C,QAAI,WAAW,SAAS,GAAG,YAAAF,QAAK,GAAG,UAAU,YAAAA,QAAK,GAAG,EAAE,EAAG;AAC1D,QACE,CAAC,GAAG,gCAAgC,EAAE,KAAK,eAAa,WAAW,SAAS,GAAG,YAAAA,QAAK,GAAG,GAAG,SAAS,GAAG,YAAAA,QAAK,GAAG,EAAE,CAAC,GACjH;AACA;AAAA,IACF;AACA,QAAI,eAAe,KAAM;AACzB,UAAM,SAAS,SAAS,UAAU;AAClC,QAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,cAAc,IAAI,OAAO,GAAG,GAAG;AACpE,oBAAc,IAAI,OAAO,GAAG;AAC5B,wBAAkB,KAAK,MAAM;AAAA,IAC/B;AAAA,EACF;AACA,MAAI,kBAAkB,SAAS,GAAG;AAChC,QAAI,UAAU,iBAAiB;AAAA,EACjC;AACA,QAAM,YAAY,SAAS,IAAI;AAC/B,QAAM,WAAW,IAAI,QAAQ,SAAS;AACtC,IAAE,WAAW,IAAI,UAAU,QAAQ;AACnC,SAAO;AACT;AAEA,SAAS,mBAAmB,WAAuC;AACjE,QAAM,UAAU,UAAU,QAAQ,QAAQ,EAAE;AAC5C,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,aAAa,YAAAA,QAAK,UAAU,OAAO;AACzC,MAAI,WAAW,WAAW,IAAI,KAAK,YAAAA,QAAK,WAAW,UAAU,EAAG,QAAO;AACvE,SAAO;AACT;AAYA,SAAS,eAAe,QAAoC;AAC1D,QAAM,OAAO,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC9C,QAAM,SAAS,OAAO,KAAK,QAAQ,WAAW,KAAK,MAAM;AACzD,QAAM,OAAO,CAAC,SAAwB;AACpC,QAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,iBAAW,QAAQ,KAAM,MAAK,IAAI;AAClC;AAAA,IACF;AACA,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,UAAM,MAAM;AACZ,QAAI,OAAO,IAAI,QAAQ,YAAY,IAAI,QAAQ,QAAQ;AACrD,aAAO,IAAI;AAAA,IACb;AACA,eAAW,SAAS,OAAO,OAAO,GAAG,EAAG,MAAK,KAAK;AAAA,EACpD;AACA,OAAK,IAAI;AACT,SAAO;AACT;AAGO,SAAS,kBAAkB,UAAkB,6BAAwB;AAC1E,QAAM,IAAI,WAAW,OAAO;AAC5B,SAAO,CAAC,GAAG,EAAE,UAAU,KAAK,CAAC,EAAE,KAAK;AACtC;AAcO,SAAS,uBAAuB,UAAkB,6BAAiC;AACxF,QAAM,IAAI,WAAW,OAAO;AAG5B,QAAM,WAAY,EAAE,IAAyD;AAC7E,SAAO,WAAW,OAAO,KAAK,QAAQ,IAAI,CAAC;AAC7C;AAWO,SAAS,gBAAgB,SAA0B;AACxD,MAAI;AACF,sBAAkB,OAAO;AACzB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,MAAM,6BAA6B,oBAAI,IAAsD;AAGtF,SAAS,yBACd,UACA,SACA,UAAkB,6BAC6B;AAC/C,QAAM,OAAO,kBAAkB,OAAO;AACtC,QAAM,WAAW,GAAG,IAAI,IAAS,OAAO,IAAS,QAAQ;AACzD,QAAM,SAAS,2BAA2B,IAAI,QAAQ;AACtD,MAAI,WAAW,OAAW,QAAO,UAAU;AAE3C,QAAM,UAAU,YAAAA,QAAK,KAAK,MAAM,KAAK;AACrC,MAAI,KAAC,sBAAW,OAAO,GAAG;AACxB,+BAA2B,IAAI,UAAU,IAAI;AAC7C,WAAO;AAAA,EACT;AACA,QAAM,uBAAmB,uBAAY,SAAS,EAAE,eAAe,KAAK,CAAC,EAClE,OAAO,WAAS,MAAM,YAAY,CAAC,EACnC,IAAI,WAAS,MAAM,IAAI,EACvB,KAAK,EACL,QAAQ;AACX,aAAW,mBAAmB,kBAAkB;AAC9C,UAAM,cAAc,YAAAA,QAAK,QAAQ,SAAS,iBAAiB,YAAY,OAAO;AAC9E,UAAM,eAAe,YAAAA,QAAK,KAAK,aAAa,eAAe;AAC3D,QAAI,KAAC,sBAAW,YAAY,EAAG;AAC/B,UAAM,WAAW,SAAS,YAAY;AAGtC,UAAM,YAAY,SAAS,QAAQ,QAAQ,GAAG;AAC9C,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,aAAa,YAAAA,QAAK,QAAQ,aAAa,SAAS;AACtD,QAAI,CAAC,WAAW,WAAW,GAAG,WAAW,GAAG,YAAAA,QAAK,GAAG,EAAE,KAAK,KAAC,sBAAW,UAAU,EAAG;AACpF,UAAM,SAAS,OAAO,OAAO,SAAS,UAAU,CAAC;AACjD,+BAA2B,IAAI,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AACA,6BAA2B,IAAI,UAAU,IAAI;AAC7C,SAAO;AACT;AAQO,SAAS,uBAAuB,SAAwB;AAC7D,6BAA2B,MAAM;AACjC,MAAI,YAAY,QAAW;AACzB,WAAO,MAAM;AAAA,EACf,OAAO;AACL,yBAAqB,iBAAiB,OAAO,CAAC;AAAA,EAChD;AACF;AAgCO,SAAS,0BAA0B,UAAkB,OAAe,UAAkB,6BAAuB;AAClH,MAAI;AACF,UAAM,IAAI,WAAW,OAAO;AAC5B,UAAM,WAAW,GAAG,QAAQ;AAC5B,UAAM,OAAO,EAAE,UAAU,IAAI,QAAQ;AACrC,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,SAAS,EAAE,WAAW,IAAI,QAAQ;AACtC,QAAI,CAAC,QAAQ;AACX,eAAS,SAAS,IAAI;AACtB,QAAE,WAAW,IAAI,UAAU,MAAM;AAAA,IACnC;AACA,UAAM,QAAQ,OAAO;AACrB,WAAO,UAAU,UAAa,SAAS;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAkBO,SAAS,4BACd,UACA,UAAkB,6BACW;AAC7B,MAAI;AACF,UAAM,IAAI,WAAW,OAAO;AAC5B,UAAM,WAAW,GAAG,QAAQ;AAC5B,UAAM,SAAS,EAAE,YAAY,IAAI,QAAQ;AACzC,QAAI,OAAQ,QAAO;AACnB,UAAM,OAAO,EAAE,UAAU,IAAI,QAAQ;AACrC,QAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,UAAM,OAAO,SAAS,IAAI;AAC1B,UAAM,QAAQ,oBAAI,IAA8B;AAChD,UAAM,QAAQ,oBAAI,IAAY;AAE9B,UAAM,iBAAiB,CAAC,UAAmB,aAA8B;AACvE,UAAI,CAAC,YAAY,aAAa,IAAK,QAAO;AAC1C,UAAI,CAAC,SAAS,WAAW,IAAI,EAAG,QAAO;AACvC,UAAI,UAAU;AACd,iBAAW,WAAW,SAAS,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG;AAClD,YAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,cAAM,MAAM,QAAQ,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG;AAC1D,kBAAW,QAAoC,GAAG;AAAA,MACpD;AACA,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,CACjB,KACA,aACA,oBACgG;AAChG,YAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,YAAM,UAAU,QAAQ,IAAI,IAAI,MAAM,GAAG,IAAI,IAAI;AACjD,YAAM,WAAW,QAAQ,IAAI,IAAI,MAAM,IAAI,IAAI;AAC/C,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,MAAM,eAAe,iBAAiB,QAAQ;AAAA,UAC9C,MAAM;AAAA,UACN,UAAU;AAAA,UACV,KAAK,GAAG,WAAW,GAAG,QAAQ;AAAA,QAChC;AAAA,MACF;AAEA,YAAM,iBAAiB,QAAQ,MAAM,yBAAyB,IAAI,CAAC;AACnE,YAAM,aAAa;AAAA,QACjB,iBAAiB,YAAAA,QAAK,KAAK,EAAE,MAAM,cAAc,IAAI;AAAA,QACrD,YAAAA,QAAK,QAAQ,YAAAA,QAAK,QAAQ,WAAW,GAAG,OAAO;AAAA,MACjD,EAAE,OAAO,CAAC,cAAmC,cAAc,MAAS;AACpE,UAAI,aAAa,WAAW,KAAK,mBAAa,sBAAW,SAAS,CAAC;AAKnE,UAAI,CAAC,YAAY;AACf,YAAI,CAAC,EAAE,eAAe;AACpB,gBAAM,WAAW,oBAAI,IAAoB;AACzC,qBAAW,cAAc,cAAc,EAAE,IAAI,GAAG;AAC9C,gBAAI;AACF,oBAAM,SAAS,SAAS,UAAU;AAClC,kBAAI,OAAO,OAAO,QAAQ,SAAU,UAAS,IAAI,OAAO,KAAK,UAAU;AAAA,YACzE,QAAQ;AAAA,YAER;AAAA,UACF;AACA,YAAE,gBAAgB;AAAA,QACpB;AACA,qBAAa,EAAE,cAAc,IAAI,OAAO;AAAA,MAC1C;AACA,UAAI,CAAC,WAAY,QAAO;AACxB,YAAM,WAAW,SAAS,UAAU;AACpC,aAAO;AAAA,QACL,MAAM,eAAe,UAAU,QAAQ;AAAA,QACvC,MAAM;AAAA,QACN;AAAA,QACA,KAAK,GAAG,UAAU,GAAG,QAAQ;AAAA,MAC/B;AAAA,IACF;AAEA,UAAM,OAAO,CACX,MACA,cACA,aACA,iBACA,UACS;AACT,UAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,QAAQ,GAAI;AACrD,YAAM,MAAM;AACZ,UAAI,OAAO,IAAI,UAAU,MAAM,YAAY,aAAa,SAAS,GAAG;AAClE,cAAM,aAAa,EAAE,MAAM,CAAC,GAAG,YAAY,GAAG,SAAS,IAAI,UAAU,EAAY;AACjF,cAAM,IAAI,GAAG,WAAW,KAAK,KAAK,GAAG,CAAC,KAAK,WAAW,OAAO,IAAI,UAAU;AAAA,MAC7E;AAEA,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC,cAAM,SAAS,WAAW,IAAI,MAAM,aAAa,eAAe;AAChE,YAAI,UAAU,OAAO,SAAS,QAAW;AACvC,gBAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,aAAa,KAAK,GAAG,CAAC;AACtD,cAAI,CAAC,MAAM,IAAI,KAAK,GAAG;AACrB,kBAAM,IAAI,KAAK;AACf,iBAAK,OAAO,MAAM,cAAc,OAAO,MAAM,OAAO,UAAU,QAAQ,CAAC;AACvE,kBAAM,OAAO,KAAK;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAEA,YAAM,aAAa,IAAI;AACvB,UAAI,cAAc,OAAO,eAAe,YAAY,CAAC,MAAM,QAAQ,UAAU,GAAG;AAC9E,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAqC,GAAG;AAChF,eAAK,OAAO,CAAC,GAAG,cAAc,GAAG,GAAG,aAAa,iBAAiB,QAAQ,CAAC;AAAA,QAC7E;AAAA,MACF;AACA,UAAI,IAAI,UAAU,QAAW;AAC3B,aAAK,IAAI,OAAO,CAAC,GAAG,cAAc,GAAG,GAAG,aAAa,iBAAiB,QAAQ,CAAC;AAAA,MACjF;AACA,iBAAW,WAAW,CAAC,SAAS,SAAS,OAAO,GAAY;AAC1D,cAAM,WAAW,IAAI,OAAO;AAC5B,YAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,qBAAW,UAAU,SAAU,MAAK,QAAQ,cAAc,aAAa,iBAAiB,QAAQ,CAAC;AAAA,QACnG;AAAA,MACF;AACA,iBAAW,WAAW,CAAC,MAAM,QAAQ,QAAQ,KAAK,GAAY;AAC5D,YAAI,IAAI,OAAO,MAAM,QAAW;AAC9B,eAAK,IAAI,OAAO,GAAG,cAAc,aAAa,iBAAiB,QAAQ,CAAC;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AAEA,SAAK,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC;AAC5B,UAAM,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAChD,YAAM,SAAS,EAAE,KAAK,KAAK,GAAG,EAAE,cAAc,EAAE,KAAK,KAAK,GAAG,CAAC;AAC9D,aAAO,UAAU,EAAE,QAAQ,cAAc,EAAE,OAAO;AAAA,IACpD,CAAC;AACD,MAAE,YAAY,IAAI,UAAU,MAAM;AAClC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAeO,SAAS,uBAAuB,WAAmB,YAAoB,UAAkB,6BAAuB;AACrH,MAAI;AACF,UAAM,IAAI,WAAW,OAAO;AAC5B,UAAM,aAAa,mBAAmB,SAAS;AAC/C,QAAI,CAAC,WAAY,QAAO;AAExB,UAAM,WAAW,eAAe,UAAU;AAC1C,UAAM,OAAO,YAAAA,QAAK,KAAK,EAAE,MAAM,UAAU;AACzC,QAAI,KAAC,sBAAW,IAAI,EAAG,QAAO;AAE9B,QAAI,SAAS,EAAE,WAAW,IAAI,QAAQ;AACtC,QAAI,CAAC,QAAQ;AACX,eAAS,SAAS,IAAI;AACtB,QAAE,WAAW,IAAI,UAAU,MAAM;AAAA,IACnC;AAEA,UAAM,OAAO,0BAA0B,QAAQ,UAAU;AACzD,QAAI,CAAC,QAAQ,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,SAAS,EAAG,QAAO;AAC5E,WAAO,eAAgB,KAA8B,OAAO;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,0BACP,QACA,YACqC;AACrC,MAAI,UAAmB;AACvB,aAAW,OAAO,WAAW,MAAM,GAAG,GAAG;AACvC,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,UAAM,QAAS,QAAoC;AACnD,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,OAAO,GAAG,EAAG,QAAO;AAC9D,cAAW,MAAkC,GAAG;AAAA,EAClD;AACA,SAAO,WAAW,OAAO,YAAY,WAAY,UAAsC;AACzF;AAEA,SAAS,eAAe,OAAyB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,SAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACzC;","names":["path","Ajv","addFormats"]}
|