@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/platform.ts"],"sourcesContent":["/**\n * DecisioningPlatform — the top-level interface adopters implement.\n *\n * Per-specialism sub-interfaces (sales, creative, audiences, etc.) are\n * optional; framework's compile-time enforcement (RequiredPlatformsFor<S>)\n * forces the right sub-interfaces based on `capabilities.specialisms[]`.\n *\n * Status: Preview / 6.0. Not yet wired into the framework.\n *\n * @public\n */\n\nimport type { DecisioningCapabilities, BrandCapabilities } from './capabilities';\nimport type { Account, AccountStore } from './account';\nimport type { BuyerAgentRegistry } from './buyer-agent';\nimport type { SessionContext, OnInstructionsError, MaybePromise } from '../create-adcp-server';\nimport type { StatusMappers } from './status-mappers';\nimport type { SalesPlatform, SalesCorePlatform, SalesIngestionPlatform } from './specialisms/sales';\nimport type { ProposalManager, Recipe } from './proposal';\nimport type { CreativeBuilderPlatform } from './specialisms/creative';\nimport type { CreativeAdServerPlatform } from './specialisms/creative-ad-server';\nimport type { AudiencePlatform } from './specialisms/audiences';\nimport type { SignalsPlatform } from './specialisms/signals';\nimport type { SponsoredIntelligencePlatform } from './specialisms/sponsored-intelligence';\nimport type { CampaignGovernancePlatform } from './specialisms/campaign-governance';\nimport type { ContentStandardsPlatform } from './specialisms/content-standards';\nimport type { BrandRightsPlatform } from './specialisms/brand-rights';\nimport type { PropertyListsPlatform, CollectionListsPlatform } from './specialisms/lists';\nimport type { AdCPSpecialism } from '../../types/tools.generated';\n\n/**\n * Top-level platform interface. Adopters implement this; framework wires\n * the wire protocol around it.\n *\n * The \"framework owns X\" claims below are the v6.0 wiring contract — the\n * runtime guarantees the framework will provide once this surface is wired.\n * They are NOT yet enforced; this module is preview-only as of the scaffold\n * landing. Treat them as the design contract a v6.0 reviewer should hold\n * the framework refactor to, not as a description of existing behavior.\n *\n * **What the framework owns** (platform implementations DON'T see these):\n * - Wire-shape mapping (MCP tools/list, A2A skill manifest, request/response envelopes)\n * - Authentication + auth-principal extraction; `accounts.resolve()` is the only\n * place the platform translates auth into its tenant model\n * - Idempotency: dedupe + replay handled before dispatch; platforms see clean traffic\n * - `sandbox` boundary: when `AccountReference.sandbox === true`, framework\n * resolves the buyer's sandbox account via `accounts.resolve()`. The platform\n * sees the resolved sandbox `Account` like any other and is responsible for\n * routing reads/writes to its sandbox backend. There is no separate\n * \"dry-run\" mode — sandbox subsumes \"validate against real platform without\n * writing to production.\" Tool-specific `dry_run` flags on `sync_catalogs`\n * and `sync_creatives` are wire fields the platform receives and honors;\n * they are NOT a framework-level mode.\n * - `context` echo: framework round-trips `context` on every response\n * - Task envelopes: `submitted` outcomes are wrapped into A2A Task envelopes /\n * MCP polling responses; `taskHandle.notify` calls dedupe + retry\n * - Schema validation: requests fail before reaching the platform; responses are\n * shape-validated against the wire schema after the platform returns\n *\n * **What the platform owns**: the business decisions in each `SalesPlatform` /\n * `CreativeBuilderPlatform` / `AudiencePlatform` method. Nothing else.\n *\n * ### Cross-specialism dispatch\n *\n * When one specialism handler needs to consult another (canonical case:\n * `brandRights.acquireRights` calling `campaignGovernance.checkGovernance`\n * before granting rights, against a buyer-registered governance binding),\n * the framework does NOT thread a separate `ctx.platform.<specialism>`\n * accessor on `RequestContext`. Two idiomatic patterns; pick by authoring\n * style:\n *\n * **Pattern A — class instance + `this`** (canonical for holdco hubs;\n * `examples/hello_seller_adapter_multi_tenant.ts` is the reference):\n *\n * ```ts\n * class HoldcoAdapter implements DecisioningPlatform<Config, TenantMeta> {\n * campaignGovernance = defineCampaignGovernancePlatform<TenantMeta>({ });\n * brandRights = defineBrandRightsPlatform<TenantMeta>({\n * acquireRights: async (req, ctx) => {\n * const denial = await this.enforceGovernance(tenant, ctx, offering, req);\n * if (denial) return denial;\n *\n * },\n * });\n * private async enforceGovernance(...) {\n * // calls this.campaignGovernance.checkGovernance(...)\n * }\n * }\n * ```\n *\n * **Pattern B — closure capture** (for adopters using `define<X>Platform({...})`\n * factories standalone):\n *\n * ```ts\n * const campaignGovernance = defineCampaignGovernancePlatform<TenantMeta>({ ... });\n * const brandRights = defineBrandRightsPlatform<TenantMeta>({\n * acquireRights: async (req, ctx) => {\n * const govResp = await campaignGovernance.checkGovernance!(checkReq, ctx);\n *\n * },\n * });\n * const platform: DecisioningPlatform<Config, TenantMeta> = {\n * capabilities: { }, accounts: { }, campaignGovernance, brandRights,\n * };\n * ```\n *\n * Both patterns forward the same `RequestContext` (resolved account, agent,\n * authInfo), so tenant invariants hold transitively. Both bypass wire-side\n * validation, idempotency dedup, and mutating-tool annotations — that's\n * correct because you're inside the seller's code, not handling a buyer\n * request, but it means an in-process `checkGovernance` won't be\n * re-deduped if the originating tool is already idempotency-protected.\n * Single-specialism adopters MUST NOT copy this short-circuit: without a\n * co-resident sibling handler, dial out to the registered governance\n * agent URL via the `@adcp/sdk` client instead.\n *\n * Full walkthrough with same-tenant invariant + production caveats:\n * `skills/build-holdco-agent/SKILL.md` § Cross-specialism dispatch.\n *\n * @template TConfig Platform-specific config typed at the call site.\n * Example: `class GAM implements DecisioningPlatform<{ networkId: string }>`.\n * @template TCtxMeta Shape of the platform's opaque ctx_metadata blob — typed\n * once and propagated into `ctx.account.ctx_metadata`,\n * `ctx.ctxMetadata.get()`, and every specialism handler.\n */\nexport interface DecisioningPlatform<TConfig = unknown, TCtxMeta = Record<string, unknown>> {\n /** Capability declaration; single source of truth for get_adcp_capabilities. */\n capabilities: DecisioningCapabilities<TConfig>;\n\n /** Account model + tenant resolution. */\n accounts: AccountStore<TCtxMeta>;\n\n /**\n * Server-level instructions surfaced on the MCP `initialize` response.\n * Use to publish platform facts, decision policy, and trends that buying\n * agents should read before issuing tool calls (e.g., \"publisher-wide\n * brand safety: alcohol disallowed\", \"carbon-aware pricing applies to\n * display impressions only\", \"weekly cutoff Thursday 17:00 UTC\").\n *\n * Two forms:\n *\n * 1. **Static string** — captured once at construction.\n * 2. **Function** `(ctx: SessionContext) => MaybePromise<string | undefined>` —\n * re-evaluated each time `createAdcpServerFromPlatform` runs. Under the\n * canonical `serve({ reuseAgent: false })` flow that is per session, so the\n * closure can surface tenant-shaped prose (per-buyer brand manifests,\n * storefront-platform copy). `serve()` refuses `reuseAgent: true`\n * when this is a function — the function would only fire once for\n * the lifetime of the shared agent.\n *\n * Async functions are supported: the framework calls the function at\n * construction and awaits the returned Promise during MCP `initialize`.\n * A rejected Promise is governed by `onInstructionsError`.\n *\n * MCP-only today. The A2A `AgentCard` analog is `description` (and\n * per-skill `description`); threading platform.instructions into the\n * agent-card builder is tracked separately so MCP and A2A buyers see\n * the same prose.\n *\n * When set on the platform, takes precedence over any `instructions`\n * supplied via `createAdcpServerFromPlatform` opts — same precedence as\n * `agentRegistry`. Adopters with v5 escape-hatch wiring can keep using\n * `opts.instructions`; v6 callers should declare it here.\n *\n * @see {@link OnInstructionsError} for `onInstructionsError` (default `'skip'`).\n */\n instructions?: string | ((ctx: SessionContext) => MaybePromise<string | undefined>);\n\n /**\n * Behavior when a function-form `instructions` callback throws.\n * Defaults to `'skip'` — best-effort prose (brand manifests, marketing\n * copy) should not kill the buyer's session on a registry fetch failure.\n * Set `'fail'` for adopters whose instructions carry load-bearing policy.\n *\n * Threaded through to {@link createAdcpServer} unchanged.\n */\n onInstructionsError?: OnInstructionsError;\n\n /**\n * Buyer-agent identity registry. Optional. When\n * configured, framework calls `agentRegistry.resolve(authInfo)` once per\n * request before `accounts.resolve` and threads the resolved record\n * through `ctx.agent` to specialism handlers.\n *\n * Adopters construct via {@link BuyerAgentRegistry.signingOnly},\n * {@link BuyerAgentRegistry.bearerOnly}, or {@link BuyerAgentRegistry.mixed}\n * depending on their authentication posture. When omitted, `ctx.agent`\n * is always undefined and the framework's request flow is unchanged.\n *\n * The resolved record drives framework status/sandbox gates and\n * `sync_accounts.billing` enforcement against\n * `BuyerAgent.billing_capabilities`.\n */\n agentRegistry?: BuyerAgentRegistry;\n\n /**\n * Native-status mappers (account, mediaBuy, creative, plan).\n *\n * **Optional.** Default behavior treats the platform's status strings as\n * already-canonical AdCP status values (no translation). Provide mappers\n * only when your platform exposes non-AdCP status strings (e.g., GAM's\n * `DELIVERY_PAUSED` → AdCP's `paused`).\n */\n statusMappers?: StatusMappers;\n\n /**\n * Per-tenant capability override. Multi-tenant SaaS adopters (Prebid-style\n * deployments where one server hosts many advertisers, each with different\n * `manualApprovalOperations` / pricing tiers / channel mixes) implement this\n * to scope capabilities per resolved Account. When absent, the framework\n * uses `capabilities` for every request.\n *\n * The framework calls this AFTER `accounts.resolve()` and uses the returned\n * capabilities to gate the rest of the request. The static `agent-card.json`\n * AND `tools/list` shape is derived from `capabilities` (the union) — per-tenant\n * differences are runtime-only.\n */\n getCapabilitiesFor?(\n account: Account<TCtxMeta>\n ): DecisioningCapabilities<TConfig> | Promise<DecisioningCapabilities<TConfig>>;\n\n // Per-specialism sub-interfaces — optional at the type level; required at the\n // call site by RequiredPlatformsFor<S>. v1.0 ships these. Each is parameterized\n // by `TCtxMeta` so adopters get typed `ctx.account.ctx_metadata` access in their\n // method bodies without casting.\n sales?: SalesPlatform<TCtxMeta>;\n creative?: CreativeBuilderPlatform<TCtxMeta> | CreativeAdServerPlatform<TCtxMeta>;\n audiences?: AudiencePlatform<TCtxMeta>;\n signals?: SignalsPlatform<TCtxMeta>;\n /**\n * Sponsored Intelligence implementation. In AdCP 3.1 this field is required\n * when the agent claims the `sponsored-intelligence` specialism. The\n * framework also derives the legacy wire protocol entry\n * `supported_protocols: ['sponsored_intelligence']` from the SI tool set so\n * protocol-bundle storyboards and 3.0-era consumers keep working.\n */\n sponsoredIntelligence?: SponsoredIntelligencePlatform<TCtxMeta>;\n /** @see DecisioningPlatform — § Cross-specialism dispatch (used as the canonical example: `brandRights.acquireRights` consulting `checkGovernance` before granting rights). */\n campaignGovernance?: CampaignGovernancePlatform<TCtxMeta>;\n contentStandards?: ContentStandardsPlatform<TCtxMeta>;\n propertyLists?: PropertyListsPlatform<TCtxMeta>;\n collectionLists?: CollectionListsPlatform<TCtxMeta>;\n /** @see DecisioningPlatform — § Cross-specialism dispatch (`acquireRights` is the canonical caller into `campaignGovernance.checkGovernance`). */\n brandRights?: BrandRightsPlatform<TCtxMeta>;\n\n /**\n * Optional sibling that owns the proposal side of the two-platform\n * composition (port of `adcp-client-python`'s `ProposalManager`). When\n * present, the framework routes `get_products` and refine traffic to\n * the manager instead of `sales.getProducts`; `sales` stays\n * responsible for media-buy execution. Either side can be mock-backed\n * independently — see `MockProposalManager`.\n *\n * **Status**: primitive types only. Framework dispatch wiring (the\n * five seams that intercept `getProducts`, `createMediaBuy`,\n * `updateMediaBuy`, `getMediaBuyDelivery` to persist drafts, hydrate\n * recipes, and commit on finalize) lands in a follow-up release. v1.5\n * adopters can already implement against this surface; the framework\n * just doesn't drive the lifecycle yet.\n */\n proposalManager?: ProposalManager<Recipe, TCtxMeta>;\n\n // v1.1+ specialisms add: creative-review.\n}\n\n// ---------------------------------------------------------------------------\n// Compile-time capability enforcement\n// ---------------------------------------------------------------------------\n\n/**\n * Maps an AdCP specialism to the platform interface(s) it requires. The\n * framework's `createAdcpServer<P extends DecisioningPlatform>` constrains\n * `P` to satisfy `RequiredPlatformsFor<P['capabilities']['specialisms'][number]>`,\n * forcing every claimed specialism's interface methods to exist.\n *\n * Drop a method, fail compile.\n * Claim a specialism without an implementation, fail compile.\n *\n * The nested-conditional encoding (rather than a union of `S extends X ? {} : never`)\n * is deliberate: when a specialism is claimed without its required platform\n * interface, TypeScript surfaces \"Property 'sales' is missing in type 'P'\"\n * rather than the unactionable \"Type 'P' does not satisfy the constraint 'never'.\"\n *\n * v1.0 covers the 4 specialisms shipping in v1.0; extended in v1.1+.\n * Unknown specialisms (v1.1+ when this module hasn't been updated yet)\n * resolve to an empty requirement — the framework's runtime check is the\n * fallback gate.\n */\n// Sales specialisms — split into two groups by what the adopter actually owns.\n//\n// - **Core sales** specialisms run their own bidding + media-buy lifecycle and\n// are required to implement `SalesCorePlatform` (`getProducts`,\n// `createMediaBuy`, `updateMediaBuy`, `getMediaBuyDelivery`, `getMediaBuys`).\n// The retail-media variants additionally compose ingestion surfaces.\n// - **Ingestion-only** specialisms (today: `sales-social`) front a walled-\n// garden CAPI / audience surface that owns bidding upstream — adopters only\n// need `SalesIngestionPlatform` (`syncCreatives` / `syncCatalogs` /\n// `syncEventSources` / `logEvent` / etc., all optional individually).\n// - **Proposal mode** is a hybrid — only `getProducts` is required; the rest\n// of the lifecycle flows through notification channels.\n//\n// Wired per the AdCP 3.0 GA enum; preview specialisms (sales-streaming-tv,\n// sales-exchange, sales-retail-media) get added when they land in spec.\ntype SalesCoreSpecialism = 'sales-non-guaranteed' | 'sales-guaranteed' | 'sales-broadcast-tv' | 'sales-catalog-driven';\ntype SalesIngestionSpecialism = 'sales-social';\ntype SalesProposalSpecialism = 'sales-proposal-mode';\n\n// Signal specialisms — both share the SignalsPlatform interface. Marketplace\n// = third-party data brokers; owned = first-party data providers.\ntype SignalSpecialism = 'signal-marketplace' | 'signal-owned';\n\n// Today's spec splits campaign governance into spend-authority + delivery-monitor;\n// both share one CampaignGovernancePlatform interface. When adcp#3329 lands and\n// the spec consolidates to `campaign-governance`, this union shrinks to one\n// value without shape changes.\ntype CampaignGovernanceSpecialism = 'governance-spend-authority' | 'governance-delivery-monitor';\n\n// `TCtxMeta` defaults to `any` so callers that don't pass it explicitly (the\n// common case — `RequiredPlatformsFor<S>` without a second argument) get a\n// constraint that accepts any adopter metadata shape. The `any` is not a\n// soundness escape — adopters declare metadata inside `DecisioningPlatform<_,\n// TCtxMeta>` directly; this constraint exists only to compile-check that\n// claimed specialisms have a matching sub-interface field on the platform.\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type RequiredPlatformsFor<\n S extends AdCPSpecialism,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n TCtxMeta = any,\n> = [S] extends [never]\n ? // Empty specialisms[] (legitimate when the agent's only declared\n // surface is a protocol or custom tool that is not represented as an\n // AdCP specialism).\n // `[S] extends [never]` short-circuits the distributive conditional —\n // without this, a generic `S extends ...` over `never` yields `never`,\n // collapsing `P & RequiredPlatformsFor<...>` to `never` and rejecting\n // every platform value at the call site.\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {}\n : S extends 'creative-template' | 'creative-generative' | 'creative-transformers'\n ? { creative: CreativeBuilderPlatform<TCtxMeta> }\n : S extends 'creative-ad-server'\n ? { creative: CreativeAdServerPlatform<TCtxMeta> }\n : S extends SalesCoreSpecialism\n ? { sales: SalesCorePlatform<TCtxMeta> & SalesIngestionPlatform<TCtxMeta> }\n : S extends SalesIngestionSpecialism\n ? // Walled-garden specialisms (sales-social, today). Bidding owned upstream\n // — only the ingestion surface is required. Adopters can voluntarily\n // implement core methods on the same `sales` object; the SalesPlatform\n // alias accepts both shapes.\n { sales: SalesIngestionPlatform<TCtxMeta> }\n : S extends SalesProposalSpecialism\n ? // Proposal-mode adopters only need `getProducts` — the rest of the\n // lifecycle flows through `publishStatusChange` on\n // `resource_type: 'proposal'`. Ingestion is optional.\n { sales: Required<Pick<SalesPlatform<TCtxMeta>, 'getProducts'>> & SalesIngestionPlatform<TCtxMeta> }\n : S extends 'audience-sync'\n ? { audiences: AudiencePlatform<TCtxMeta> }\n : S extends SignalSpecialism\n ? { signals: SignalsPlatform<TCtxMeta> }\n : S extends CampaignGovernanceSpecialism\n ? { campaignGovernance: CampaignGovernancePlatform<TCtxMeta> }\n : S extends 'sponsored-intelligence'\n ? { sponsoredIntelligence: SponsoredIntelligencePlatform<TCtxMeta> }\n : S extends 'property-lists'\n ? { propertyLists: PropertyListsPlatform<TCtxMeta> }\n : S extends 'collection-lists'\n ? { collectionLists: CollectionListsPlatform<TCtxMeta> }\n : S extends 'content-standards'\n ? { contentStandards: ContentStandardsPlatform<TCtxMeta> }\n : S extends 'brand-rights'\n ? { brandRights: BrandRightsPlatform<TCtxMeta> }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {};\n// `{}` (not `Record<string, never>`) is the right \"no extra requirements\"\n// fallthrough — intersects to identity (`P & {} = P`) for specialisms\n// without platform constraints. Same reasoning RequiredCapabilitiesFor\n// documents at its own fall-through. `Record<string, never>` would force\n// the platform to have NO extra properties, collapsing `P & Record<string,\n// never>` to `never` for any platform with handler fields.\n\n/**\n * The framework's createAdcpServer<P> signature uses this intersection to\n * enforce capability claims at compile time. Sketch:\n *\n * ```ts\n * declare function createAdcpServer<P extends DecisioningPlatform>(config: {\n * platform: P & RequiredPlatformsFor<P['capabilities']['specialisms'][number]>;\n * }): AdcpServer;\n * ```\n *\n * NOTE: The companion file is preview-only; the actual `createAdcpServer`\n * doesn't yet enforce this. Wiring lands in a follow-up PR with the\n * framework refactor.\n */\n\n/**\n * Compile-time mapping from a claimed specialism to the capability\n * blocks the framework requires on `DecisioningCapabilities`. Sister\n * type to `RequiredPlatformsFor<S>` — that one constrains the per-\n * specialism platform interfaces; this one constrains capability-block\n * declarations on `capabilities.*`.\n *\n * Mappings populated conservatively in v1.0:\n *\n * - `'brand-rights'` → `{ brand: BrandCapabilities }`. Adopters\n * claiming brand-rights MUST declare `capabilities.brand`. The\n * framework auto-derives `rights: true` from the\n * `BrandRightsPlatform` impl, but adopters still need to declare\n * the block (even as `{}`) so `right_types`, `available_uses`,\n * etc. land coherently in `get_adcp_capabilities`.\n *\n * Other specialisms have no required capability blocks today —\n * `audience_targeting` is recommended for `audience-sync` adopters but\n * not enforced (some sync platforms accept anonymous IDs only and\n * legitimately have no `supported_identifier_types` to declare).\n *\n * The `& Record<string, never>` fallthrough means specialisms not\n * mapped here add no constraint — adopters can claim them without\n * declaring extra capability blocks.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type RequiredCapabilitiesFor<S extends AdCPSpecialism> = S extends 'brand-rights'\n ? { capabilities: { brand: BrandCapabilities } }\n : {};\n// `{}` (not `Record<string, never>`) is the right \"no extra requirements\"\n// fallthrough: it intersects to identity (`P & {} = P`) for specialisms\n// without capability constraints. `Record<string, never>` would force the\n// platform to have NO extra properties, which would reject every real\n// platform impl.\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/server/decisioning/platform.ts"],"sourcesContent":["/**\n * DecisioningPlatform — the top-level interface adopters implement.\n *\n * Per-specialism sub-interfaces (sales, creative, audiences, etc.) are\n * optional; framework's compile-time enforcement (RequiredPlatformsFor<S>)\n * forces the right sub-interfaces based on `capabilities.specialisms[]`.\n *\n * Status: Preview / 6.0. Not yet wired into the framework.\n *\n * @public\n */\n\nimport type { DecisioningCapabilities, BrandCapabilities } from './capabilities';\nimport type { Account, AccountStore } from './account';\nimport type { BuyerAgentRegistry } from './buyer-agent';\nimport type { SessionContext, OnInstructionsError, MaybePromise } from '../create-adcp-server';\nimport type { StatusMappers } from './status-mappers';\nimport type {\n SalesPlatform,\n SalesCorePlatform,\n SalesIngestionPlatform,\n MediaBuyLifecyclePlatform,\n MediaBuyLifecycleCorePlatform,\n MediaBuyLifecycleProposalPlatform,\n} from './specialisms/sales';\nimport type { ProposalManager, Recipe } from './proposal';\nimport type { CreativeBuilderPlatform } from './specialisms/creative';\nimport type { CreativeAdServerPlatform } from './specialisms/creative-ad-server';\nimport type { AudiencePlatform } from './specialisms/audiences';\nimport type { SignalsPlatform } from './specialisms/signals';\nimport type { SponsoredIntelligencePlatform } from './specialisms/sponsored-intelligence';\nimport type { CampaignGovernancePlatform } from './specialisms/campaign-governance';\nimport type { ContentStandardsPlatform } from './specialisms/content-standards';\nimport type { BrandRightsPlatform } from './specialisms/brand-rights';\nimport type { PropertyListsPlatform, CollectionListsPlatform } from './specialisms/lists';\nimport type { AdCPSpecialism } from '../../types/tools.generated';\n\n/**\n * Top-level platform interface. Adopters implement this; framework wires\n * the wire protocol around it.\n *\n * The \"framework owns X\" claims below are the v6.0 wiring contract — the\n * runtime guarantees the framework will provide once this surface is wired.\n * They are NOT yet enforced; this module is preview-only as of the scaffold\n * landing. Treat them as the design contract a v6.0 reviewer should hold\n * the framework refactor to, not as a description of existing behavior.\n *\n * **What the framework owns** (platform implementations DON'T see these):\n * - Wire-shape mapping (MCP tools/list, A2A skill manifest, request/response envelopes)\n * - Authentication + auth-principal extraction; `accounts.resolve()` is the only\n * place the platform translates auth into its tenant model\n * - Idempotency: dedupe + replay handled before dispatch; platforms see clean traffic\n * - `sandbox` boundary: when `AccountReference.sandbox === true`, framework\n * resolves the buyer's sandbox account via `accounts.resolve()`. The platform\n * sees the resolved sandbox `Account` like any other and is responsible for\n * routing reads/writes to its sandbox backend. There is no separate\n * \"dry-run\" mode — sandbox subsumes \"validate against real platform without\n * writing to production.\" Tool-specific `dry_run` flags on `sync_catalogs`\n * and `sync_creatives` are wire fields the platform receives and honors;\n * they are NOT a framework-level mode.\n * - `context` echo: framework round-trips `context` on every response\n * - Task envelopes: `submitted` outcomes are wrapped into A2A Task envelopes /\n * MCP polling responses; `taskHandle.notify` calls dedupe + retry\n * - Schema validation: requests fail before reaching the platform; responses are\n * shape-validated against the wire schema after the platform returns\n *\n * **What the platform owns**: the business decisions in each `SalesPlatform` /\n * `CreativeBuilderPlatform` / `AudiencePlatform` method. Nothing else.\n *\n * ### Cross-specialism dispatch\n *\n * When one specialism handler needs to consult another (canonical case:\n * `brandRights.acquireRights` calling `campaignGovernance.checkGovernance`\n * before granting rights, against a buyer-registered governance binding),\n * the framework does NOT thread a separate `ctx.platform.<specialism>`\n * accessor on `RequestContext`. Two idiomatic patterns; pick by authoring\n * style:\n *\n * **Pattern A — class instance + `this`** (canonical for holdco hubs;\n * `examples/hello_seller_adapter_multi_tenant.ts` is the reference):\n *\n * ```ts\n * class HoldcoAdapter implements DecisioningPlatform<Config, TenantMeta> {\n * campaignGovernance = defineCampaignGovernancePlatform<TenantMeta>({ });\n * brandRights = defineBrandRightsPlatform<TenantMeta>({\n * acquireRights: async (req, ctx) => {\n * const denial = await this.enforceGovernance(tenant, ctx, offering, req);\n * if (denial) return denial;\n *\n * },\n * });\n * private async enforceGovernance(...) {\n * // calls this.campaignGovernance.checkGovernance(...)\n * }\n * }\n * ```\n *\n * **Pattern B — closure capture** (for adopters using `define<X>Platform({...})`\n * factories standalone):\n *\n * ```ts\n * const campaignGovernance = defineCampaignGovernancePlatform<TenantMeta>({ ... });\n * const brandRights = defineBrandRightsPlatform<TenantMeta>({\n * acquireRights: async (req, ctx) => {\n * const govResp = await campaignGovernance.checkGovernance!(checkReq, ctx);\n *\n * },\n * });\n * const platform: DecisioningPlatform<Config, TenantMeta> = {\n * capabilities: { }, accounts: { }, campaignGovernance, brandRights,\n * };\n * ```\n *\n * Both patterns forward the same `RequestContext` (resolved account, agent,\n * authInfo), so tenant invariants hold transitively. Both bypass wire-side\n * validation, idempotency dedup, and mutating-tool annotations — that's\n * correct because you're inside the seller's code, not handling a buyer\n * request, but it means an in-process `checkGovernance` won't be\n * re-deduped if the originating tool is already idempotency-protected.\n * Single-specialism adopters MUST NOT copy this short-circuit: without a\n * co-resident sibling handler, dial out to the registered governance\n * agent URL via the `@adcp/sdk` client instead.\n *\n * Full walkthrough with same-tenant invariant + production caveats:\n * `skills/build-holdco-agent/SKILL.md` § Cross-specialism dispatch.\n *\n * @template TConfig Platform-specific config typed at the call site.\n * Example: `class GAM implements DecisioningPlatform<{ networkId: string }>`.\n * @template TCtxMeta Shape of the platform's opaque ctx_metadata blob — typed\n * once and propagated into `ctx.account.ctx_metadata`,\n * `ctx.ctxMetadata.get()`, and every specialism handler.\n */\nexport interface DecisioningPlatform<TConfig = unknown, TCtxMeta = Record<string, unknown>> {\n /** Capability declaration; single source of truth for get_adcp_capabilities. */\n capabilities: DecisioningCapabilities<TConfig>;\n\n /** Account model + tenant resolution. */\n accounts: AccountStore<TCtxMeta>;\n\n /**\n * Server-level instructions surfaced on the MCP `initialize` response.\n * Use to publish platform facts, decision policy, and trends that buying\n * agents should read before issuing tool calls (e.g., \"publisher-wide\n * brand safety: alcohol disallowed\", \"carbon-aware pricing applies to\n * display impressions only\", \"weekly cutoff Thursday 17:00 UTC\").\n *\n * Two forms:\n *\n * 1. **Static string** — captured once at construction.\n * 2. **Function** `(ctx: SessionContext) => MaybePromise<string | undefined>` —\n * re-evaluated each time `createAdcpServerFromPlatform` runs. Under the\n * canonical `serve({ reuseAgent: false })` flow that is per session, so the\n * closure can surface tenant-shaped prose (per-buyer brand manifests,\n * storefront-platform copy). `serve()` refuses `reuseAgent: true`\n * when this is a function — the function would only fire once for\n * the lifetime of the shared agent.\n *\n * Async functions are supported: the framework calls the function at\n * construction and awaits the returned Promise during MCP `initialize`.\n * A rejected Promise is governed by `onInstructionsError`.\n *\n * MCP-only today. The A2A `AgentCard` analog is `description` (and\n * per-skill `description`); threading platform.instructions into the\n * agent-card builder is tracked separately so MCP and A2A buyers see\n * the same prose.\n *\n * When set on the platform, takes precedence over any `instructions`\n * supplied via `createAdcpServerFromPlatform` opts — same precedence as\n * `agentRegistry`. Adopters with v5 escape-hatch wiring can keep using\n * `opts.instructions`; v6 callers should declare it here.\n *\n * @see {@link OnInstructionsError} for `onInstructionsError` (default `'skip'`).\n */\n instructions?: string | ((ctx: SessionContext) => MaybePromise<string | undefined>);\n\n /**\n * Behavior when a function-form `instructions` callback throws.\n * Defaults to `'skip'` — best-effort prose (brand manifests, marketing\n * copy) should not kill the buyer's session on a registry fetch failure.\n * Set `'fail'` for adopters whose instructions carry load-bearing policy.\n *\n * Threaded through to {@link createAdcpServer} unchanged.\n */\n onInstructionsError?: OnInstructionsError;\n\n /**\n * Buyer-agent identity registry. Optional. When\n * configured, framework calls `agentRegistry.resolve(authInfo)` once per\n * request before `accounts.resolve` and threads the resolved record\n * through `ctx.agent` to specialism handlers.\n *\n * Adopters construct via {@link BuyerAgentRegistry.signingOnly},\n * {@link BuyerAgentRegistry.bearerOnly}, or {@link BuyerAgentRegistry.mixed}\n * depending on their authentication posture. When omitted, `ctx.agent`\n * is always undefined and the framework's request flow is unchanged.\n *\n * The resolved record drives framework status/sandbox gates and\n * `sync_accounts.billing` enforcement against\n * `BuyerAgent.billing_capabilities`.\n */\n agentRegistry?: BuyerAgentRegistry;\n\n /**\n * Native-status mappers (account, mediaBuy, creative, plan).\n *\n * **Optional.** Default behavior treats the platform's status strings as\n * already-canonical AdCP status values (no translation). Provide mappers\n * only when your platform exposes non-AdCP status strings (e.g., GAM's\n * `DELIVERY_PAUSED` → AdCP's `paused`).\n */\n statusMappers?: StatusMappers;\n\n /**\n * Per-tenant capability override. Multi-tenant SaaS adopters (Prebid-style\n * deployments where one server hosts many advertisers, each with different\n * `manualApprovalOperations` / pricing tiers / channel mixes) implement this\n * to scope capabilities per resolved Account. When absent, the framework\n * uses `capabilities` for every request.\n *\n * The framework calls this AFTER `accounts.resolve()` and uses the returned\n * capabilities to gate the rest of the request. The static `agent-card.json`\n * AND `tools/list` shape is derived from `capabilities` (the union) — per-tenant\n * differences are runtime-only.\n */\n getCapabilitiesFor?(\n account: Account<TCtxMeta>\n ): DecisioningCapabilities<TConfig> | Promise<DecisioningCapabilities<TConfig>>;\n\n // Per-specialism sub-interfaces — optional at the type level; required at the\n // call site by RequiredPlatformsFor<S>. v1.0 ships these. Each is parameterized\n // by `TCtxMeta` so adopters get typed `ctx.account.ctx_metadata` access in their\n // method bodies without casting.\n sales?: SalesPlatform<TCtxMeta>;\n /** Primary AdCP 3.2 media-buy lifecycle; compose with `sales` for 3.0/3.1 compatibility routes. */\n mediaBuyLifecycle?: MediaBuyLifecyclePlatform<TCtxMeta>;\n creative?: CreativeBuilderPlatform<TCtxMeta> | CreativeAdServerPlatform<TCtxMeta>;\n audiences?: AudiencePlatform<TCtxMeta>;\n signals?: SignalsPlatform<TCtxMeta>;\n /**\n * Sponsored Intelligence implementation. In AdCP 3.1 this field is required\n * when the agent claims the `sponsored-intelligence` specialism. The\n * framework also derives the legacy wire protocol entry\n * `supported_protocols: ['sponsored_intelligence']` from the SI tool set so\n * protocol-bundle storyboards and 3.0-era consumers keep working.\n */\n sponsoredIntelligence?: SponsoredIntelligencePlatform<TCtxMeta>;\n /** @see DecisioningPlatform — § Cross-specialism dispatch (used as the canonical example: `brandRights.acquireRights` consulting `checkGovernance` before granting rights). */\n campaignGovernance?: CampaignGovernancePlatform<TCtxMeta>;\n contentStandards?: ContentStandardsPlatform<TCtxMeta>;\n propertyLists?: PropertyListsPlatform<TCtxMeta>;\n collectionLists?: CollectionListsPlatform<TCtxMeta>;\n /** @see DecisioningPlatform — § Cross-specialism dispatch (`acquireRights` is the canonical caller into `campaignGovernance.checkGovernance`). */\n brandRights?: BrandRightsPlatform<TCtxMeta>;\n\n /**\n * Optional sibling that owns the proposal side of the two-platform\n * composition (port of `adcp-client-python`'s `ProposalManager`). When\n * present, the framework routes `get_products` and refine traffic to\n * the manager instead of `sales.getProducts`; `sales` stays\n * responsible for media-buy execution. Either side can be mock-backed\n * independently — see `MockProposalManager`.\n *\n * **Status**: primitive types only. Framework dispatch wiring (the\n * five seams that intercept `getProducts`, `createMediaBuy`,\n * `updateMediaBuy`, `getMediaBuyDelivery` to persist drafts, hydrate\n * recipes, and commit on finalize) lands in a follow-up release. v1.5\n * adopters can already implement against this surface; the framework\n * just doesn't drive the lifecycle yet.\n */\n proposalManager?: ProposalManager<Recipe, TCtxMeta>;\n\n // v1.1+ specialisms add: creative-review.\n}\n\n// ---------------------------------------------------------------------------\n// Compile-time capability enforcement\n// ---------------------------------------------------------------------------\n\n/**\n * Maps an AdCP specialism to the platform interface(s) it requires. The\n * framework's `createAdcpServer<P extends DecisioningPlatform>` constrains\n * `P` to satisfy `RequiredPlatformsFor<P['capabilities']['specialisms'][number]>`,\n * forcing every claimed specialism's interface methods to exist.\n *\n * Drop a method, fail compile.\n * Claim a specialism without an implementation, fail compile.\n *\n * The nested-conditional encoding (rather than a union of `S extends X ? {} : never`)\n * is deliberate: when a specialism is claimed without its required platform\n * interface, TypeScript surfaces \"Property 'sales' is missing in type 'P'\"\n * rather than the unactionable \"Type 'P' does not satisfy the constraint 'never'.\"\n *\n * v1.0 covers the 4 specialisms shipping in v1.0; extended in v1.1+.\n * Unknown specialisms (v1.1+ when this module hasn't been updated yet)\n * resolve to an empty requirement — the framework's runtime check is the\n * fallback gate.\n */\n// Sales specialisms — split into two groups by what the adopter actually owns.\n//\n// - **Core sales** specialisms run their own bidding + media-buy lifecycle and\n// are required to implement `SalesCorePlatform` (`getProducts`,\n// `createMediaBuy`, `updateMediaBuy`, `getMediaBuyDelivery`, `getMediaBuys`).\n// The retail-media variants additionally compose ingestion surfaces.\n// - **Ingestion-only** specialisms (today: `sales-social`) front a walled-\n// garden CAPI / audience surface that owns bidding upstream — adopters only\n// need `SalesIngestionPlatform` (`syncCreatives` / `syncCatalogs` /\n// `syncEventSources` / `logEvent` / etc., all optional individually).\n// - **Proposal mode** is a hybrid — only `getProducts` is required; the rest\n// of the lifecycle flows through notification channels.\n//\n// Wired per the AdCP 3.0 GA enum; preview specialisms (sales-streaming-tv,\n// sales-exchange, sales-retail-media) get added when they land in spec.\ntype SalesCoreSpecialism = 'sales-non-guaranteed' | 'sales-guaranteed' | 'sales-broadcast-tv';\ntype SalesCatalogSpecialism = 'sales-catalog-driven';\ntype SalesIngestionSpecialism = 'sales-social';\ntype SalesProposalSpecialism = 'sales-proposal-mode';\n\n// Signal specialisms — both share the SignalsPlatform interface. Marketplace\n// = third-party data brokers; owned = first-party data providers.\ntype SignalSpecialism = 'signal-marketplace' | 'signal-owned';\n\n// Today's spec splits campaign governance into spend-authority + delivery-monitor;\n// both share one CampaignGovernancePlatform interface. When adcp#3329 lands and\n// the spec consolidates to `campaign-governance`, this union shrinks to one\n// value without shape changes.\ntype CampaignGovernanceSpecialism = 'governance-spend-authority' | 'governance-delivery-monitor';\n\n// `TCtxMeta` defaults to `any` so callers that don't pass it explicitly (the\n// common case — `RequiredPlatformsFor<S>` without a second argument) get a\n// constraint that accepts any adopter metadata shape. The `any` is not a\n// soundness escape — adopters declare metadata inside `DecisioningPlatform<_,\n// TCtxMeta>` directly; this constraint exists only to compile-check that\n// claimed specialisms have a matching sub-interface field on the platform.\ntype SalesCorePlatformRequirement<TCtxMeta> =\n | {\n sales: SalesCorePlatform<TCtxMeta> & SalesIngestionPlatform<TCtxMeta>;\n mediaBuyLifecycle?: MediaBuyLifecyclePlatform<TCtxMeta>;\n }\n | {\n sales?: SalesPlatform<TCtxMeta>;\n mediaBuyLifecycle: MediaBuyLifecycleCorePlatform<TCtxMeta>;\n };\n\ntype SalesProposalPlatformRequirement<TCtxMeta> =\n | {\n sales: Required<Pick<SalesPlatform<TCtxMeta>, 'getProducts'>> & SalesIngestionPlatform<TCtxMeta>;\n mediaBuyLifecycle?: MediaBuyLifecyclePlatform<TCtxMeta>;\n }\n | {\n sales?: SalesPlatform<TCtxMeta>;\n mediaBuyLifecycle: MediaBuyLifecycleProposalPlatform<TCtxMeta>;\n };\n\nexport type RequiredPlatformsFor<\n S extends AdCPSpecialism,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n TCtxMeta = any,\n> = [S] extends [never]\n ? // Empty specialisms[] (legitimate when the agent's only declared\n // surface is a protocol or custom tool that is not represented as an\n // AdCP specialism).\n // `[S] extends [never]` short-circuits the distributive conditional —\n // without this, a generic `S extends ...` over `never` yields `never`,\n // collapsing `P & RequiredPlatformsFor<...>` to `never` and rejecting\n // every platform value at the call site.\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {}\n : S extends 'creative-template' | 'creative-generative' | 'creative-transformers'\n ? { creative: CreativeBuilderPlatform<TCtxMeta> }\n : S extends 'creative-ad-server'\n ? { creative: CreativeAdServerPlatform<TCtxMeta> }\n : S extends SalesCoreSpecialism\n ? SalesCorePlatformRequirement<TCtxMeta>\n : S extends SalesCatalogSpecialism\n ? { sales: SalesCorePlatform<TCtxMeta> & SalesIngestionPlatform<TCtxMeta> }\n : S extends SalesIngestionSpecialism\n ? // Walled-garden specialisms (sales-social, today). Bidding owned upstream\n // — only the ingestion surface is required. Adopters can voluntarily\n // implement core methods on the same `sales` object; the SalesPlatform\n // alias accepts both shapes.\n { sales: SalesIngestionPlatform<TCtxMeta> }\n : S extends SalesProposalSpecialism\n ? // Proposal-mode adopters only need `getProducts` — the rest of the\n // lifecycle flows through `publishStatusChange` on\n // `resource_type: 'proposal'`. Ingestion is optional.\n SalesProposalPlatformRequirement<TCtxMeta>\n : S extends 'audience-sync'\n ? { audiences: AudiencePlatform<TCtxMeta> }\n : S extends SignalSpecialism\n ? { signals: SignalsPlatform<TCtxMeta> }\n : S extends CampaignGovernanceSpecialism\n ? { campaignGovernance: CampaignGovernancePlatform<TCtxMeta> }\n : S extends 'sponsored-intelligence'\n ? { sponsoredIntelligence: SponsoredIntelligencePlatform<TCtxMeta> }\n : S extends 'property-lists'\n ? { propertyLists: PropertyListsPlatform<TCtxMeta> }\n : S extends 'collection-lists'\n ? { collectionLists: CollectionListsPlatform<TCtxMeta> }\n : S extends 'content-standards'\n ? { contentStandards: ContentStandardsPlatform<TCtxMeta> }\n : S extends 'brand-rights'\n ? { brandRights: BrandRightsPlatform<TCtxMeta> }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {};\n// `{}` (not `Record<string, never>`) is the right \"no extra requirements\"\n// fallthrough — intersects to identity (`P & {} = P`) for specialisms\n// without platform constraints. Same reasoning RequiredCapabilitiesFor\n// documents at its own fall-through. `Record<string, never>` would force\n// the platform to have NO extra properties, collapsing `P & Record<string,\n// never>` to `never` for any platform with handler fields.\n\n/**\n * The framework's createAdcpServer<P> signature uses this intersection to\n * enforce capability claims at compile time. Sketch:\n *\n * ```ts\n * declare function createAdcpServer<P extends DecisioningPlatform>(config: {\n * platform: P & RequiredPlatformsFor<P['capabilities']['specialisms'][number]>;\n * }): AdcpServer;\n * ```\n *\n * NOTE: The companion file is preview-only; the actual `createAdcpServer`\n * doesn't yet enforce this. Wiring lands in a follow-up PR with the\n * framework refactor.\n */\n\n/**\n * Compile-time mapping from a claimed specialism to the capability\n * blocks the framework requires on `DecisioningCapabilities`. Sister\n * type to `RequiredPlatformsFor<S>` — that one constrains the per-\n * specialism platform interfaces; this one constrains capability-block\n * declarations on `capabilities.*`.\n *\n * Mappings populated conservatively in v1.0:\n *\n * - `'brand-rights'` → `{ brand: BrandCapabilities }`. Adopters\n * claiming brand-rights MUST declare `capabilities.brand`. The\n * framework auto-derives `rights: true` from the\n * `BrandRightsPlatform` impl, but adopters still need to declare\n * the block (even as `{}`) so `right_types`, `available_uses`,\n * etc. land coherently in `get_adcp_capabilities`.\n *\n * Other specialisms have no required capability blocks today —\n * `audience_targeting` is recommended for `audience-sync` adopters but\n * not enforced (some sync platforms accept anonymous IDs only and\n * legitimately have no `supported_identifier_types` to declare).\n *\n * The `& Record<string, never>` fallthrough means specialisms not\n * mapped here add no constraint — adopters can claim them without\n * declaring extra capability blocks.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type RequiredCapabilitiesFor<S extends AdCPSpecialism> = S extends 'brand-rights'\n ? { capabilities: { brand: BrandCapabilities } }\n : {};\n// `{}` (not `Record<string, never>`) is the right \"no extra requirements\"\n// fallthrough: it intersects to identity (`P & {} = P`) for specialisms\n// without capability constraints. `Record<string, never>` would force the\n// platform to have NO extra properties, which would reject every real\n// platform impl.\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"from-platform.d.ts","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/runtime/from-platform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,
|
|
1
|
+
{"version":3,"file":"from-platform.d.ts","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/runtime/from-platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -1017,8 +1017,8 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1017
1017
|
const som = somCandidate != null && somCandidate.length > 0 ? somCandidate : void 0;
|
|
1018
1018
|
const fc = platform.capabilities.frequency_capping;
|
|
1019
1019
|
const targeting = platform.capabilities.targeting ? (0, import_capabilities.normalizeTargetingCapabilities)(platform.capabilities.targeting) : void 0;
|
|
1020
|
-
const hasSalesPlatform = platform.sales != null || platform.proposalManager != null;
|
|
1021
|
-
const supportsProposals = platform.capabilities.supportsProposals ?? (platform.proposalManager != null ? true : hasSalesPlatform ? false : void 0);
|
|
1020
|
+
const hasSalesPlatform = platform.sales != null || platform.mediaBuyLifecycle != null || platform.proposalManager != null;
|
|
1021
|
+
const supportsProposals = platform.capabilities.supportsProposals ?? (platform.proposalManager != null || platform.mediaBuyLifecycle?.requestProposals != null || platform.mediaBuyLifecycle?.refineProposals != null ? true : hasSalesPlatform ? false : void 0);
|
|
1022
1022
|
const hasMediaBuyProjection = hasSalesPlatform || at != null || ct != null || cs != null || som != null || fc != null || targeting != null || supportsProposals !== void 0;
|
|
1023
1023
|
const configuredAdcpVersion = opts.adcpVersion ?? import_version.ADCP_VERSION;
|
|
1024
1024
|
const configuredRelease = parseAdcpRelease(configuredAdcpVersion);
|
|
@@ -1147,6 +1147,23 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1147
1147
|
}
|
|
1148
1148
|
};
|
|
1149
1149
|
const ctxFor = makeCtxFor(effectiveCtxMetadata);
|
|
1150
|
+
const platformProposalNegotiation = buildProposalNegotiationHandlers(
|
|
1151
|
+
platform,
|
|
1152
|
+
taskRegistry,
|
|
1153
|
+
taskWebhookEmit,
|
|
1154
|
+
observability,
|
|
1155
|
+
fwLogger,
|
|
1156
|
+
{
|
|
1157
|
+
allowPrivateWebhookUrls: opts.allowPrivateWebhookUrls === true,
|
|
1158
|
+
autoEmitCompletionWebhooks: opts.autoEmitCompletionWebhooks === true
|
|
1159
|
+
},
|
|
1160
|
+
ctxFor
|
|
1161
|
+
);
|
|
1162
|
+
if (platformProposalNegotiation && opts.proposalNegotiation) {
|
|
1163
|
+
throw new import_validate_platform.PlatformConfigError(
|
|
1164
|
+
"Configure refine_proposals through platform.mediaBuyLifecycle or opts.proposalNegotiation, not both"
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1150
1167
|
if (opts.resolveIdempotencyPrincipal === void 0) {
|
|
1151
1168
|
const env = process.env.NODE_ENV;
|
|
1152
1169
|
const inDevAllowlist = env === "test" || env === "development";
|
|
@@ -1159,6 +1176,7 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1159
1176
|
}
|
|
1160
1177
|
const config = {
|
|
1161
1178
|
...opts,
|
|
1179
|
+
requireCompactMutationAccountScope: true,
|
|
1162
1180
|
taskRegistry,
|
|
1163
1181
|
...autoSeedStore != null && { testController: makeAutoSeedBridge(autoSeedStore) },
|
|
1164
1182
|
...projectedCapabilitiesConfig != null && { capabilities: projectedCapabilitiesConfig },
|
|
@@ -1182,17 +1200,14 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1182
1200
|
// Pool-derived stores override the spread above when adopters supplied
|
|
1183
1201
|
// `pool` but no explicit per-store opt. Explicit values still win.
|
|
1184
1202
|
...effectiveIdempotency !== void 0 && { idempotency: effectiveIdempotency },
|
|
1185
|
-
//
|
|
1186
|
-
//
|
|
1187
|
-
//
|
|
1188
|
-
//
|
|
1189
|
-
//
|
|
1190
|
-
//
|
|
1191
|
-
//
|
|
1192
|
-
|
|
1193
|
-
// explicit values winning. Closed by the Emma matrix surfacing
|
|
1194
|
-
// SERVICE_UNAVAILABLE on every v6 mutating call.
|
|
1195
|
-
resolveIdempotencyPrincipal: opts.resolveIdempotencyPrincipal ?? ((ctx) => ctx.authInfo?.clientId ?? ctx.sessionKey ?? ctx.account?.id ?? void 0),
|
|
1203
|
+
// Preserve the SDK 13 principal namespace for established tools so a
|
|
1204
|
+
// retry spanning a rolling 13→14 deployment still finds its durable
|
|
1205
|
+
// idempotency entry. The new compact lifecycle uses credential-kind
|
|
1206
|
+
// namespacing and refuses session/account fallbacks, preventing
|
|
1207
|
+
// cross-credential collisions without reopening a duplicate-buy window
|
|
1208
|
+
// on create_media_buy/update_media_buy. Explicit adopter resolvers still
|
|
1209
|
+
// win for every tool.
|
|
1210
|
+
resolveIdempotencyPrincipal: opts.resolveIdempotencyPrincipal ?? ((ctx, _params, toolName) => import_create_adcp_server.COMPACT_MEDIA_BUY_MUTATION_TOOLS.has(toolName) ? authenticatedPrincipalFor(ctx) : ctx.authInfo?.clientId ?? ctx.sessionKey ?? ctx.account?.id ?? void 0),
|
|
1196
1211
|
resolveAccount: async (ref, ctx) => {
|
|
1197
1212
|
const start = Date.now();
|
|
1198
1213
|
let resolved = false;
|
|
@@ -1294,6 +1309,7 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1294
1309
|
mergeOpts,
|
|
1295
1310
|
defaultCreativeWireMode
|
|
1296
1311
|
),
|
|
1312
|
+
proposalNegotiation: platformProposalNegotiation ?? opts.proposalNegotiation,
|
|
1297
1313
|
creative: mergeHandlers(
|
|
1298
1314
|
legacyHandlers.creative,
|
|
1299
1315
|
buildCreativeHandlers(
|
|
@@ -2093,6 +2109,17 @@ function taskOwnerScopeFor(ctx, accountId) {
|
|
|
2093
2109
|
}
|
|
2094
2110
|
return `account:${accountId}`;
|
|
2095
2111
|
}
|
|
2112
|
+
function authenticatedPrincipalFor(ctx) {
|
|
2113
|
+
if (ctx.agent?.agent_url) return `agent:${ctx.agent.agent_url}`;
|
|
2114
|
+
const credential = ctx.authInfo?.credential;
|
|
2115
|
+
if (credential?.kind === "http_sig") return `http_sig:${credential.agent_url}`;
|
|
2116
|
+
if (credential?.kind === "oauth") return `oauth:${credential.client_id}`;
|
|
2117
|
+
if (credential?.kind === "api_key") return `api_key:${credential.key_id}`;
|
|
2118
|
+
if (typeof ctx.authInfo?.clientId === "string" && ctx.authInfo.clientId.length > 0) {
|
|
2119
|
+
return `client:${ctx.authInfo.clientId}`;
|
|
2120
|
+
}
|
|
2121
|
+
return void 0;
|
|
2122
|
+
}
|
|
2096
2123
|
function hasPushNotificationConfig(params) {
|
|
2097
2124
|
return params != null && typeof params === "object" && params.push_notification_config !== void 0;
|
|
2098
2125
|
}
|
|
@@ -2755,11 +2782,167 @@ function validatePushNotificationOperationId(operationId) {
|
|
|
2755
2782
|
}
|
|
2756
2783
|
return { ok: true };
|
|
2757
2784
|
}
|
|
2785
|
+
function buildProposalNegotiationHandlers(platform, taskRegistry, taskWebhookEmit, observability, logger, pushOpts, ctxFor) {
|
|
2786
|
+
const lifecycle = platform.mediaBuyLifecycle;
|
|
2787
|
+
if (!lifecycle?.refineProposals) return void 0;
|
|
2788
|
+
if (!lifecycle.proposalRefinement) {
|
|
2789
|
+
throw new import_validate_platform.PlatformConfigError(
|
|
2790
|
+
"mediaBuyLifecycle.refineProposals requires mediaBuyLifecycle.proposalRefinement capability metadata"
|
|
2791
|
+
);
|
|
2792
|
+
}
|
|
2793
|
+
return {
|
|
2794
|
+
capabilities: lifecycle.proposalRefinement,
|
|
2795
|
+
resolveScope: (ctx) => {
|
|
2796
|
+
const accountId = ctx.account?.id;
|
|
2797
|
+
if (!accountId) {
|
|
2798
|
+
throw new import_async_outcome.AdcpError("ACCOUNT_NOT_FOUND", {
|
|
2799
|
+
message: "refine_proposals requires an authenticated account scope",
|
|
2800
|
+
recovery: "correctable"
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
const principalId = authenticatedPrincipalFor(ctx);
|
|
2804
|
+
if (!principalId) {
|
|
2805
|
+
throw new import_async_outcome.AdcpError("AUTH_REQUIRED", {
|
|
2806
|
+
message: "refine_proposals requires an authenticated buyer principal",
|
|
2807
|
+
recovery: "correctable"
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
return { tenant_id: accountId, account_id: accountId, principal_id: principalId };
|
|
2811
|
+
},
|
|
2812
|
+
refineProposals: async (params, ctx) => {
|
|
2813
|
+
const request = params;
|
|
2814
|
+
const reqCtx = ctxFor(ctx, request);
|
|
2815
|
+
if (!reqCtx.account?.id) {
|
|
2816
|
+
throw new import_async_outcome.AdcpError("ACCOUNT_NOT_FOUND", {
|
|
2817
|
+
message: "refine_proposals requires an authenticated account scope",
|
|
2818
|
+
recovery: "correctable"
|
|
2819
|
+
});
|
|
2820
|
+
}
|
|
2821
|
+
return projectSync(
|
|
2822
|
+
async () => {
|
|
2823
|
+
const push = extractPushConfig(request, logger, {
|
|
2824
|
+
allowPrivateWebhookUrls: pushOpts.allowPrivateWebhookUrls
|
|
2825
|
+
});
|
|
2826
|
+
const result = await lifecycle.refineProposals(params, reqCtx);
|
|
2827
|
+
return routeIfHandoff(
|
|
2828
|
+
taskRegistry,
|
|
2829
|
+
{
|
|
2830
|
+
tool: "refine_proposals",
|
|
2831
|
+
accountId: reqCtx.account.id,
|
|
2832
|
+
ownerScope: taskOwnerScopeFor(ctx, reqCtx.account.id),
|
|
2833
|
+
pushNotificationUrl: push.url,
|
|
2834
|
+
pushNotificationToken: push.token,
|
|
2835
|
+
pushNotificationOperationId: push.operationId,
|
|
2836
|
+
emitWebhook: taskWebhookEmit ?? ctx.emitWebhook,
|
|
2837
|
+
autoEmitCompletion: pushOpts.autoEmitCompletionWebhooks,
|
|
2838
|
+
observability,
|
|
2839
|
+
logger
|
|
2840
|
+
},
|
|
2841
|
+
result,
|
|
2842
|
+
(value) => value
|
|
2843
|
+
);
|
|
2844
|
+
},
|
|
2845
|
+
(value) => value
|
|
2846
|
+
);
|
|
2847
|
+
}
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2758
2850
|
function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observability, logger, pushOpts, ctxFor, ctxMetadataStore, mediaBuyStore, proposalStore, legacyFormatConverter, canonicalFormatLegacyResolver, creativeWireMode) {
|
|
2759
2851
|
const sales = platform.sales;
|
|
2852
|
+
const lifecycle = platform.mediaBuyLifecycle;
|
|
2853
|
+
const getMediaBuyDelivery = lifecycle?.getMediaBuyDelivery ?? sales?.getMediaBuyDelivery;
|
|
2854
|
+
const getMediaBuys = lifecycle?.getMediaBuys ?? sales?.getMediaBuys;
|
|
2760
2855
|
const proposalManager = platform.proposalManager;
|
|
2761
|
-
if (!sales && !proposalManager) return void 0;
|
|
2856
|
+
if (!sales && !lifecycle && !proposalManager) return void 0;
|
|
2857
|
+
const dispatchCompactMutation = async (tool, params, ctx, invoke) => {
|
|
2858
|
+
return projectSync(
|
|
2859
|
+
async () => {
|
|
2860
|
+
if (ctx.authInfo === void 0 && ctx.agent === void 0) {
|
|
2861
|
+
throw new import_async_outcome.AdcpError("AUTH_MISSING", {
|
|
2862
|
+
message: `${tool} requires an authenticated buyer principal`,
|
|
2863
|
+
recovery: "correctable"
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
const accountId = ctx.account?.id;
|
|
2867
|
+
if (!accountId) {
|
|
2868
|
+
throw new import_async_outcome.AdcpError("ACCOUNT_NOT_FOUND", {
|
|
2869
|
+
message: `${tool} requires a resolved account scope`,
|
|
2870
|
+
recovery: "correctable"
|
|
2871
|
+
});
|
|
2872
|
+
}
|
|
2873
|
+
const principalId = authenticatedPrincipalFor(ctx);
|
|
2874
|
+
if (!principalId) {
|
|
2875
|
+
throw new import_async_outcome.AdcpError("AUTH_MISSING", {
|
|
2876
|
+
message: `${tool} requires an authenticated buyer principal`,
|
|
2877
|
+
recovery: "correctable"
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
const callerMutationScope = Object.freeze({
|
|
2881
|
+
tenant_id: accountId,
|
|
2882
|
+
account_id: accountId,
|
|
2883
|
+
principal_id: principalId
|
|
2884
|
+
});
|
|
2885
|
+
const reqCtx = ctxFor({ ...ctx, callerMutationScope }, params);
|
|
2886
|
+
const push = extractPushConfig(params, logger, {
|
|
2887
|
+
allowPrivateWebhookUrls: pushOpts.allowPrivateWebhookUrls
|
|
2888
|
+
});
|
|
2889
|
+
const result = await invoke(reqCtx);
|
|
2890
|
+
return routeIfHandoff(
|
|
2891
|
+
taskRegistry,
|
|
2892
|
+
{
|
|
2893
|
+
tool,
|
|
2894
|
+
accountId,
|
|
2895
|
+
ownerScope: taskOwnerScopeFor(ctx, accountId),
|
|
2896
|
+
pushNotificationUrl: push.url,
|
|
2897
|
+
pushNotificationToken: push.token,
|
|
2898
|
+
pushNotificationOperationId: push.operationId,
|
|
2899
|
+
emitWebhook: taskWebhookEmit ?? ctx.emitWebhook,
|
|
2900
|
+
autoEmitCompletion: pushOpts.autoEmitCompletionWebhooks,
|
|
2901
|
+
observability,
|
|
2902
|
+
logger
|
|
2903
|
+
},
|
|
2904
|
+
result,
|
|
2905
|
+
(value) => value
|
|
2906
|
+
);
|
|
2907
|
+
},
|
|
2908
|
+
(value) => value
|
|
2909
|
+
);
|
|
2910
|
+
};
|
|
2762
2911
|
return {
|
|
2912
|
+
...lifecycle?.listProducts && {
|
|
2913
|
+
listProducts: async (...[params, ctx]) => {
|
|
2914
|
+
const reqCtx = ctxFor(ctx, params);
|
|
2915
|
+
return projectSync(
|
|
2916
|
+
() => lifecycle.listProducts(params, reqCtx),
|
|
2917
|
+
(value) => value
|
|
2918
|
+
);
|
|
2919
|
+
}
|
|
2920
|
+
},
|
|
2921
|
+
...lifecycle?.requestProposals && {
|
|
2922
|
+
requestProposals: async (...[params, ctx]) => dispatchCompactMutation(
|
|
2923
|
+
"request_proposals",
|
|
2924
|
+
params,
|
|
2925
|
+
ctx,
|
|
2926
|
+
(reqCtx) => lifecycle.requestProposals(params, reqCtx)
|
|
2927
|
+
)
|
|
2928
|
+
},
|
|
2929
|
+
...lifecycle?.declineProposals && {
|
|
2930
|
+
declineProposals: async (...[params, ctx]) => dispatchCompactMutation(
|
|
2931
|
+
"decline_proposals",
|
|
2932
|
+
params,
|
|
2933
|
+
ctx,
|
|
2934
|
+
(reqCtx) => lifecycle.declineProposals(params, reqCtx)
|
|
2935
|
+
)
|
|
2936
|
+
},
|
|
2937
|
+
...lifecycle?.buyProducts && {
|
|
2938
|
+
buyProducts: async (...[params, ctx]) => dispatchCompactMutation("buy_products", params, ctx, (reqCtx) => lifecycle.buyProducts(params, reqCtx))
|
|
2939
|
+
},
|
|
2940
|
+
...lifecycle?.acceptProposal && {
|
|
2941
|
+
acceptProposal: async (...[params, ctx]) => dispatchCompactMutation("accept_proposal", params, ctx, (reqCtx) => lifecycle.acceptProposal(params, reqCtx))
|
|
2942
|
+
},
|
|
2943
|
+
...lifecycle?.controlMediaBuy && {
|
|
2944
|
+
controlMediaBuy: async (...[params, ctx]) => dispatchCompactMutation("control_media_buy", params, ctx, (reqCtx) => lifecycle.controlMediaBuy(params, reqCtx))
|
|
2945
|
+
},
|
|
2763
2946
|
...(sales?.getProducts || proposalManager) && {
|
|
2764
2947
|
getProducts: async (...[params, ctx]) => {
|
|
2765
2948
|
const responseWireMode = creativeWireModeForRequest(
|
|
@@ -3107,7 +3290,7 @@ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observab
|
|
|
3107
3290
|
);
|
|
3108
3291
|
}
|
|
3109
3292
|
},
|
|
3110
|
-
...
|
|
3293
|
+
...getMediaBuyDelivery && {
|
|
3111
3294
|
getMediaBuyDelivery: async (...[params, ctx]) => {
|
|
3112
3295
|
const responseWireMode = creativeWireModeForRequest(ctx, creativeWireMode, params);
|
|
3113
3296
|
const reqCtx = ctxFor(ctx, params);
|
|
@@ -3127,7 +3310,7 @@ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observab
|
|
|
3127
3310
|
}
|
|
3128
3311
|
return projectSync(
|
|
3129
3312
|
async () => {
|
|
3130
|
-
const result = await
|
|
3313
|
+
const result = await getMediaBuyDelivery(asValidatedDomainRequest(params), reqCtx);
|
|
3131
3314
|
warnIfTruncatedMultiIdResponse(
|
|
3132
3315
|
"getMediaBuyDelivery",
|
|
3133
3316
|
"media_buy_ids",
|
|
@@ -3160,13 +3343,13 @@ function buildMediaBuyHandlers(platform, taskRegistry, taskWebhookEmit, observab
|
|
|
3160
3343
|
// platform-derived handler when absent lets `mergeHandlers` pick up the
|
|
3161
3344
|
// adopter's custom handler from `opts.legacyHandlers.mediaBuy` instead of throwing
|
|
3162
3345
|
// `sales.getMediaBuys is not a function`.
|
|
3163
|
-
...
|
|
3346
|
+
...getMediaBuys && {
|
|
3164
3347
|
getMediaBuys: async (...[params, ctx]) => {
|
|
3165
3348
|
const responseWireMode = creativeWireModeForRequest(ctx, creativeWireMode, params);
|
|
3166
3349
|
const reqCtx = ctxFor(ctx, params);
|
|
3167
3350
|
return projectSync(
|
|
3168
3351
|
async () => {
|
|
3169
|
-
const result = await
|
|
3352
|
+
const result = await getMediaBuys(asValidatedDomainRequest(params), reqCtx);
|
|
3170
3353
|
warnIfTruncatedMultiIdResponse(
|
|
3171
3354
|
"getMediaBuys",
|
|
3172
3355
|
"media_buy_ids",
|