@adcp/sdk 12.0.0 → 12.0.2
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/adapters/content-standards-adapter.mjs +0 -6
- package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
- package/dist/lib/adapters/derived-account-store.mjs +0 -6
- package/dist/lib/adapters/derived-account-store.mjs.map +1 -1
- package/dist/lib/adapters/governance-adapter.mjs +0 -6
- package/dist/lib/adapters/governance-adapter.mjs.map +1 -1
- package/dist/lib/adapters/implicit-account-store.mjs +0 -6
- package/dist/lib/adapters/implicit-account-store.mjs.map +1 -1
- package/dist/lib/adapters/index.mjs +0 -6
- package/dist/lib/adapters/index.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/create_media_buy.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/get_products.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/get_products.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/index.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/index.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/list_creative_formats.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/preview_creative.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/sync_creatives.mjs.map +1 -1
- package/dist/lib/adapters/legacy/v2-5/types.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs +0 -6
- package/dist/lib/adapters/legacy/v2-5/update_media_buy.mjs.map +1 -1
- package/dist/lib/adapters/oauth-passthrough-resolver.mjs +0 -6
- package/dist/lib/adapters/oauth-passthrough-resolver.mjs.map +1 -1
- package/dist/lib/adapters/property-list-adapter.mjs +0 -6
- package/dist/lib/adapters/property-list-adapter.mjs.map +1 -1
- package/dist/lib/adapters/roster-account-store.mjs +0 -6
- package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
- package/dist/lib/adapters/si-session-manager.mjs +0 -6
- package/dist/lib/adapters/si-session-manager.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/brand-fields.mjs +0 -6
- package/dist/lib/adapters/version/3.0/brand-fields.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/get-products.mjs +0 -6
- package/dist/lib/adapters/version/3.0/get-products.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/index.mjs +0 -6
- package/dist/lib/adapters/version/3.0/index.mjs.map +1 -1
- package/dist/lib/adapters/version/3.0/sync-accounts.mjs +0 -6
- package/dist/lib/adapters/version/3.0/sync-accounts.mjs.map +1 -1
- package/dist/lib/adapters/version/index.mjs +0 -6
- package/dist/lib/adapters/version/index.mjs.map +1 -1
- package/dist/lib/adapters/version/types.mjs +0 -6
- package/dist/lib/advanced.mjs +0 -6
- package/dist/lib/advanced.mjs.map +1 -1
- package/dist/lib/agents/index.generated.mjs +0 -6
- package/dist/lib/agents/index.generated.mjs.map +1 -1
- package/dist/lib/auth/index.mjs +0 -6
- package/dist/lib/auth/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs +0 -6
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs.map +1 -1
- package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs +0 -6
- package/dist/lib/auth/oauth/ClientCredentialsFlow.mjs.map +1 -1
- package/dist/lib/auth/oauth/MCPOAuthProvider.mjs +0 -6
- package/dist/lib/auth/oauth/MCPOAuthProvider.mjs.map +1 -1
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs +0 -6
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.mjs.map +1 -1
- package/dist/lib/auth/oauth/authorization-required.mjs +0 -6
- package/dist/lib/auth/oauth/authorization-required.mjs.map +1 -1
- package/dist/lib/auth/oauth/diagnose.mjs +0 -6
- package/dist/lib/auth/oauth/diagnose.mjs.map +1 -1
- package/dist/lib/auth/oauth/diagnostics.mjs +0 -6
- package/dist/lib/auth/oauth/diagnostics.mjs.map +1 -1
- package/dist/lib/auth/oauth/discovery.mjs +0 -6
- package/dist/lib/auth/oauth/discovery.mjs.map +1 -1
- package/dist/lib/auth/oauth/file-storage.mjs +0 -6
- package/dist/lib/auth/oauth/file-storage.mjs.map +1 -1
- package/dist/lib/auth/oauth/index.mjs +0 -6
- package/dist/lib/auth/oauth/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/secret-resolver.mjs +0 -6
- package/dist/lib/auth/oauth/secret-resolver.mjs.map +1 -1
- package/dist/lib/auth/oauth/storage-registry.mjs +0 -6
- package/dist/lib/auth/oauth/storage-registry.mjs.map +1 -1
- package/dist/lib/auth/oauth/types.mjs +0 -6
- package/dist/lib/auth/oauth/types.mjs.map +1 -1
- package/dist/lib/auth/oauth/web-flow.mjs +0 -6
- package/dist/lib/auth/oauth/web-flow.mjs.map +1 -1
- package/dist/lib/brand/index.mjs +0 -6
- package/dist/lib/brand/index.mjs.map +1 -1
- package/dist/lib/canonical-references/index.mjs +6 -7
- package/dist/lib/canonical-references/index.mjs.map +1 -1
- package/dist/lib/client/index.mjs +0 -6
- package/dist/lib/client/index.mjs.map +1 -1
- package/dist/lib/compliance/index.mjs +0 -6
- package/dist/lib/compliance/index.mjs.map +1 -1
- package/dist/lib/compliance-fixtures/index.mjs +0 -6
- package/dist/lib/compliance-fixtures/index.mjs.map +1 -1
- package/dist/lib/compliance-fixtures/test-authorization-server.mjs +0 -6
- package/dist/lib/compliance-fixtures/test-authorization-server.mjs.map +1 -1
- package/dist/lib/conformance/index.mjs +0 -6
- package/dist/lib/conformance/index.mjs.map +1 -1
- package/dist/lib/conformance/invariants/uniformError.mjs +0 -6
- package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
- package/dist/lib/conformance/invariants/uniformErrorComparator.mjs +0 -6
- package/dist/lib/conformance/invariants/uniformErrorComparator.mjs.map +1 -1
- package/dist/lib/conformance/oracle.mjs +0 -6
- package/dist/lib/conformance/oracle.mjs.map +1 -1
- package/dist/lib/conformance/runConformance.mjs +0 -6
- package/dist/lib/conformance/runConformance.mjs.map +1 -1
- package/dist/lib/conformance/runners.mjs +0 -6
- package/dist/lib/conformance/runners.mjs.map +1 -1
- package/dist/lib/conformance/schemaArbitrary.mjs +0 -6
- package/dist/lib/conformance/schemaArbitrary.mjs.map +1 -1
- package/dist/lib/conformance/schemaLoader.mjs +5 -6
- package/dist/lib/conformance/schemaLoader.mjs.map +1 -1
- package/dist/lib/conformance/seeder.mjs +0 -6
- package/dist/lib/conformance/seeder.mjs.map +1 -1
- package/dist/lib/conformance/types.mjs +0 -6
- package/dist/lib/conformance/types.mjs.map +1 -1
- package/dist/lib/conformance/webhook.mjs +0 -6
- package/dist/lib/conformance/webhook.mjs.map +1 -1
- package/dist/lib/core/ADCPMultiAgentClient.mjs +0 -6
- package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
- package/dist/lib/core/AgentClient.mjs +0 -6
- package/dist/lib/core/AgentClient.mjs.map +1 -1
- package/dist/lib/core/AsyncHandler.mjs +0 -6
- package/dist/lib/core/AsyncHandler.mjs.map +1 -1
- package/dist/lib/core/ConfigurationManager.mjs +0 -6
- package/dist/lib/core/ConfigurationManager.mjs.map +1 -1
- package/dist/lib/core/ConversationTypes.mjs +0 -6
- package/dist/lib/core/CreativeAgentClient.mjs +0 -6
- package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
- package/dist/lib/core/GovernanceMiddleware.mjs +0 -6
- package/dist/lib/core/GovernanceMiddleware.mjs.map +1 -1
- package/dist/lib/core/GovernanceTypes.mjs +0 -6
- package/dist/lib/core/GovernanceTypes.mjs.map +1 -1
- package/dist/lib/core/ProtocolResponseParser.mjs +0 -6
- package/dist/lib/core/ProtocolResponseParser.mjs.map +1 -1
- package/dist/lib/core/ResponseValidator.mjs +0 -6
- package/dist/lib/core/ResponseValidator.mjs.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +0 -6
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskEventTypes.mjs +0 -6
- package/dist/lib/core/TaskEventTypes.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +0 -6
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/core/match.mjs +0 -6
- package/dist/lib/core/match.mjs.map +1 -1
- package/dist/lib/core/task-status.mjs +0 -6
- package/dist/lib/core/task-status.mjs.map +1 -1
- package/dist/lib/core/webhook-url.mjs +0 -6
- package/dist/lib/core/webhook-url.mjs.map +1 -1
- package/dist/lib/discovery/adagents-redirects.mjs +0 -6
- package/dist/lib/discovery/adagents-redirects.mjs.map +1 -1
- package/dist/lib/discovery/agent-directory.mjs +0 -6
- package/dist/lib/discovery/agent-directory.mjs.map +1 -1
- package/dist/lib/discovery/inline-publisher-properties.mjs +0 -6
- package/dist/lib/discovery/inline-publisher-properties.mjs.map +1 -1
- package/dist/lib/discovery/network-consistency-checker.mjs +0 -6
- package/dist/lib/discovery/network-consistency-checker.mjs.map +1 -1
- package/dist/lib/discovery/property-crawler.mjs +0 -6
- package/dist/lib/discovery/property-crawler.mjs.map +1 -1
- package/dist/lib/discovery/property-index.mjs +0 -6
- package/dist/lib/discovery/property-index.mjs.map +1 -1
- package/dist/lib/discovery/publisher-property-selector.mjs +0 -6
- package/dist/lib/discovery/publisher-property-selector.mjs.map +1 -1
- package/dist/lib/discovery/resolve-agent-properties.mjs +0 -6
- package/dist/lib/discovery/resolve-agent-properties.mjs.map +1 -1
- package/dist/lib/discovery/types.mjs +0 -6
- package/dist/lib/discovery/validate-adagents.mjs +0 -6
- package/dist/lib/discovery/validate-adagents.mjs.map +1 -1
- package/dist/lib/enums.mjs +0 -6
- package/dist/lib/enums.mjs.map +1 -1
- package/dist/lib/errors/index.mjs +0 -6
- package/dist/lib/errors/index.mjs.map +1 -1
- package/dist/lib/express-mcp/index.mjs +0 -6
- package/dist/lib/express-mcp/index.mjs.map +1 -1
- package/dist/lib/governance/index.mjs +0 -6
- package/dist/lib/governance/index.mjs.map +1 -1
- package/dist/lib/handlers/types.mjs +0 -6
- package/dist/lib/handlers/types.mjs.map +1 -1
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +0 -6
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/media-buy/available-actions.mjs +0 -6
- package/dist/lib/media-buy/available-actions.mjs.map +1 -1
- package/dist/lib/media-buy/index.mjs +0 -6
- package/dist/lib/media-buy/index.mjs.map +1 -1
- package/dist/lib/media-buy/preflight.mjs +0 -6
- package/dist/lib/media-buy/preflight.mjs.map +1 -1
- package/dist/lib/media-buy/property-policy.mjs +0 -6
- package/dist/lib/media-buy/property-policy.mjs.map +1 -1
- package/dist/lib/media-buy/types.mjs +0 -6
- package/dist/lib/media-buy/types.mjs.map +1 -1
- package/dist/lib/media-buy/update-fields.generated.mjs +0 -6
- package/dist/lib/media-buy/update-fields.generated.mjs.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/seed-data.mjs +0 -6
- package/dist/lib/mock-server/creative-ad-server/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/creative-ad-server/server.mjs +0 -6
- package/dist/lib/mock-server/creative-ad-server/server.mjs.map +1 -1
- package/dist/lib/mock-server/creative-template/seed-data.mjs +0 -6
- package/dist/lib/mock-server/creative-template/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/creative-template/server.mjs +0 -6
- package/dist/lib/mock-server/creative-template/server.mjs.map +1 -1
- package/dist/lib/mock-server/index.mjs +0 -6
- package/dist/lib/mock-server/index.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/recipe.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/recipe.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/server.mjs +0 -6
- package/dist/lib/mock-server/sales-guaranteed/server.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/server.mjs +0 -6
- package/dist/lib/mock-server/sales-non-guaranteed/server.mjs.map +1 -1
- package/dist/lib/mock-server/sales-social/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sales-social/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sales-social/server.mjs +0 -6
- package/dist/lib/mock-server/sales-social/server.mjs.map +1 -1
- package/dist/lib/mock-server/scenario.mjs +0 -6
- package/dist/lib/mock-server/scenario.mjs.map +1 -1
- package/dist/lib/mock-server/signal-marketplace/seed-data.mjs +0 -6
- package/dist/lib/mock-server/signal-marketplace/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/signal-marketplace/server.mjs +0 -6
- package/dist/lib/mock-server/signal-marketplace/server.mjs.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs +0 -6
- package/dist/lib/mock-server/sponsored-intelligence/seed-data.mjs.map +1 -1
- package/dist/lib/mock-server/sponsored-intelligence/server.mjs +0 -6
- package/dist/lib/mock-server/sponsored-intelligence/server.mjs.map +1 -1
- package/dist/lib/net/address-guards.mjs +0 -6
- package/dist/lib/net/address-guards.mjs.map +1 -1
- package/dist/lib/net/index.mjs +0 -6
- package/dist/lib/net/index.mjs.map +1 -1
- package/dist/lib/net/ssrf-fetch.mjs +0 -6
- package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
- package/dist/lib/observability/index.mjs +0 -6
- package/dist/lib/observability/index.mjs.map +1 -1
- package/dist/lib/observability/tracing.mjs +6 -7
- package/dist/lib/observability/tracing.mjs.map +1 -1
- package/dist/lib/protocols/a2a.mjs +0 -6
- package/dist/lib/protocols/a2a.mjs.map +1 -1
- package/dist/lib/protocols/abort.mjs +0 -6
- package/dist/lib/protocols/abort.mjs.map +1 -1
- package/dist/lib/protocols/index.mjs +0 -6
- package/dist/lib/protocols/index.mjs.map +1 -1
- package/dist/lib/protocols/mcp-modern.mjs +0 -6
- package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
- package/dist/lib/protocols/mcp-tasks.mjs +0 -6
- package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
- package/dist/lib/protocols/mcp.mjs +0 -6
- package/dist/lib/protocols/mcp.mjs.map +1 -1
- package/dist/lib/protocols/rawResponseCapture.mjs +0 -6
- package/dist/lib/protocols/rawResponseCapture.mjs.map +1 -1
- package/dist/lib/protocols/responseSizeLimit.mjs +0 -6
- package/dist/lib/protocols/responseSizeLimit.mjs.map +1 -1
- package/dist/lib/protocols/transportDiagnostics.mjs +0 -6
- package/dist/lib/protocols/transportDiagnostics.mjs.map +1 -1
- package/dist/lib/registry/cursor-store.mjs +0 -6
- package/dist/lib/registry/cursor-store.mjs.map +1 -1
- package/dist/lib/registry/feed-stream.mjs +0 -6
- package/dist/lib/registry/feed-stream.mjs.map +1 -1
- package/dist/lib/registry/index.mjs +0 -6
- package/dist/lib/registry/index.mjs.map +1 -1
- package/dist/lib/registry/property-registry.mjs +0 -6
- package/dist/lib/registry/property-registry.mjs.map +1 -1
- package/dist/lib/registry/sync.mjs +0 -6
- package/dist/lib/registry/sync.mjs.map +1 -1
- package/dist/lib/registry/types.generated.mjs +0 -6
- package/dist/lib/registry/types.mjs +0 -6
- package/dist/lib/schemas/index.mjs +0 -6
- package/dist/lib/schemas/index.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/a2a-adapter.mjs +0 -6
- package/dist/lib/server/a2a-adapter.mjs.map +1 -1
- package/dist/lib/server/account-mode.mjs +0 -6
- package/dist/lib/server/account-mode.mjs.map +1 -1
- package/dist/lib/server/adcp-server.mjs +0 -6
- package/dist/lib/server/adcp-server.mjs.map +1 -1
- package/dist/lib/server/auth-introspection.mjs +0 -6
- package/dist/lib/server/auth-introspection.mjs.map +1 -1
- package/dist/lib/server/auth-signature.mjs +0 -6
- package/dist/lib/server/auth-signature.mjs.map +1 -1
- package/dist/lib/server/auth.mjs +0 -6
- package/dist/lib/server/auth.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +13 -0
- package/dist/lib/server/create-adcp-server.d.ts +13 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +3 -2
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +3 -8
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/credential-policy.mjs +0 -6
- package/dist/lib/server/credential-policy.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/memory.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/memory.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/pg.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/pg.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/redis.mjs +0 -6
- package/dist/lib/server/ctx-metadata/backends/redis.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/index.mjs +0 -6
- package/dist/lib/server/ctx-metadata/index.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/store.mjs +0 -6
- package/dist/lib/server/ctx-metadata/store.mjs.map +1 -1
- package/dist/lib/server/ctx-metadata/wire-shape.mjs +0 -6
- package/dist/lib/server/ctx-metadata/wire-shape.mjs.map +1 -1
- package/dist/lib/server/decisioning/account.mjs +0 -6
- package/dist/lib/server/decisioning/account.mjs.map +1 -1
- package/dist/lib/server/decisioning/admin-router.mjs +0 -6
- package/dist/lib/server/decisioning/admin-router.mjs.map +1 -1
- package/dist/lib/server/decisioning/assembly-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/async-outcome.mjs +0 -6
- package/dist/lib/server/decisioning/async-outcome.mjs.map +1 -1
- package/dist/lib/server/decisioning/buyer-agent.mjs +0 -6
- package/dist/lib/server/decisioning/buyer-agent.mjs.map +1 -1
- package/dist/lib/server/decisioning/capabilities.mjs +0 -6
- package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
- package/dist/lib/server/decisioning/compose.mjs +0 -6
- package/dist/lib/server/decisioning/compose.mjs.map +1 -1
- package/dist/lib/server/decisioning/context.mjs +0 -6
- package/dist/lib/server/decisioning/errors-typed.mjs +0 -6
- package/dist/lib/server/decisioning/errors-typed.mjs.map +1 -1
- package/dist/lib/server/decisioning/helpers.mjs +0 -6
- package/dist/lib/server/decisioning/helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.mjs +0 -6
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/pagination.mjs +0 -6
- package/dist/lib/server/decisioning/platform-helpers.mjs +0 -6
- package/dist/lib/server/decisioning/platform-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/platform.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/dispatch.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/index.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/lifecycle.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/store.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/store.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.mjs +0 -6
- package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
- package/dist/lib/server/decisioning/resolve-presets.mjs +0 -6
- package/dist/lib/server/decisioning/resolve-presets.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/entity-hydration.generated.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/observed-modes.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/observed-modes.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs +0 -6
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/audiences.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/brand-rights.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/campaign-governance.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/content-standards.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/creative.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/lists.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/sales.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/signals.mjs +0 -6
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.mjs +0 -6
- package/dist/lib/server/decisioning/start-time.mjs +0 -6
- package/dist/lib/server/decisioning/start-time.mjs.map +1 -1
- package/dist/lib/server/decisioning/status-changes.mjs +0 -6
- package/dist/lib/server/decisioning/status-changes.mjs.map +1 -1
- package/dist/lib/server/decisioning/status-mappers.mjs +0 -6
- package/dist/lib/server/decisioning/status-mappers.mjs.map +1 -1
- package/dist/lib/server/decisioning/tenant-registry.mjs +0 -6
- package/dist/lib/server/decisioning/tenant-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/tenant-store.mjs +0 -6
- package/dist/lib/server/decisioning/tenant-store.mjs.map +1 -1
- package/dist/lib/server/decisioning/validate-specialisms.mjs +0 -6
- package/dist/lib/server/decisioning/validate-specialisms.mjs.map +1 -1
- package/dist/lib/server/dynamic-registry.mjs +0 -6
- package/dist/lib/server/dynamic-registry.mjs.map +1 -1
- package/dist/lib/server/envelope-allowlist.mjs +0 -6
- package/dist/lib/server/envelope-allowlist.mjs.map +1 -1
- package/dist/lib/server/error-arm-tools.mjs +5 -6
- package/dist/lib/server/error-arm-tools.mjs.map +1 -1
- package/dist/lib/server/errors.mjs +0 -6
- package/dist/lib/server/errors.mjs.map +1 -1
- package/dist/lib/server/example-tld-guard.mjs +0 -6
- package/dist/lib/server/example-tld-guard.mjs.map +1 -1
- package/dist/lib/server/express-adapter.mjs +0 -6
- package/dist/lib/server/express-adapter.mjs.map +1 -1
- package/dist/lib/server/governance.mjs +0 -6
- package/dist/lib/server/governance.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/lazy.mjs +0 -6
- package/dist/lib/server/idempotency/backends/lazy.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/memory.mjs +0 -6
- package/dist/lib/server/idempotency/backends/memory.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/pg.mjs +0 -6
- package/dist/lib/server/idempotency/backends/pg.mjs.map +1 -1
- package/dist/lib/server/idempotency/backends/redis.mjs +0 -6
- package/dist/lib/server/idempotency/backends/redis.mjs.map +1 -1
- package/dist/lib/server/idempotency/index.mjs +0 -6
- package/dist/lib/server/idempotency/index.mjs.map +1 -1
- package/dist/lib/server/idempotency/store.mjs +0 -6
- package/dist/lib/server/idempotency/store.mjs.map +1 -1
- package/dist/lib/server/index.d.mts +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs +0 -6
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.mts +1 -1
- package/dist/lib/server/legacy/v5/index.d.ts +1 -1
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
- package/dist/lib/server/legacy/v5/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.mjs +0 -6
- package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
- package/dist/lib/server/mcp-modern-server.mjs +0 -6
- package/dist/lib/server/mcp-modern-server.mjs.map +1 -1
- package/dist/lib/server/media-buy-actions.mjs +0 -6
- package/dist/lib/server/media-buy-actions.mjs.map +1 -1
- package/dist/lib/server/media-buy-helpers.mjs +0 -6
- package/dist/lib/server/media-buy-helpers.mjs.map +1 -1
- package/dist/lib/server/media-buy-store.mjs +0 -6
- package/dist/lib/server/media-buy-store.mjs.map +1 -1
- package/dist/lib/server/normalize-errors.mjs +0 -6
- package/dist/lib/server/normalize-errors.mjs.map +1 -1
- package/dist/lib/server/operational-platform.mjs +0 -6
- package/dist/lib/server/operational-platform.mjs.map +1 -1
- package/dist/lib/server/pick-safe-details.mjs +0 -6
- package/dist/lib/server/pick-safe-details.mjs.map +1 -1
- package/dist/lib/server/pin-and-bind-fetch.mjs +0 -6
- package/dist/lib/server/pin-and-bind-fetch.mjs.map +1 -1
- package/dist/lib/server/postgres-state-store.mjs +0 -6
- package/dist/lib/server/postgres-state-store.mjs.map +1 -1
- package/dist/lib/server/postgres-task-store.mjs +0 -6
- package/dist/lib/server/postgres-task-store.mjs.map +1 -1
- package/dist/lib/server/product-defaults.mjs +0 -6
- package/dist/lib/server/product-defaults.mjs.map +1 -1
- package/dist/lib/server/redact.mjs +0 -6
- package/dist/lib/server/redact.mjs.map +1 -1
- package/dist/lib/server/responses.mjs +0 -6
- package/dist/lib/server/responses.mjs.map +1 -1
- package/dist/lib/server/serve.mjs +0 -6
- package/dist/lib/server/serve.mjs.map +1 -1
- package/dist/lib/server/socket-mode/conformance-client.mjs +0 -6
- package/dist/lib/server/socket-mode/conformance-client.mjs.map +1 -1
- package/dist/lib/server/socket-mode/index.mjs +0 -6
- package/dist/lib/server/socket-mode/index.mjs.map +1 -1
- package/dist/lib/server/socket-mode/ws-transport.mjs +0 -6
- package/dist/lib/server/socket-mode/ws-transport.mjs.map +1 -1
- package/dist/lib/server/state-machine.mjs +0 -6
- package/dist/lib/server/state-machine.mjs.map +1 -1
- package/dist/lib/server/state-store.mjs +0 -6
- package/dist/lib/server/state-store.mjs.map +1 -1
- package/dist/lib/server/structured-serialize.mjs +0 -6
- package/dist/lib/server/structured-serialize.mjs.map +1 -1
- package/dist/lib/server/targeting-helpers.mjs +0 -6
- package/dist/lib/server/targeting-helpers.mjs.map +1 -1
- package/dist/lib/server/tasks.mjs +0 -6
- package/dist/lib/server/tasks.mjs.map +1 -1
- package/dist/lib/server/test-controller-bridge.mjs +0 -6
- package/dist/lib/server/test-controller-bridge.mjs.map +1 -1
- package/dist/lib/server/test-controller.mjs +0 -6
- package/dist/lib/server/test-controller.mjs.map +1 -1
- package/dist/lib/server/upstream-helpers.mjs +0 -6
- package/dist/lib/server/upstream-helpers.mjs.map +1 -1
- package/dist/lib/server/webhook-emitter.mjs +0 -6
- package/dist/lib/server/webhook-emitter.mjs.map +1 -1
- package/dist/lib/server/wire-safe.mjs +0 -6
- package/dist/lib/server/wire-safe.mjs.map +1 -1
- package/dist/lib/server/wire-spec-fields.generated.mjs +0 -6
- package/dist/lib/server/wire-spec-fields.generated.mjs.map +1 -1
- package/dist/lib/server/wrap-envelope.mjs +0 -6
- package/dist/lib/server/wrap-envelope.mjs.map +1 -1
- package/dist/lib/signing/agent-context.mjs +0 -6
- package/dist/lib/signing/agent-context.mjs.map +1 -1
- package/dist/lib/signing/agent-fetch.mjs +0 -6
- package/dist/lib/signing/agent-fetch.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/canonicalize.mjs +0 -6
- package/dist/lib/signing/agent-resolver/canonicalize.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/capabilities-types.mjs +0 -6
- package/dist/lib/signing/agent-resolver/capabilities-types.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/consistency.mjs +0 -6
- package/dist/lib/signing/agent-resolver/consistency.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/errors.mjs +0 -6
- package/dist/lib/signing/agent-resolver/errors.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/etld.mjs +0 -6
- package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +0 -6
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/index.mjs +0 -6
- package/dist/lib/signing/agent-resolver/index.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/jwks-set.mjs +0 -6
- package/dist/lib/signing/agent-resolver/jwks-set.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs +0 -6
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/select-agent.mjs +0 -6
- package/dist/lib/signing/agent-resolver/select-agent.mjs.map +1 -1
- package/dist/lib/signing/agent-resolver/strict-json.mjs +0 -6
- package/dist/lib/signing/agent-resolver/strict-json.mjs.map +1 -1
- package/dist/lib/signing/brand-jwks.mjs +0 -6
- package/dist/lib/signing/brand-jwks.mjs.map +1 -1
- package/dist/lib/signing/canonicalize.mjs +0 -6
- package/dist/lib/signing/canonicalize.mjs.map +1 -1
- package/dist/lib/signing/capability-cache.mjs +0 -6
- package/dist/lib/signing/capability-cache.mjs.map +1 -1
- package/dist/lib/signing/capability-priming.mjs +0 -6
- package/dist/lib/signing/capability-priming.mjs.map +1 -1
- package/dist/lib/signing/client.mjs +0 -6
- package/dist/lib/signing/client.mjs.map +1 -1
- package/dist/lib/signing/content-digest.mjs +0 -6
- package/dist/lib/signing/content-digest.mjs.map +1 -1
- package/dist/lib/signing/crypto.mjs +0 -6
- package/dist/lib/signing/crypto.mjs.map +1 -1
- package/dist/lib/signing/ecdsa-encoding.mjs +0 -6
- package/dist/lib/signing/ecdsa-encoding.mjs.map +1 -1
- package/dist/lib/signing/errors.mjs +0 -6
- package/dist/lib/signing/errors.mjs.map +1 -1
- package/dist/lib/signing/fetch-async.mjs +0 -6
- package/dist/lib/signing/fetch-async.mjs.map +1 -1
- package/dist/lib/signing/fetch.mjs +0 -6
- package/dist/lib/signing/fetch.mjs.map +1 -1
- package/dist/lib/signing/index.mjs +0 -6
- package/dist/lib/signing/index.mjs.map +1 -1
- package/dist/lib/signing/jwks-helpers.mjs +0 -6
- package/dist/lib/signing/jwks-helpers.mjs.map +1 -1
- package/dist/lib/signing/jwks-https.mjs +0 -6
- package/dist/lib/signing/jwks-https.mjs.map +1 -1
- package/dist/lib/signing/jwks.mjs +0 -6
- package/dist/lib/signing/jwks.mjs.map +1 -1
- package/dist/lib/signing/middleware.mjs +0 -6
- package/dist/lib/signing/middleware.mjs.map +1 -1
- package/dist/lib/signing/parser.mjs +0 -6
- package/dist/lib/signing/parser.mjs.map +1 -1
- package/dist/lib/signing/postgres-replay-store.mjs +0 -6
- package/dist/lib/signing/postgres-replay-store.mjs.map +1 -1
- package/dist/lib/signing/protocol-response.mjs +0 -6
- package/dist/lib/signing/protocol-response.mjs.map +1 -1
- package/dist/lib/signing/provider.mjs +0 -6
- package/dist/lib/signing/redis-replay-store.mjs +0 -6
- package/dist/lib/signing/redis-replay-store.mjs.map +1 -1
- package/dist/lib/signing/replay.mjs +0 -6
- package/dist/lib/signing/replay.mjs.map +1 -1
- package/dist/lib/signing/request-context.mjs +0 -6
- package/dist/lib/signing/request-context.mjs.map +1 -1
- package/dist/lib/signing/revocation-https.mjs +0 -6
- package/dist/lib/signing/revocation-https.mjs.map +1 -1
- package/dist/lib/signing/revocation.mjs +0 -6
- package/dist/lib/signing/revocation.mjs.map +1 -1
- package/dist/lib/signing/server.mjs +0 -6
- package/dist/lib/signing/server.mjs.map +1 -1
- package/dist/lib/signing/signer-async.mjs +0 -6
- package/dist/lib/signing/signer-async.mjs.map +1 -1
- package/dist/lib/signing/signer.mjs +0 -6
- package/dist/lib/signing/signer.mjs.map +1 -1
- package/dist/lib/signing/testing.mjs +0 -6
- package/dist/lib/signing/testing.mjs.map +1 -1
- package/dist/lib/signing/types.mjs +0 -6
- package/dist/lib/signing/types.mjs.map +1 -1
- package/dist/lib/signing/verifier.mjs +0 -6
- package/dist/lib/signing/verifier.mjs.map +1 -1
- package/dist/lib/signing/webhook-auth-detection.mjs +0 -6
- package/dist/lib/signing/webhook-auth-detection.mjs.map +1 -1
- package/dist/lib/signing/webhook-verifier.mjs +0 -6
- package/dist/lib/signing/webhook-verifier.mjs.map +1 -1
- package/dist/lib/storage/MemoryStorage.mjs +0 -6
- package/dist/lib/storage/MemoryStorage.mjs.map +1 -1
- package/dist/lib/storage/interfaces.mjs +0 -6
- package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs +0 -6
- package/dist/lib/substitution/encoder/SubstitutionEncoder.mjs.map +1 -1
- package/dist/lib/substitution/encoder/index.mjs +0 -6
- package/dist/lib/substitution/encoder/index.mjs.map +1 -1
- package/dist/lib/substitution/index.mjs +0 -6
- package/dist/lib/substitution/index.mjs.map +1 -1
- package/dist/lib/substitution/observer/SubstitutionObserver.mjs +0 -6
- package/dist/lib/substitution/observer/SubstitutionObserver.mjs.map +1 -1
- package/dist/lib/substitution/observer/alignment.mjs +0 -6
- package/dist/lib/substitution/observer/alignment.mjs.map +1 -1
- package/dist/lib/substitution/observer/assertions.mjs +0 -6
- package/dist/lib/substitution/observer/assertions.mjs.map +1 -1
- package/dist/lib/substitution/observer/html-parser.mjs +0 -6
- package/dist/lib/substitution/observer/html-parser.mjs.map +1 -1
- package/dist/lib/substitution/observer/index.mjs +0 -6
- package/dist/lib/substitution/observer/index.mjs.map +1 -1
- package/dist/lib/substitution/observer/ssrf.mjs +0 -6
- package/dist/lib/substitution/observer/ssrf.mjs.map +1 -1
- package/dist/lib/substitution/rfc3986.mjs +0 -6
- package/dist/lib/substitution/rfc3986.mjs.map +1 -1
- package/dist/lib/substitution/translate.mjs +0 -6
- package/dist/lib/substitution/translate.mjs.map +1 -1
- package/dist/lib/substitution/types.mjs +0 -6
- package/dist/lib/substitution/vectors.mjs +0 -6
- package/dist/lib/substitution/vectors.mjs.map +1 -1
- package/dist/lib/testing/agent-tester.mjs +0 -6
- package/dist/lib/testing/agent-tester.mjs.map +1 -1
- package/dist/lib/testing/client.mjs +0 -6
- package/dist/lib/testing/client.mjs.map +1 -1
- package/dist/lib/testing/compliance/briefs.mjs +0 -6
- package/dist/lib/testing/compliance/briefs.mjs.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +0 -6
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.mjs +0 -6
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/spec-conformance.mjs +0 -6
- package/dist/lib/testing/compliance/spec-conformance.mjs.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +0 -6
- package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
- package/dist/lib/testing/compliance/summary.mjs +0 -6
- package/dist/lib/testing/compliance/summary.mjs.map +1 -1
- package/dist/lib/testing/compliance/types.mjs +0 -6
- package/dist/lib/testing/comply-controller.mjs +0 -6
- package/dist/lib/testing/comply-controller.mjs.map +1 -1
- package/dist/lib/testing/controller-assertions.mjs +0 -6
- package/dist/lib/testing/controller-assertions.mjs.map +1 -1
- package/dist/lib/testing/formatter.mjs +0 -6
- package/dist/lib/testing/formatter.mjs.map +1 -1
- package/dist/lib/testing/index.mjs +0 -6
- package/dist/lib/testing/index.mjs.map +1 -1
- package/dist/lib/testing/local-agent-runner.mjs +0 -6
- package/dist/lib/testing/local-agent-runner.mjs.map +1 -1
- package/dist/lib/testing/orchestrator.mjs +0 -6
- package/dist/lib/testing/orchestrator.mjs.map +1 -1
- package/dist/lib/testing/personas/index.mjs +0 -6
- package/dist/lib/testing/personas/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.mjs +0 -6
- package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +0 -6
- package/dist/lib/testing/scenarios/capabilities.mjs.map +1 -1
- package/dist/lib/testing/scenarios/creative.mjs +0 -6
- package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
- package/dist/lib/testing/scenarios/deterministic.mjs +0 -6
- package/dist/lib/testing/scenarios/deterministic.mjs.map +1 -1
- package/dist/lib/testing/scenarios/discovery.mjs +0 -6
- package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
- package/dist/lib/testing/scenarios/edge-cases.mjs +0 -6
- package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
- package/dist/lib/testing/scenarios/error-compliance.mjs +0 -6
- package/dist/lib/testing/scenarios/error-compliance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/governance.mjs +0 -6
- package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/health.mjs +0 -6
- package/dist/lib/testing/scenarios/health.mjs.map +1 -1
- package/dist/lib/testing/scenarios/index.mjs +0 -6
- package/dist/lib/testing/scenarios/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.mjs +0 -6
- package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.mjs +0 -6
- package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/signals.mjs +0 -6
- package/dist/lib/testing/scenarios/signals.mjs.map +1 -1
- package/dist/lib/testing/scenarios/sponsored-intelligence.mjs +0 -6
- package/dist/lib/testing/scenarios/sponsored-intelligence.mjs.map +1 -1
- package/dist/lib/testing/scenarios/trusted-match.mjs +0 -6
- package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
- package/dist/lib/testing/seed-merge.mjs +0 -6
- package/dist/lib/testing/seed-merge.mjs.map +1 -1
- package/dist/lib/testing/storyboard/agent-routing.mjs +0 -6
- package/dist/lib/testing/storyboard/agent-routing.mjs.map +1 -1
- package/dist/lib/testing/storyboard/assertions.mjs +0 -6
- package/dist/lib/testing/storyboard/assertions.mjs.map +1 -1
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs +0 -6
- package/dist/lib/testing/storyboard/canonical-format-satisfaction.mjs.map +1 -1
- package/dist/lib/testing/storyboard/compliance.mjs +5 -6
- package/dist/lib/testing/storyboard/compliance.mjs.map +1 -1
- package/dist/lib/testing/storyboard/context.mjs +0 -6
- package/dist/lib/testing/storyboard/context.mjs.map +1 -1
- package/dist/lib/testing/storyboard/default-invariants.mjs +0 -6
- package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
- package/dist/lib/testing/storyboard/index.mjs +0 -6
- package/dist/lib/testing/storyboard/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/junit.mjs +0 -6
- package/dist/lib/testing/storyboard/junit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/loader.mjs +0 -6
- package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/parallel-dispatch.mjs +0 -6
- package/dist/lib/testing/storyboard/parallel-dispatch.mjs.map +1 -1
- package/dist/lib/testing/storyboard/path.mjs +0 -6
- package/dist/lib/testing/storyboard/path.mjs.map +1 -1
- package/dist/lib/testing/storyboard/probes.mjs +0 -6
- package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
- package/dist/lib/testing/storyboard/rate-limit-trip.mjs +0 -6
- package/dist/lib/testing/storyboard/rate-limit-trip.mjs.map +1 -1
- package/dist/lib/testing/storyboard/rejection-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/rejection-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.mjs +0 -6
- package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/builder.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/grader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/index.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/probe.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/probe.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/types.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +0 -6
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +0 -6
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/sandbox-entities.mjs +0 -6
- package/dist/lib/testing/storyboard/sandbox-entities.mjs.map +1 -1
- package/dist/lib/testing/storyboard/seeding.mjs +0 -6
- package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs +0 -6
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/index.mjs +0 -6
- package/dist/lib/testing/storyboard/signer-grader/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/signer-grader/types.mjs +0 -6
- package/dist/lib/testing/storyboard/strict-validation-hints.mjs +0 -6
- package/dist/lib/testing/storyboard/strict-validation-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +0 -6
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/storyboard/test-kit.mjs +0 -6
- package/dist/lib/testing/storyboard/test-kit.mjs.map +1 -1
- package/dist/lib/testing/storyboard/types.mjs +0 -6
- package/dist/lib/testing/storyboard/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.mjs +0 -6
- package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
- package/dist/lib/testing/storyboard/webhook-assertions.mjs +0 -6
- package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
- package/dist/lib/testing/storyboard/webhook-receiver.mjs +0 -6
- package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
- package/dist/lib/testing/stubs/governance-agent-stub.mjs +0 -6
- package/dist/lib/testing/stubs/governance-agent-stub.mjs.map +1 -1
- package/dist/lib/testing/stubs/index.mjs +0 -6
- package/dist/lib/testing/stubs/index.mjs.map +1 -1
- package/dist/lib/testing/test-controller.mjs +0 -6
- package/dist/lib/testing/test-controller.mjs.map +1 -1
- package/dist/lib/testing/test-helpers.mjs +0 -6
- package/dist/lib/testing/test-helpers.mjs.map +1 -1
- package/dist/lib/testing/types.mjs +0 -6
- package/dist/lib/types/adcp.mjs +0 -6
- package/dist/lib/types/adcp.mjs.map +1 -1
- package/dist/lib/types/asset-instances.mjs +0 -6
- package/dist/lib/types/compat.mjs +0 -6
- package/dist/lib/types/compat.mjs.map +1 -1
- package/dist/lib/types/core.generated.mjs +0 -6
- package/dist/lib/types/enums.generated.mjs +0 -6
- package/dist/lib/types/enums.generated.mjs.map +1 -1
- package/dist/lib/types/error-codes.mjs +0 -6
- package/dist/lib/types/error-codes.mjs.map +1 -1
- package/dist/lib/types/error-details.aliases.mjs +0 -6
- package/dist/lib/types/error-details.aliases.mjs.map +1 -1
- package/dist/lib/types/format-asset-slots.mjs +0 -6
- package/dist/lib/types/forward-compat-error-codes.mjs +0 -6
- package/dist/lib/types/forward-compat-error-codes.mjs.map +1 -1
- package/dist/lib/types/index.mjs +0 -6
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/types/inline-enums.aliases.mjs +0 -6
- package/dist/lib/types/inline-enums.aliases.mjs.map +1 -1
- package/dist/lib/types/inline-enums.generated.mjs +0 -6
- package/dist/lib/types/inline-enums.generated.mjs.map +1 -1
- package/dist/lib/types/manifest.generated.mjs +0 -6
- package/dist/lib/types/manifest.generated.mjs.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +0 -6
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/server-payload-aliases.mjs +0 -6
- package/dist/lib/types/server-payload.mjs +0 -6
- package/dist/lib/types/sync-rows.mjs +0 -6
- package/dist/lib/types/tools.generated.mjs +0 -6
- package/dist/lib/types/v2-5/index.mjs +0 -6
- package/dist/lib/types/v2-5/index.mjs.map +1 -1
- package/dist/lib/types/v2-5/tools.generated.mjs +0 -6
- package/dist/lib/types/v3-1-beta/index.mjs +0 -6
- package/dist/lib/types/v3-1-beta/index.mjs.map +1 -1
- package/dist/lib/types/v3-1-beta/tools.generated.mjs +0 -6
- package/dist/lib/types/wellknown-schemas.generated.mjs +0 -6
- package/dist/lib/types/wellknown-schemas.generated.mjs.map +1 -1
- package/dist/lib/upstream-recorder/constants.mjs +0 -6
- package/dist/lib/upstream-recorder/constants.mjs.map +1 -1
- package/dist/lib/upstream-recorder/index.mjs +0 -6
- package/dist/lib/upstream-recorder/index.mjs.map +1 -1
- package/dist/lib/upstream-recorder/recorder.mjs +0 -6
- package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
- package/dist/lib/upstream-recorder/types.mjs +0 -6
- package/dist/lib/upstream-recorder/types.mjs.map +1 -1
- package/dist/lib/utils/a2a-artifacts.mjs +0 -6
- package/dist/lib/utils/a2a-artifacts.mjs.map +1 -1
- package/dist/lib/utils/a2a-discovery.mjs +0 -6
- package/dist/lib/utils/a2a-discovery.mjs.map +1 -1
- package/dist/lib/utils/activation-key-builders.mjs +0 -6
- package/dist/lib/utils/activation-key-builders.mjs.map +1 -1
- package/dist/lib/utils/adcp-version-config.mjs +0 -6
- package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
- package/dist/lib/utils/asset-builders.mjs +0 -6
- package/dist/lib/utils/asset-builders.mjs.map +1 -1
- package/dist/lib/utils/build-creative-return-builders.mjs +0 -6
- package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
- package/dist/lib/utils/buyer-retry-policy.mjs +0 -6
- package/dist/lib/utils/buyer-retry-policy.mjs.map +1 -1
- package/dist/lib/utils/capabilities.mjs +0 -6
- package/dist/lib/utils/capabilities.mjs.map +1 -1
- package/dist/lib/utils/capability-rollups.mjs +0 -6
- package/dist/lib/utils/capability-rollups.mjs.map +1 -1
- package/dist/lib/utils/creative-adapter.mjs +0 -6
- package/dist/lib/utils/creative-adapter.mjs.map +1 -1
- package/dist/lib/utils/creative-delivery.mjs +0 -6
- package/dist/lib/utils/creative-delivery.mjs.map +1 -1
- package/dist/lib/utils/deprecation.mjs +0 -6
- package/dist/lib/utils/deprecation.mjs.map +1 -1
- package/dist/lib/utils/envelope-status-compat.mjs +0 -6
- package/dist/lib/utils/envelope-status-compat.mjs.map +1 -1
- package/dist/lib/utils/error-extraction.mjs +0 -6
- package/dist/lib/utils/error-extraction.mjs.map +1 -1
- package/dist/lib/utils/extract-result.mjs +0 -6
- package/dist/lib/utils/extract-result.mjs.map +1 -1
- package/dist/lib/utils/format-asset-slot-builders.mjs +0 -6
- package/dist/lib/utils/format-asset-slot-builders.mjs.map +1 -1
- package/dist/lib/utils/format-assets.mjs +0 -6
- package/dist/lib/utils/format-assets.mjs.map +1 -1
- package/dist/lib/utils/format-render-builders.mjs +0 -6
- package/dist/lib/utils/format-render-builders.mjs.map +1 -1
- package/dist/lib/utils/format-renders.mjs +0 -6
- package/dist/lib/utils/format-renders.mjs.map +1 -1
- package/dist/lib/utils/get-products-cache-scope.mjs +0 -6
- package/dist/lib/utils/get-products-cache-scope.mjs.map +1 -1
- package/dist/lib/utils/glob.mjs +0 -6
- package/dist/lib/utils/glob.mjs.map +1 -1
- package/dist/lib/utils/global-async-local-storage.mjs +0 -6
- package/dist/lib/utils/global-async-local-storage.mjs.map +1 -1
- package/dist/lib/utils/idempotency.mjs +0 -6
- package/dist/lib/utils/idempotency.mjs.map +1 -1
- package/dist/lib/utils/index.mjs +0 -6
- package/dist/lib/utils/index.mjs.map +1 -1
- package/dist/lib/utils/jcs.mjs +0 -6
- package/dist/lib/utils/jcs.mjs.map +1 -1
- package/dist/lib/utils/json-depth.mjs +0 -6
- package/dist/lib/utils/json-depth.mjs.map +1 -1
- package/dist/lib/utils/logger.mjs +0 -6
- package/dist/lib/utils/logger.mjs.map +1 -1
- package/dist/lib/utils/media-buy-delivery-notification-builders.mjs +0 -6
- package/dist/lib/utils/media-buy-delivery-notification-builders.mjs.map +1 -1
- package/dist/lib/utils/media-buy-status.mjs +0 -6
- package/dist/lib/utils/media-buy-status.mjs.map +1 -1
- package/dist/lib/utils/pagination.mjs +0 -6
- package/dist/lib/utils/pagination.mjs.map +1 -1
- package/dist/lib/utils/preview-creative-builders.mjs +0 -6
- package/dist/lib/utils/preview-creative-builders.mjs.map +1 -1
- package/dist/lib/utils/preview-normalizer.mjs +0 -6
- package/dist/lib/utils/preview-normalizer.mjs.map +1 -1
- package/dist/lib/utils/preview-utils.mjs +0 -6
- package/dist/lib/utils/preview-utils.mjs.map +1 -1
- package/dist/lib/utils/pricing-adapter.mjs +0 -6
- package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
- package/dist/lib/utils/probe-policy.mjs +0 -6
- package/dist/lib/utils/probe-policy.mjs.map +1 -1
- package/dist/lib/utils/protocol-detection.mjs +0 -6
- package/dist/lib/utils/protocol-detection.mjs.map +1 -1
- package/dist/lib/utils/redact-secrets.mjs +0 -6
- package/dist/lib/utils/redact-secrets.mjs.map +1 -1
- package/dist/lib/utils/redis-default-prefix-warn.mjs +0 -6
- package/dist/lib/utils/redis-default-prefix-warn.mjs.map +1 -1
- package/dist/lib/utils/render-builders.mjs +0 -6
- package/dist/lib/utils/render-builders.mjs.map +1 -1
- package/dist/lib/utils/request-normalizer.mjs +0 -6
- package/dist/lib/utils/request-normalizer.mjs.map +1 -1
- package/dist/lib/utils/response-schemas.mjs +0 -6
- package/dist/lib/utils/response-schemas.mjs.map +1 -1
- package/dist/lib/utils/response-unwrapper.mjs +0 -6
- package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
- package/dist/lib/utils/retry.mjs +0 -6
- package/dist/lib/utils/retry.mjs.map +1 -1
- package/dist/lib/utils/signal-discovery-helpers.mjs +0 -6
- package/dist/lib/utils/signal-discovery-helpers.mjs.map +1 -1
- package/dist/lib/utils/signal-id-builders.mjs +0 -6
- package/dist/lib/utils/signal-id-builders.mjs.map +1 -1
- package/dist/lib/utils/sync-creatives-adapter.mjs +0 -6
- package/dist/lib/utils/sync-creatives-adapter.mjs.map +1 -1
- package/dist/lib/utils/task-state.mjs +0 -6
- package/dist/lib/utils/task-state.mjs.map +1 -1
- package/dist/lib/utils/tool-request-schemas.mjs +0 -6
- package/dist/lib/utils/tool-request-schemas.mjs.map +1 -1
- package/dist/lib/utils/typeGuards.mjs +0 -6
- package/dist/lib/utils/typeGuards.mjs.map +1 -1
- package/dist/lib/utils/union-errors.mjs +0 -6
- package/dist/lib/utils/union-errors.mjs.map +1 -1
- package/dist/lib/utils/validate-user-agent.mjs +0 -6
- package/dist/lib/utils/validate-user-agent.mjs.map +1 -1
- package/dist/lib/v2/format-schema/fetch.mjs +0 -6
- package/dist/lib/v2/format-schema/fetch.mjs.map +1 -1
- package/dist/lib/v2/format-schema/index.mjs +0 -6
- package/dist/lib/v2/format-schema/index.mjs.map +1 -1
- package/dist/lib/v2/format-schema/regex-safety.mjs +0 -6
- package/dist/lib/v2/format-schema/regex-safety.mjs.map +1 -1
- package/dist/lib/v2/format-schema/resolver.mjs +7 -8
- package/dist/lib/v2/format-schema/resolver.mjs.map +1 -1
- package/dist/lib/v2/format-schema/sandbox-refs.mjs +0 -6
- package/dist/lib/v2/format-schema/sandbox-refs.mjs.map +1 -1
- package/dist/lib/v2/projection/augment-response.mjs +0 -6
- package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
- package/dist/lib/v2/projection/builders.mjs +0 -6
- package/dist/lib/v2/projection/builders.mjs.map +1 -1
- package/dist/lib/v2/projection/cache-versions.mjs +0 -6
- package/dist/lib/v2/projection/cache-versions.mjs.map +1 -1
- package/dist/lib/v2/projection/canonical-properties.mjs +5 -6
- package/dist/lib/v2/projection/canonical-properties.mjs.map +1 -1
- package/dist/lib/v2/projection/catalog.mjs +5 -6
- package/dist/lib/v2/projection/catalog.mjs.map +1 -1
- package/dist/lib/v2/projection/constants.mjs +0 -6
- package/dist/lib/v2/projection/constants.mjs.map +1 -1
- package/dist/lib/v2/projection/index.mjs +0 -6
- package/dist/lib/v2/projection/index.mjs.map +1 -1
- package/dist/lib/v2/projection/registry.mjs +5 -6
- package/dist/lib/v2/projection/registry.mjs.map +1 -1
- package/dist/lib/v2/projection/types.mjs +0 -6
- package/dist/lib/v2/projection/v1-to-v2.mjs +0 -6
- package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
- package/dist/lib/v2/projection/v2-to-v1.mjs +0 -6
- package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
- package/dist/lib/v2/projection/write-side.mjs +0 -6
- package/dist/lib/v2/projection/write-side.mjs.map +1 -1
- package/dist/lib/v2/publisher-catalog/formats.mjs +0 -6
- package/dist/lib/v2/publisher-catalog/formats.mjs.map +1 -1
- package/dist/lib/v2/publisher-catalog/index.mjs +0 -6
- package/dist/lib/v2/publisher-catalog/index.mjs.map +1 -1
- package/dist/lib/validation/client-hooks.mjs +0 -6
- package/dist/lib/validation/client-hooks.mjs.map +1 -1
- package/dist/lib/validation/hints.mjs +0 -6
- package/dist/lib/validation/hints.mjs.map +1 -1
- package/dist/lib/validation/index.mjs +0 -6
- package/dist/lib/validation/index.mjs.map +1 -1
- package/dist/lib/validation/schema-errors.mjs +0 -6
- package/dist/lib/validation/schema-errors.mjs.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +5 -6
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/validation/schema-validator.mjs +0 -6
- package/dist/lib/validation/schema-validator.mjs.map +1 -1
- package/dist/lib/validation/sync-creatives.mjs +0 -6
- package/dist/lib/validation/sync-creatives.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 -9
- package/dist/lib/version.mjs.map +1 -1
- package/dist/lib/webhooks/index.mjs +0 -6
- package/dist/lib/webhooks/index.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/index.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/index.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/sync.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/sync.mjs.map +1 -1
- package/dist/lib/wholesale-feed-sync/types.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +0 -6
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
const observed = /* @__PURE__ */ new Set();
|
|
8
2
|
function recordResolvedAccountMode(account) {
|
|
9
3
|
if (account == null || typeof account !== "object") return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/observed-modes.ts"],"sourcesContent":["/**\n * Process-scoped tracker of explicit `Account.mode` values returned from\n * `platform.accounts.resolve` during framework-side comply-controller\n * dispatch. Used by the sandbox gate's deprecated env-fallback path\n * (`ADCP_SANDBOX === '1'`) to fail closed when a process has resolved\n * any live-mode account.\n *\n * Rationale: the env-fallback exists for back-compat with adopters that\n * have not yet adopted the per-account `mode` field. If those adopters\n * have ALSO begun returning explicit `mode: 'live'` from their resolver,\n * the env var is a misconfiguration — leaving it set would re-open the\n * gate for live principals after the resolver was meant to close it.\n *\n * Implicit-default `live` (resolver returns no mode field) is NOT\n * observed here — those adopters are exactly who the env-fallback bridge\n * exists for. Only the own-property `mode === 'live'` shape, set\n * deliberately by the resolver, trips the guard.\n *\n * @internal\n */\n\nconst observed = new Set<string>();\n\n/**\n * Record an account returned from `platform.accounts.resolve`. Reads\n * via `Object.hasOwn` so the same prototype-pollution defense as\n * `getAccountMode` applies — an attacker who reaches a `__proto__`-via-\n * merge sink can't stamp `Object.prototype.mode = 'sandbox'` to evade\n * the live observation.\n *\n * No-op when `account` is null / not an object / lacks an own `mode`\n * property / `mode` is not a known string. The set only collects\n * explicit, deliberate mode values.\n */\nexport function recordResolvedAccountMode(account: unknown): void {\n if (account == null || typeof account !== 'object') return;\n if (!Object.hasOwn(account, 'mode')) return;\n const mode = (account as { mode?: unknown }).mode;\n if (mode === 'live' || mode === 'sandbox' || mode === 'mock') {\n observed.add(mode);\n }\n}\n\n/**\n * `true` when this process has observed at least one explicit\n * `mode: 'live'` account from `platform.accounts.resolve`. The\n * sandbox-gate env-fallback consults this to decide whether\n * `ADCP_SANDBOX=1` is a safe legacy bridge or a misconfiguration.\n */\nexport function hasObservedLiveMode(): boolean {\n return observed.has('live');\n}\n\n/**\n * Test seam — reset the observed-modes set between describe blocks\n * so a test that intentionally resolves a live account doesn't leak\n * the observation into subsequent tests in the same process.\n *\n * Refuses to clear when `NODE_ENV` is anything other than `test` or\n * `development`. The observed-modes set is intentionally process-scoped\n * — clearing it in production would re-arm the env-fallback admit path\n * for live principals already seen, defeating the whole point of the\n * fail-closed guard. The allowlist (rather than `!= 'production'`)\n * matches the project's broader `feedback_node_env_allowlist.md` policy.\n *\n * Not part of the public API. Adopter code MUST NOT call this.\n *\n * @internal\n */\nexport function __resetObservedAccountModes(): void {\n const env = process.env.NODE_ENV;\n if (env !== 'test' && env !== 'development') {\n throw new Error(\n `__resetObservedAccountModes is a test seam; refusing to clear observed account modes ` +\n `in NODE_ENV=${env ?? '<unset>'}. The set is process-scoped to keep the comply ` +\n `controller's env-fallback fail-closed guard armed once a live account has been seen.`\n );\n }\n observed.clear();\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/observed-modes.ts"],"sourcesContent":["/**\n * Process-scoped tracker of explicit `Account.mode` values returned from\n * `platform.accounts.resolve` during framework-side comply-controller\n * dispatch. Used by the sandbox gate's deprecated env-fallback path\n * (`ADCP_SANDBOX === '1'`) to fail closed when a process has resolved\n * any live-mode account.\n *\n * Rationale: the env-fallback exists for back-compat with adopters that\n * have not yet adopted the per-account `mode` field. If those adopters\n * have ALSO begun returning explicit `mode: 'live'` from their resolver,\n * the env var is a misconfiguration — leaving it set would re-open the\n * gate for live principals after the resolver was meant to close it.\n *\n * Implicit-default `live` (resolver returns no mode field) is NOT\n * observed here — those adopters are exactly who the env-fallback bridge\n * exists for. Only the own-property `mode === 'live'` shape, set\n * deliberately by the resolver, trips the guard.\n *\n * @internal\n */\n\nconst observed = new Set<string>();\n\n/**\n * Record an account returned from `platform.accounts.resolve`. Reads\n * via `Object.hasOwn` so the same prototype-pollution defense as\n * `getAccountMode` applies — an attacker who reaches a `__proto__`-via-\n * merge sink can't stamp `Object.prototype.mode = 'sandbox'` to evade\n * the live observation.\n *\n * No-op when `account` is null / not an object / lacks an own `mode`\n * property / `mode` is not a known string. The set only collects\n * explicit, deliberate mode values.\n */\nexport function recordResolvedAccountMode(account: unknown): void {\n if (account == null || typeof account !== 'object') return;\n if (!Object.hasOwn(account, 'mode')) return;\n const mode = (account as { mode?: unknown }).mode;\n if (mode === 'live' || mode === 'sandbox' || mode === 'mock') {\n observed.add(mode);\n }\n}\n\n/**\n * `true` when this process has observed at least one explicit\n * `mode: 'live'` account from `platform.accounts.resolve`. The\n * sandbox-gate env-fallback consults this to decide whether\n * `ADCP_SANDBOX=1` is a safe legacy bridge or a misconfiguration.\n */\nexport function hasObservedLiveMode(): boolean {\n return observed.has('live');\n}\n\n/**\n * Test seam — reset the observed-modes set between describe blocks\n * so a test that intentionally resolves a live account doesn't leak\n * the observation into subsequent tests in the same process.\n *\n * Refuses to clear when `NODE_ENV` is anything other than `test` or\n * `development`. The observed-modes set is intentionally process-scoped\n * — clearing it in production would re-arm the env-fallback admit path\n * for live principals already seen, defeating the whole point of the\n * fail-closed guard. The allowlist (rather than `!= 'production'`)\n * matches the project's broader `feedback_node_env_allowlist.md` policy.\n *\n * Not part of the public API. Adopter code MUST NOT call this.\n *\n * @internal\n */\nexport function __resetObservedAccountModes(): void {\n const env = process.env.NODE_ENV;\n if (env !== 'test' && env !== 'development') {\n throw new Error(\n `__resetObservedAccountModes is a test seam; refusing to clear observed account modes ` +\n `in NODE_ENV=${env ?? '<unset>'}. The set is process-scoped to keep the comply ` +\n `controller's env-fallback fail-closed guard armed once a live account has been seen.`\n );\n }\n observed.clear();\n}\n"],"mappings":"AAqBA,MAAM,WAAW,oBAAI,IAAY;AAa1B,SAAS,0BAA0B,SAAwB;AAChE,MAAI,WAAW,QAAQ,OAAO,YAAY,SAAU;AACpD,MAAI,CAAC,OAAO,OAAO,SAAS,MAAM,EAAG;AACrC,QAAM,OAAQ,QAA+B;AAC7C,MAAI,SAAS,UAAU,SAAS,aAAa,SAAS,QAAQ;AAC5D,aAAS,IAAI,IAAI;AAAA,EACnB;AACF;AAQO,SAAS,sBAA+B;AAC7C,SAAO,SAAS,IAAI,MAAM;AAC5B;AAkBO,SAAS,8BAAoC;AAClD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ,UAAU,QAAQ,eAAe;AAC3C,UAAM,IAAI;AAAA,MACR,oGACiB,OAAO,SAAS;AAAA,IAEnC;AAAA,EACF;AACA,WAAS,MAAM;AACjB;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { randomUUID } from "node:crypto";
|
|
8
2
|
const DEFAULT_TABLE = "adcp_decisioning_tasks";
|
|
9
3
|
const VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/postgres-task-registry.ts"],"sourcesContent":["/**\n * PostgreSQL-backed `TaskRegistry` for the v6.0 decisioning runtime.\n *\n * The default `createInMemoryTaskRegistry()` loses task state on process\n * restart and doesn't share state across instances behind a load balancer —\n * fine for tests and local dev, broken for production HITL paths\n * (`createMediaBuyTask`, `syncCreativesTask`, etc.). Wire this in via\n * `createAdcpServerFromPlatform({ taskRegistry: createPostgresTaskRegistry({ pool }) })`\n * to persist task lifecycle across requests, processes, and crashes.\n *\n * @example\n * ```typescript\n * import { Pool } from 'pg';\n * import {\n * createAdcpServerFromPlatform,\n * createPostgresTaskRegistry,\n * getDecisioningTaskRegistryMigration,\n * } from '@adcp/sdk/server/decisioning';\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n *\n * // Run once at boot — idempotent CREATE TABLE IF NOT EXISTS.\n * await pool.query(getDecisioningTaskRegistryMigration());\n *\n * const server = createAdcpServerFromPlatform(platform, {\n * name: 'My Ad Network',\n * version: '1.0.0',\n * taskRegistry: createPostgresTaskRegistry({ pool }),\n * });\n * ```\n *\n * **Background-completion lifecycle.** `_registerBackground` / `awaitTask`\n * are PROCESS-LOCAL — promises don't serialize. When a HITL `*Task` method\n * is invoked, the returned promise lives on the originating process; if\n * that process restarts before the method completes, the task record stays\n * in `submitted` state in Postgres but no `awaitTask` resolution is\n * possible from a different instance. Production HITL flows that span\n * process boundaries should drive completion via webhook → an explicit\n * `complete()` / `fail()` call from the webhook handler, not via\n * `awaitTask`. The MCP `tasks/get` wire path reads via `getTask` and is\n * already cross-instance.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AdcpStructuredError, TaskHandoffProgress } from '../async-outcome';\nimport type { TaskRecord, TaskRegistry, TaskStatus } from './task-registry';\n\n/**\n * Minimal subset of the `pg.Pool` interface used by the registry.\n * Mirrors `PgQueryable` in `postgres-task-store.ts` so callers can pass\n * pools, transaction wrappers, or any pg-compatible query executor.\n */\nexport interface PgQueryable {\n query(text: string, values?: unknown[]): Promise<{ rows: Record<string, unknown>[]; rowCount: number | null }>;\n}\n\nexport interface CreatePostgresTaskRegistryOptions {\n /** A `pg.Pool` instance (or any `PgQueryable`). */\n pool: PgQueryable;\n /**\n * Table name. Defaults to `'adcp_decisioning_tasks'` (vendor-prefixed to\n * avoid collisions with the MCP-level `adcp_mcp_tasks` table from\n * `PostgresTaskStore` and any consumer tables).\n *\n * Must match `^[a-z_][a-z0-9_]*$` — schema-qualified names are not\n * supported by this validator. Set search_path on the pool if you need\n * a non-default schema.\n */\n tableName?: string;\n}\n\n/** Default table name — vendor-prefixed to avoid collisions. */\nconst DEFAULT_TABLE = 'adcp_decisioning_tasks';\n\n/** Validates a SQL identifier to prevent injection via table names. */\nconst VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;\n\nfunction assertValidIdentifier(name: string): void {\n if (!VALID_IDENTIFIER.test(name)) {\n throw new Error(\n `Invalid table name \"${name}\": must be lowercase letters, digits, ` +\n `or underscores, starting with a letter or underscore.`\n );\n }\n}\n\n/**\n * Cap on `result` / `error` JSONB column size. Adopter `*Task` returns are\n * written verbatim — a buggy or malicious adopter handing back a 1GB\n * result would OOM the Node process before pg complains. 4MB matches the\n * default Postgres `toast` row threshold and gives plenty of headroom for\n * legitimate task payloads.\n *\n * **This cap protects the DB write path only.** Adopter code that\n * serializes `result` / `error` for logs, metrics, or downstream services\n * MUST impose its own size cap — `JSON.stringify(result)` in a logger\n * call is unbounded.\n */\nconst MAX_RESULT_BYTES = 4 * 1024 * 1024;\n\nfunction assertResultSize(json: string, taskId: string): void {\n // `Buffer.byteLength` is utf-8 byte length, which is what Postgres stores.\n if (Buffer.byteLength(json, 'utf8') > MAX_RESULT_BYTES) {\n throw new Error(\n `Task ${taskId}: result/error JSON exceeds ${MAX_RESULT_BYTES} bytes ` +\n `(adopter *Task method returned an oversized payload — investigate ` +\n `whether the body should be persisted via blob storage and referenced).`\n );\n }\n}\n\n/**\n * Wrap `JSON.stringify` with a clearer error when the adopter `*Task`\n * return contains circular references. Default `TypeError: Converting\n * circular structure to JSON` doesn't surface the task id; this version\n * bubbles a registry-write error pointing at the adopter return shape.\n */\nfunction safeStringify(value: unknown, taskId: string): string {\n try {\n return JSON.stringify(value);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Task ${taskId}: adopter *Task return is not JSON-serializable: ${msg}. ` +\n `Strip circular refs / non-plain-data before returning from your *Task method.`\n );\n }\n}\n\n/**\n * Generate the SQL DDL for the decisioning task registry table.\n *\n * Run once at boot (idempotent — `CREATE TABLE IF NOT EXISTS`). Constraint\n * and index names are derived from the table name to avoid collisions when\n * multiple registries share the same database.\n *\n * @example\n * ```typescript\n * import { getDecisioningTaskRegistryMigration } from '@adcp/sdk/server/decisioning';\n * await pool.query(getDecisioningTaskRegistryMigration());\n * await pool.query(getDecisioningTaskRegistryMigration({ tableName: 'my_tasks' }));\n * ```\n */\nexport function getDecisioningTaskRegistryMigration(options?: { tableName?: string }): string {\n const table = options?.tableName ?? DEFAULT_TABLE;\n assertValidIdentifier(table);\n return `\nCREATE TABLE IF NOT EXISTS ${table} (\n task_id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n account_id TEXT NOT NULL,\n owner_scope TEXT,\n status TEXT NOT NULL DEFAULT 'submitted',\n status_message TEXT,\n result JSONB,\n error JSONB,\n progress JSONB,\n has_webhook BOOLEAN NOT NULL DEFAULT FALSE,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\n CONSTRAINT ${table}_valid_status CHECK (\n -- Framework-written values: 'submitted' (initial), 'working'\n -- (after first updateProgress() call), 'completed' / 'failed'\n -- (terminal). The other 5 spec-defined states ('input-required',\n -- 'canceled', 'rejected', 'auth-required', 'unknown') are reserved\n -- for adopter-emitted transitions via the v6.1\n -- \\`taskRegistry.transition()\\` API; the v6.1 migration will widen\n -- this CHECK.\n status IN ('submitted', 'working', 'completed', 'failed')\n )\n);\n\nCREATE INDEX IF NOT EXISTS idx_${table}_account_id\n ON ${table}(account_id);\n\nCREATE INDEX IF NOT EXISTS idx_${table}_status_created\n ON ${table}(status, created_at);\n\nALTER TABLE ${table}\n ADD COLUMN IF NOT EXISTS owner_scope TEXT;\n\nCREATE INDEX IF NOT EXISTS idx_${table}_owner_account\n ON ${table}(owner_scope, account_id);\n`.trim();\n}\n\ninterface DbTaskRow {\n task_id: string;\n tool: string;\n account_id: string;\n owner_scope: string | null;\n status: TaskStatus;\n status_message: string | null;\n result: unknown;\n error: AdcpStructuredError | null;\n progress: TaskHandoffProgress | null;\n has_webhook: boolean;\n created_at: Date;\n updated_at: Date;\n}\n\nfunction rowToRecord<TResult>(row: DbTaskRow): TaskRecord<TResult> {\n return {\n taskId: row.task_id,\n tool: row.tool,\n accountId: row.account_id,\n ...(row.owner_scope ? { ownerScope: row.owner_scope } : {}),\n status: row.status,\n ...(row.status_message !== null && { statusMessage: row.status_message }),\n ...(row.result !== null && row.result !== undefined && { result: row.result as TResult }),\n ...(row.error !== null && row.error !== undefined && { error: row.error }),\n ...(row.progress !== null && row.progress !== undefined && { progress: row.progress }),\n ...(row.has_webhook && { hasWebhook: true }),\n createdAt: row.created_at.toISOString(),\n updatedAt: row.updated_at.toISOString(),\n };\n}\n\n/**\n * Build a Postgres-backed `TaskRegistry`.\n *\n * Idempotency: `complete()` and `fail()` are no-ops on already-terminal\n * tasks, matching `createInMemoryTaskRegistry()`. The terminal-state guard\n * is enforced via SQL `WHERE status = 'submitted'` predicates so concurrent\n * webhook deliveries can't race to overwrite each other.\n *\n * **Multi-tenant deployments — accountId namespacing.** When sharing a\n * single Postgres registry across tenants in a `TenantRegistry`\n * deployment (one table for all tenants), prefix `account_id` per-tenant\n * to prevent cross-tenant collisions. If tenant A and tenant B both\n * resolve a buyer to literal `account_id: 'acme'`, their tasks land in\n * the same row keyspace and `tasks_get` can't distinguish ownership\n * by `account_id` alone (the tenant boundary upstream IS protected by\n * `accounts.resolve(ref, ctx)` returning each tenant's own Account, but\n * the registry sees the same `acme` string in both rows). Recommended\n * pattern: adopters' `accounts.resolve` returns\n * `id: \\`tenant_${tenantId}_${accountId}\\`` so the table-level keys\n * stay distinct. Alternative: separate `tableName` per tenant, one\n * `createPostgresTaskRegistry({ pool, tableName })` per `TenantRegistry`\n * tenant — heavier ops, stronger isolation.\n */\nexport function createPostgresTaskRegistry(opts: CreatePostgresTaskRegistryOptions): TaskRegistry {\n const table = opts.tableName ?? DEFAULT_TABLE;\n assertValidIdentifier(table);\n const pool = opts.pool;\n\n // Process-local background tracking — see file header note. Promises\n // can't be persisted; cross-instance HITL completion happens via\n // webhook → explicit complete()/fail(), not via awaitTask.\n const backgrounds = new Map<string, Promise<void>>();\n\n return {\n async create(createOpts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }> {\n const taskId = createOpts.overrideTaskId ?? `task_${randomUUID()}`;\n const result = await pool.query(\n `INSERT INTO ${table} (task_id, tool, account_id, owner_scope, status, has_webhook) VALUES ($1, $2, $3, $4, 'submitted', $5) ON CONFLICT (task_id) DO NOTHING`,\n [\n taskId,\n createOpts.tool,\n createOpts.accountId,\n createOpts.ownerScope ?? `account:${createOpts.accountId}`,\n createOpts.hasWebhook === true,\n ]\n );\n if ((result.rowCount ?? 0) === 0) {\n throw new Error(`task_id already registered: ${taskId}`);\n }\n return { taskId };\n },\n\n async getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null> {\n const { rows } = await pool.query(\n `SELECT task_id, tool, account_id, owner_scope, status, status_message, result, error, progress, has_webhook, created_at, updated_at\n FROM ${table} WHERE task_id = $1`,\n [taskId]\n );\n if (rows.length === 0) return null;\n return rowToRecord<TResult>(rows[0] as unknown as DbTaskRow);\n },\n\n async list(listOpts: { accountId: string; ownerScope?: string }): Promise<{ tasks: TaskRecord[] }> {\n if (listOpts.ownerScope === undefined) return { tasks: [] };\n const { rows } = await pool.query(\n `SELECT task_id, tool, account_id, owner_scope, status, status_message, result, error, progress, has_webhook, created_at, updated_at\n FROM ${table}\n WHERE account_id = $1 AND (owner_scope = $2 OR (owner_scope IS NULL AND $2 = $3))\n ORDER BY created_at DESC, task_id DESC`,\n [listOpts.accountId, listOpts.ownerScope, `account:${listOpts.accountId}`]\n );\n return { tasks: rows.map(row => rowToRecord(row as unknown as DbTaskRow)) };\n },\n\n async complete<TResult>(taskId: string, result: TResult): Promise<void> {\n const json = safeStringify(result, taskId);\n assertResultSize(json, taskId);\n await pool.query(\n `UPDATE ${table}\n SET status = 'completed', result = $2::jsonb, updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json]\n );\n },\n\n async fail(taskId: string, error: AdcpStructuredError): Promise<void> {\n const json = safeStringify(error, taskId);\n assertResultSize(json, taskId);\n await pool.query(\n `UPDATE ${table}\n SET status = 'failed', error = $2::jsonb, status_message = $3, updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json, error.message]\n );\n },\n\n async updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void> {\n const json = safeStringify(progress, taskId);\n await pool.query(\n `UPDATE ${table}\n SET progress = $2::jsonb,\n status = CASE WHEN status = 'submitted' THEN 'working' ELSE status END,\n updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json]\n );\n },\n\n _registerBackground(taskId: string, completion: Promise<void>): void {\n const composed: Promise<void> = completion.then(\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n },\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n }\n );\n backgrounds.set(taskId, composed);\n },\n\n async awaitTask(taskId: string): Promise<void> {\n const pending = backgrounds.get(taskId);\n if (pending) await pending;\n },\n } satisfies TaskRegistry;\n}\n"],"mappings":";;;;;;AA+CA,SAAS,kBAAkB;AA6B3B,MAAM,gBAAgB;AAGtB,MAAM,mBAAmB;AAEzB,SAAS,sBAAsB,MAAoB;AACjD,MAAI,CAAC,iBAAiB,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI;AAAA,MACR,uBAAuB,IAAI;AAAA,IAE7B;AAAA,EACF;AACF;AAcA,MAAM,mBAAmB,IAAI,OAAO;AAEpC,SAAS,iBAAiB,MAAc,QAAsB;AAE5D,MAAI,OAAO,WAAW,MAAM,MAAM,IAAI,kBAAkB;AACtD,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,+BAA+B,gBAAgB;AAAA,IAG/D;AAAA,EACF;AACF;AAQA,SAAS,cAAc,OAAgB,QAAwB;AAC7D,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,oDAAoD,GAAG;AAAA,IAEvE;AAAA,EACF;AACF;AAgBO,SAAS,oCAAoC,SAA0C;AAC5F,QAAM,QAAQ,SAAS,aAAa;AACpC,wBAAsB,KAAK;AAC3B,SAAO;AAAA,6BACoB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAcnB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAYa,KAAK;AAAA,OAC/B,KAAK;AAAA;AAAA,iCAEqB,KAAK;AAAA,OAC/B,KAAK;AAAA;AAAA,cAEE,KAAK;AAAA;AAAA;AAAA,iCAGc,KAAK;AAAA,OAC/B,KAAK;AAAA,EACV,KAAK;AACP;AAiBA,SAAS,YAAqB,KAAqC;AACjE,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,WAAW,IAAI;AAAA,IACf,GAAI,IAAI,cAAc,EAAE,YAAY,IAAI,YAAY,IAAI,CAAC;AAAA,IACzD,QAAQ,IAAI;AAAA,IACZ,GAAI,IAAI,mBAAmB,QAAQ,EAAE,eAAe,IAAI,eAAe;AAAA,IACvE,GAAI,IAAI,WAAW,QAAQ,IAAI,WAAW,UAAa,EAAE,QAAQ,IAAI,OAAkB;AAAA,IACvF,GAAI,IAAI,UAAU,QAAQ,IAAI,UAAU,UAAa,EAAE,OAAO,IAAI,MAAM;AAAA,IACxE,GAAI,IAAI,aAAa,QAAQ,IAAI,aAAa,UAAa,EAAE,UAAU,IAAI,SAAS;AAAA,IACpF,GAAI,IAAI,eAAe,EAAE,YAAY,KAAK;AAAA,IAC1C,WAAW,IAAI,WAAW,YAAY;AAAA,IACtC,WAAW,IAAI,WAAW,YAAY;AAAA,EACxC;AACF;AAyBO,SAAS,2BAA2B,MAAuD;AAChG,QAAM,QAAQ,KAAK,aAAa;AAChC,wBAAsB,KAAK;AAC3B,QAAM,OAAO,KAAK;AAKlB,QAAM,cAAc,oBAAI,IAA2B;AAEnD,SAAO;AAAA,IACL,MAAM,OAAO,YAMmB;AAC9B,YAAM,SAAS,WAAW,kBAAkB,QAAQ,WAAW,CAAC;AAChE,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB,eAAe,KAAK;AAAA,QACpB;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW,cAAc,WAAW,WAAW,SAAS;AAAA,UACxD,WAAW,eAAe;AAAA,QAC5B;AAAA,MACF;AACA,WAAK,OAAO,YAAY,OAAO,GAAG;AAChC,cAAM,IAAI,MAAM,+BAA+B,MAAM,EAAE;AAAA,MACzD;AACA,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,MAAM,QAA2B,QAAqD;AACpF,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B;AAAA,gBACQ,KAAK;AAAA,QACb,CAAC,MAAM;AAAA,MACT;AACA,UAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,aAAO,YAAqB,KAAK,CAAC,CAAyB;AAAA,IAC7D;AAAA,IAEA,MAAM,KAAK,UAAwF;AACjG,UAAI,SAAS,eAAe,OAAW,QAAO,EAAE,OAAO,CAAC,EAAE;AAC1D,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B;AAAA,gBACQ,KAAK;AAAA;AAAA;AAAA,QAGb,CAAC,SAAS,WAAW,SAAS,YAAY,WAAW,SAAS,SAAS,EAAE;AAAA,MAC3E;AACA,aAAO,EAAE,OAAO,KAAK,IAAI,SAAO,YAAY,GAA2B,CAAC,EAAE;AAAA,IAC5E;AAAA,IAEA,MAAM,SAAkB,QAAgB,QAAgC;AACtE,YAAM,OAAO,cAAc,QAAQ,MAAM;AACzC,uBAAiB,MAAM,MAAM;AAC7B,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA,QAGf,CAAC,QAAQ,IAAI;AAAA,MACf;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAgB,OAA2C;AACpE,YAAM,OAAO,cAAc,OAAO,MAAM;AACxC,uBAAiB,MAAM,MAAM;AAC7B,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA,QAGf,CAAC,QAAQ,MAAM,MAAM,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,eAAe,QAAgB,UAA8C;AACjF,YAAM,OAAO,cAAc,UAAU,MAAM;AAC3C,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,QAKf,CAAC,QAAQ,IAAI;AAAA,MACf;AAAA,IACF;AAAA,IAEA,oBAAoB,QAAgB,YAAiC;AACnE,YAAM,WAA0B,WAAW;AAAA,QACzC,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,QACA,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,MACF;AACA,kBAAY,IAAI,QAAQ,QAAQ;AAAA,IAClC;AAAA,IAEA,MAAM,UAAU,QAA+B;AAC7C,YAAM,UAAU,YAAY,IAAI,MAAM;AACtC,UAAI,QAAS,OAAM;AAAA,IACrB;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/postgres-task-registry.ts"],"sourcesContent":["/**\n * PostgreSQL-backed `TaskRegistry` for the v6.0 decisioning runtime.\n *\n * The default `createInMemoryTaskRegistry()` loses task state on process\n * restart and doesn't share state across instances behind a load balancer —\n * fine for tests and local dev, broken for production HITL paths\n * (`createMediaBuyTask`, `syncCreativesTask`, etc.). Wire this in via\n * `createAdcpServerFromPlatform({ taskRegistry: createPostgresTaskRegistry({ pool }) })`\n * to persist task lifecycle across requests, processes, and crashes.\n *\n * @example\n * ```typescript\n * import { Pool } from 'pg';\n * import {\n * createAdcpServerFromPlatform,\n * createPostgresTaskRegistry,\n * getDecisioningTaskRegistryMigration,\n * } from '@adcp/sdk/server/decisioning';\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL });\n *\n * // Run once at boot — idempotent CREATE TABLE IF NOT EXISTS.\n * await pool.query(getDecisioningTaskRegistryMigration());\n *\n * const server = createAdcpServerFromPlatform(platform, {\n * name: 'My Ad Network',\n * version: '1.0.0',\n * taskRegistry: createPostgresTaskRegistry({ pool }),\n * });\n * ```\n *\n * **Background-completion lifecycle.** `_registerBackground` / `awaitTask`\n * are PROCESS-LOCAL — promises don't serialize. When a HITL `*Task` method\n * is invoked, the returned promise lives on the originating process; if\n * that process restarts before the method completes, the task record stays\n * in `submitted` state in Postgres but no `awaitTask` resolution is\n * possible from a different instance. Production HITL flows that span\n * process boundaries should drive completion via webhook → an explicit\n * `complete()` / `fail()` call from the webhook handler, not via\n * `awaitTask`. The MCP `tasks/get` wire path reads via `getTask` and is\n * already cross-instance.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AdcpStructuredError, TaskHandoffProgress } from '../async-outcome';\nimport type { TaskRecord, TaskRegistry, TaskStatus } from './task-registry';\n\n/**\n * Minimal subset of the `pg.Pool` interface used by the registry.\n * Mirrors `PgQueryable` in `postgres-task-store.ts` so callers can pass\n * pools, transaction wrappers, or any pg-compatible query executor.\n */\nexport interface PgQueryable {\n query(text: string, values?: unknown[]): Promise<{ rows: Record<string, unknown>[]; rowCount: number | null }>;\n}\n\nexport interface CreatePostgresTaskRegistryOptions {\n /** A `pg.Pool` instance (or any `PgQueryable`). */\n pool: PgQueryable;\n /**\n * Table name. Defaults to `'adcp_decisioning_tasks'` (vendor-prefixed to\n * avoid collisions with the MCP-level `adcp_mcp_tasks` table from\n * `PostgresTaskStore` and any consumer tables).\n *\n * Must match `^[a-z_][a-z0-9_]*$` — schema-qualified names are not\n * supported by this validator. Set search_path on the pool if you need\n * a non-default schema.\n */\n tableName?: string;\n}\n\n/** Default table name — vendor-prefixed to avoid collisions. */\nconst DEFAULT_TABLE = 'adcp_decisioning_tasks';\n\n/** Validates a SQL identifier to prevent injection via table names. */\nconst VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;\n\nfunction assertValidIdentifier(name: string): void {\n if (!VALID_IDENTIFIER.test(name)) {\n throw new Error(\n `Invalid table name \"${name}\": must be lowercase letters, digits, ` +\n `or underscores, starting with a letter or underscore.`\n );\n }\n}\n\n/**\n * Cap on `result` / `error` JSONB column size. Adopter `*Task` returns are\n * written verbatim — a buggy or malicious adopter handing back a 1GB\n * result would OOM the Node process before pg complains. 4MB matches the\n * default Postgres `toast` row threshold and gives plenty of headroom for\n * legitimate task payloads.\n *\n * **This cap protects the DB write path only.** Adopter code that\n * serializes `result` / `error` for logs, metrics, or downstream services\n * MUST impose its own size cap — `JSON.stringify(result)` in a logger\n * call is unbounded.\n */\nconst MAX_RESULT_BYTES = 4 * 1024 * 1024;\n\nfunction assertResultSize(json: string, taskId: string): void {\n // `Buffer.byteLength` is utf-8 byte length, which is what Postgres stores.\n if (Buffer.byteLength(json, 'utf8') > MAX_RESULT_BYTES) {\n throw new Error(\n `Task ${taskId}: result/error JSON exceeds ${MAX_RESULT_BYTES} bytes ` +\n `(adopter *Task method returned an oversized payload — investigate ` +\n `whether the body should be persisted via blob storage and referenced).`\n );\n }\n}\n\n/**\n * Wrap `JSON.stringify` with a clearer error when the adopter `*Task`\n * return contains circular references. Default `TypeError: Converting\n * circular structure to JSON` doesn't surface the task id; this version\n * bubbles a registry-write error pointing at the adopter return shape.\n */\nfunction safeStringify(value: unknown, taskId: string): string {\n try {\n return JSON.stringify(value);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Task ${taskId}: adopter *Task return is not JSON-serializable: ${msg}. ` +\n `Strip circular refs / non-plain-data before returning from your *Task method.`\n );\n }\n}\n\n/**\n * Generate the SQL DDL for the decisioning task registry table.\n *\n * Run once at boot (idempotent — `CREATE TABLE IF NOT EXISTS`). Constraint\n * and index names are derived from the table name to avoid collisions when\n * multiple registries share the same database.\n *\n * @example\n * ```typescript\n * import { getDecisioningTaskRegistryMigration } from '@adcp/sdk/server/decisioning';\n * await pool.query(getDecisioningTaskRegistryMigration());\n * await pool.query(getDecisioningTaskRegistryMigration({ tableName: 'my_tasks' }));\n * ```\n */\nexport function getDecisioningTaskRegistryMigration(options?: { tableName?: string }): string {\n const table = options?.tableName ?? DEFAULT_TABLE;\n assertValidIdentifier(table);\n return `\nCREATE TABLE IF NOT EXISTS ${table} (\n task_id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n account_id TEXT NOT NULL,\n owner_scope TEXT,\n status TEXT NOT NULL DEFAULT 'submitted',\n status_message TEXT,\n result JSONB,\n error JSONB,\n progress JSONB,\n has_webhook BOOLEAN NOT NULL DEFAULT FALSE,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n\n CONSTRAINT ${table}_valid_status CHECK (\n -- Framework-written values: 'submitted' (initial), 'working'\n -- (after first updateProgress() call), 'completed' / 'failed'\n -- (terminal). The other 5 spec-defined states ('input-required',\n -- 'canceled', 'rejected', 'auth-required', 'unknown') are reserved\n -- for adopter-emitted transitions via the v6.1\n -- \\`taskRegistry.transition()\\` API; the v6.1 migration will widen\n -- this CHECK.\n status IN ('submitted', 'working', 'completed', 'failed')\n )\n);\n\nCREATE INDEX IF NOT EXISTS idx_${table}_account_id\n ON ${table}(account_id);\n\nCREATE INDEX IF NOT EXISTS idx_${table}_status_created\n ON ${table}(status, created_at);\n\nALTER TABLE ${table}\n ADD COLUMN IF NOT EXISTS owner_scope TEXT;\n\nCREATE INDEX IF NOT EXISTS idx_${table}_owner_account\n ON ${table}(owner_scope, account_id);\n`.trim();\n}\n\ninterface DbTaskRow {\n task_id: string;\n tool: string;\n account_id: string;\n owner_scope: string | null;\n status: TaskStatus;\n status_message: string | null;\n result: unknown;\n error: AdcpStructuredError | null;\n progress: TaskHandoffProgress | null;\n has_webhook: boolean;\n created_at: Date;\n updated_at: Date;\n}\n\nfunction rowToRecord<TResult>(row: DbTaskRow): TaskRecord<TResult> {\n return {\n taskId: row.task_id,\n tool: row.tool,\n accountId: row.account_id,\n ...(row.owner_scope ? { ownerScope: row.owner_scope } : {}),\n status: row.status,\n ...(row.status_message !== null && { statusMessage: row.status_message }),\n ...(row.result !== null && row.result !== undefined && { result: row.result as TResult }),\n ...(row.error !== null && row.error !== undefined && { error: row.error }),\n ...(row.progress !== null && row.progress !== undefined && { progress: row.progress }),\n ...(row.has_webhook && { hasWebhook: true }),\n createdAt: row.created_at.toISOString(),\n updatedAt: row.updated_at.toISOString(),\n };\n}\n\n/**\n * Build a Postgres-backed `TaskRegistry`.\n *\n * Idempotency: `complete()` and `fail()` are no-ops on already-terminal\n * tasks, matching `createInMemoryTaskRegistry()`. The terminal-state guard\n * is enforced via SQL `WHERE status = 'submitted'` predicates so concurrent\n * webhook deliveries can't race to overwrite each other.\n *\n * **Multi-tenant deployments — accountId namespacing.** When sharing a\n * single Postgres registry across tenants in a `TenantRegistry`\n * deployment (one table for all tenants), prefix `account_id` per-tenant\n * to prevent cross-tenant collisions. If tenant A and tenant B both\n * resolve a buyer to literal `account_id: 'acme'`, their tasks land in\n * the same row keyspace and `tasks_get` can't distinguish ownership\n * by `account_id` alone (the tenant boundary upstream IS protected by\n * `accounts.resolve(ref, ctx)` returning each tenant's own Account, but\n * the registry sees the same `acme` string in both rows). Recommended\n * pattern: adopters' `accounts.resolve` returns\n * `id: \\`tenant_${tenantId}_${accountId}\\`` so the table-level keys\n * stay distinct. Alternative: separate `tableName` per tenant, one\n * `createPostgresTaskRegistry({ pool, tableName })` per `TenantRegistry`\n * tenant — heavier ops, stronger isolation.\n */\nexport function createPostgresTaskRegistry(opts: CreatePostgresTaskRegistryOptions): TaskRegistry {\n const table = opts.tableName ?? DEFAULT_TABLE;\n assertValidIdentifier(table);\n const pool = opts.pool;\n\n // Process-local background tracking — see file header note. Promises\n // can't be persisted; cross-instance HITL completion happens via\n // webhook → explicit complete()/fail(), not via awaitTask.\n const backgrounds = new Map<string, Promise<void>>();\n\n return {\n async create(createOpts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }> {\n const taskId = createOpts.overrideTaskId ?? `task_${randomUUID()}`;\n const result = await pool.query(\n `INSERT INTO ${table} (task_id, tool, account_id, owner_scope, status, has_webhook) VALUES ($1, $2, $3, $4, 'submitted', $5) ON CONFLICT (task_id) DO NOTHING`,\n [\n taskId,\n createOpts.tool,\n createOpts.accountId,\n createOpts.ownerScope ?? `account:${createOpts.accountId}`,\n createOpts.hasWebhook === true,\n ]\n );\n if ((result.rowCount ?? 0) === 0) {\n throw new Error(`task_id already registered: ${taskId}`);\n }\n return { taskId };\n },\n\n async getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null> {\n const { rows } = await pool.query(\n `SELECT task_id, tool, account_id, owner_scope, status, status_message, result, error, progress, has_webhook, created_at, updated_at\n FROM ${table} WHERE task_id = $1`,\n [taskId]\n );\n if (rows.length === 0) return null;\n return rowToRecord<TResult>(rows[0] as unknown as DbTaskRow);\n },\n\n async list(listOpts: { accountId: string; ownerScope?: string }): Promise<{ tasks: TaskRecord[] }> {\n if (listOpts.ownerScope === undefined) return { tasks: [] };\n const { rows } = await pool.query(\n `SELECT task_id, tool, account_id, owner_scope, status, status_message, result, error, progress, has_webhook, created_at, updated_at\n FROM ${table}\n WHERE account_id = $1 AND (owner_scope = $2 OR (owner_scope IS NULL AND $2 = $3))\n ORDER BY created_at DESC, task_id DESC`,\n [listOpts.accountId, listOpts.ownerScope, `account:${listOpts.accountId}`]\n );\n return { tasks: rows.map(row => rowToRecord(row as unknown as DbTaskRow)) };\n },\n\n async complete<TResult>(taskId: string, result: TResult): Promise<void> {\n const json = safeStringify(result, taskId);\n assertResultSize(json, taskId);\n await pool.query(\n `UPDATE ${table}\n SET status = 'completed', result = $2::jsonb, updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json]\n );\n },\n\n async fail(taskId: string, error: AdcpStructuredError): Promise<void> {\n const json = safeStringify(error, taskId);\n assertResultSize(json, taskId);\n await pool.query(\n `UPDATE ${table}\n SET status = 'failed', error = $2::jsonb, status_message = $3, updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json, error.message]\n );\n },\n\n async updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void> {\n const json = safeStringify(progress, taskId);\n await pool.query(\n `UPDATE ${table}\n SET progress = $2::jsonb,\n status = CASE WHEN status = 'submitted' THEN 'working' ELSE status END,\n updated_at = NOW()\n WHERE task_id = $1 AND status NOT IN ('completed', 'failed')`,\n [taskId, json]\n );\n },\n\n _registerBackground(taskId: string, completion: Promise<void>): void {\n const composed: Promise<void> = completion.then(\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n },\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n }\n );\n backgrounds.set(taskId, composed);\n },\n\n async awaitTask(taskId: string): Promise<void> {\n const pending = backgrounds.get(taskId);\n if (pending) await pending;\n },\n } satisfies TaskRegistry;\n}\n"],"mappings":"AA+CA,SAAS,kBAAkB;AA6B3B,MAAM,gBAAgB;AAGtB,MAAM,mBAAmB;AAEzB,SAAS,sBAAsB,MAAoB;AACjD,MAAI,CAAC,iBAAiB,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI;AAAA,MACR,uBAAuB,IAAI;AAAA,IAE7B;AAAA,EACF;AACF;AAcA,MAAM,mBAAmB,IAAI,OAAO;AAEpC,SAAS,iBAAiB,MAAc,QAAsB;AAE5D,MAAI,OAAO,WAAW,MAAM,MAAM,IAAI,kBAAkB;AACtD,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,+BAA+B,gBAAgB;AAAA,IAG/D;AAAA,EACF;AACF;AAQA,SAAS,cAAc,OAAgB,QAAwB;AAC7D,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAM,IAAI;AAAA,MACR,QAAQ,MAAM,oDAAoD,GAAG;AAAA,IAEvE;AAAA,EACF;AACF;AAgBO,SAAS,oCAAoC,SAA0C;AAC5F,QAAM,QAAQ,SAAS,aAAa;AACpC,wBAAsB,KAAK;AAC3B,SAAO;AAAA,6BACoB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAcnB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAYa,KAAK;AAAA,OAC/B,KAAK;AAAA;AAAA,iCAEqB,KAAK;AAAA,OAC/B,KAAK;AAAA;AAAA,cAEE,KAAK;AAAA;AAAA;AAAA,iCAGc,KAAK;AAAA,OAC/B,KAAK;AAAA,EACV,KAAK;AACP;AAiBA,SAAS,YAAqB,KAAqC;AACjE,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,WAAW,IAAI;AAAA,IACf,GAAI,IAAI,cAAc,EAAE,YAAY,IAAI,YAAY,IAAI,CAAC;AAAA,IACzD,QAAQ,IAAI;AAAA,IACZ,GAAI,IAAI,mBAAmB,QAAQ,EAAE,eAAe,IAAI,eAAe;AAAA,IACvE,GAAI,IAAI,WAAW,QAAQ,IAAI,WAAW,UAAa,EAAE,QAAQ,IAAI,OAAkB;AAAA,IACvF,GAAI,IAAI,UAAU,QAAQ,IAAI,UAAU,UAAa,EAAE,OAAO,IAAI,MAAM;AAAA,IACxE,GAAI,IAAI,aAAa,QAAQ,IAAI,aAAa,UAAa,EAAE,UAAU,IAAI,SAAS;AAAA,IACpF,GAAI,IAAI,eAAe,EAAE,YAAY,KAAK;AAAA,IAC1C,WAAW,IAAI,WAAW,YAAY;AAAA,IACtC,WAAW,IAAI,WAAW,YAAY;AAAA,EACxC;AACF;AAyBO,SAAS,2BAA2B,MAAuD;AAChG,QAAM,QAAQ,KAAK,aAAa;AAChC,wBAAsB,KAAK;AAC3B,QAAM,OAAO,KAAK;AAKlB,QAAM,cAAc,oBAAI,IAA2B;AAEnD,SAAO;AAAA,IACL,MAAM,OAAO,YAMmB;AAC9B,YAAM,SAAS,WAAW,kBAAkB,QAAQ,WAAW,CAAC;AAChE,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB,eAAe,KAAK;AAAA,QACpB;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW,cAAc,WAAW,WAAW,SAAS;AAAA,UACxD,WAAW,eAAe;AAAA,QAC5B;AAAA,MACF;AACA,WAAK,OAAO,YAAY,OAAO,GAAG;AAChC,cAAM,IAAI,MAAM,+BAA+B,MAAM,EAAE;AAAA,MACzD;AACA,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,MAAM,QAA2B,QAAqD;AACpF,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B;AAAA,gBACQ,KAAK;AAAA,QACb,CAAC,MAAM;AAAA,MACT;AACA,UAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,aAAO,YAAqB,KAAK,CAAC,CAAyB;AAAA,IAC7D;AAAA,IAEA,MAAM,KAAK,UAAwF;AACjG,UAAI,SAAS,eAAe,OAAW,QAAO,EAAE,OAAO,CAAC,EAAE;AAC1D,YAAM,EAAE,KAAK,IAAI,MAAM,KAAK;AAAA,QAC1B;AAAA,gBACQ,KAAK;AAAA;AAAA;AAAA,QAGb,CAAC,SAAS,WAAW,SAAS,YAAY,WAAW,SAAS,SAAS,EAAE;AAAA,MAC3E;AACA,aAAO,EAAE,OAAO,KAAK,IAAI,SAAO,YAAY,GAA2B,CAAC,EAAE;AAAA,IAC5E;AAAA,IAEA,MAAM,SAAkB,QAAgB,QAAgC;AACtE,YAAM,OAAO,cAAc,QAAQ,MAAM;AACzC,uBAAiB,MAAM,MAAM;AAC7B,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA,QAGf,CAAC,QAAQ,IAAI;AAAA,MACf;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAgB,OAA2C;AACpE,YAAM,OAAO,cAAc,OAAO,MAAM;AACxC,uBAAiB,MAAM,MAAM;AAC7B,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA,QAGf,CAAC,QAAQ,MAAM,MAAM,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,eAAe,QAAgB,UAA8C;AACjF,YAAM,OAAO,cAAc,UAAU,MAAM;AAC3C,YAAM,KAAK;AAAA,QACT,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,QAKf,CAAC,QAAQ,IAAI;AAAA,MACf;AAAA,IACF;AAAA,IAEA,oBAAoB,QAAgB,YAAiC;AACnE,YAAM,WAA0B,WAAW;AAAA,QACzC,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,QACA,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,MACF;AACA,kBAAY,IAAI,QAAQ,QAAQ;AAAA,IAClC;AAAA,IAEA,MAAM,UAAU,QAA+B;AAC7C,YAAM,UAAU,YAAY,IAAI,MAAM;AACtC,UAAI,QAAS,OAAM;AAAA,IACrB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
const TOOL_PROTOCOL_MAP = {
|
|
8
2
|
// sponsored-intelligence
|
|
9
3
|
si_get_offering: "sponsored-intelligence",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/protocol-for-tool.ts"],"sourcesContent":["/**\n * Tool-name → AdCP protocol category mapping.\n *\n * Goes on the webhook payload's `protocol` field (per `enums/adcp-protocol.json`)\n * and on the `tasks_get` lifecycle response so receivers can route to the\n * right pipeline before parsing the task body.\n *\n * The map is exported as a plain `Record<string, AdcpProtocol>` so adopters\n * with framework-extension code paths can introspect it (e.g., to build\n * per-protocol metric emitters).\n *\n * @public\n */\n\nimport type { AdCPProtocol } from '../../../types/core.generated';\n\ntype AdcpProtocol = AdCPProtocol;\n\n/**\n * Tool-name → protocol lookup. Keys are wire tool names (snake_case). Values\n * are the 6 closed-enum protocol categories from `enums/adcp-protocol.json`.\n *\n * Tools not in this map fall through to `'media-buy'` — sales is the\n * largest specialism and the safest default for unknown tools (anything\n * the framework dispatches but isn't catalogued here is most likely a new\n * sales tool added in a downstream release).\n */\nexport const TOOL_PROTOCOL_MAP: Readonly<Record<string, AdcpProtocol>> = {\n // sponsored-intelligence\n si_get_offering: 'sponsored-intelligence',\n si_initiate_session: 'sponsored-intelligence',\n si_send_message: 'sponsored-intelligence',\n si_terminate_session: 'sponsored-intelligence',\n\n // governance\n check_governance: 'governance',\n sync_plans: 'governance',\n report_plan_outcome: 'governance',\n get_plan_audit_logs: 'governance',\n get_media_buy_artifacts: 'governance',\n calibrate_content: 'governance',\n validate_content_delivery: 'governance',\n create_property_list: 'governance',\n update_property_list: 'governance',\n get_property_list: 'governance',\n list_property_lists: 'governance',\n delete_property_list: 'governance',\n create_collection_list: 'governance',\n update_collection_list: 'governance',\n get_collection_list: 'governance',\n list_collection_lists: 'governance',\n delete_collection_list: 'governance',\n create_content_standards: 'governance',\n update_content_standards: 'governance',\n get_content_standards: 'governance',\n\n // signals\n get_signals: 'signals',\n activate_signal: 'signals',\n\n // creative\n build_creative: 'creative',\n preview_creative: 'creative',\n get_creative_delivery: 'creative',\n list_creative_formats: 'creative',\n list_creatives: 'creative',\n sync_creatives: 'creative',\n\n // brand\n get_brand_identity: 'brand',\n search_brands: 'brand',\n get_rights: 'brand',\n acquire_rights: 'brand',\n\n // media-buy (explicit listing — anything not here falls back to media-buy)\n get_products: 'media-buy',\n create_media_buy: 'media-buy',\n update_media_buy: 'media-buy',\n get_media_buy_delivery: 'media-buy',\n sync_event_sources: 'media-buy',\n sync_audiences: 'media-buy',\n sync_catalogs: 'media-buy',\n log_event: 'media-buy',\n sync_accounts: 'media-buy',\n list_accounts: 'media-buy',\n get_account_financials: 'media-buy',\n report_usage: 'media-buy',\n provide_performance_feedback: 'media-buy',\n get_media_buys: 'media-buy',\n};\n\n/**\n * Map a v6 tool name to its AdCP protocol category. Falls back to\n * `'media-buy'` for unknown tools — see `TOOL_PROTOCOL_MAP` JSDoc.\n */\nexport function protocolForTool(tool: string): AdcpProtocol {\n return TOOL_PROTOCOL_MAP[tool] ?? 'media-buy';\n}\n\n/**\n * Tools whose `task_type` value is permitted in the v6.0 webhook payload\n * envelope. Spec `enums/task-type.json` is a closed enum — receivers\n * validate against it. Tools NOT in this set still\n * dispatch fine but the framework MUST NOT emit a webhook with a\n * non-spec `task_type` value (it would be rejected by spec-validating\n * subscribers).\n *\n * Tracking spec issue to widen the enum: filing as `adcontextprotocol/adcp`\n * follow-up. Until that lands the framework gates webhook delivery to\n * spec-listed tools and uses `publishStatusChange` for the rest.\n *\n * @internal\n */\nexport const SPEC_WEBHOOK_TASK_TYPES: ReadonlySet<string> = new Set([\n 'get_products',\n 'create_media_buy',\n 'update_media_buy',\n 'sync_creatives',\n 'activate_signal',\n 'get_signals',\n 'create_property_list',\n 'update_property_list',\n 'get_property_list',\n 'list_property_lists',\n 'delete_property_list',\n 'sync_accounts',\n 'get_account_financials',\n 'get_creative_delivery',\n 'sync_event_sources',\n 'sync_audiences',\n 'sync_catalogs',\n 'log_event',\n 'get_brand_identity',\n 'get_rights',\n 'acquire_rights',\n]);\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/protocol-for-tool.ts"],"sourcesContent":["/**\n * Tool-name → AdCP protocol category mapping.\n *\n * Goes on the webhook payload's `protocol` field (per `enums/adcp-protocol.json`)\n * and on the `tasks_get` lifecycle response so receivers can route to the\n * right pipeline before parsing the task body.\n *\n * The map is exported as a plain `Record<string, AdcpProtocol>` so adopters\n * with framework-extension code paths can introspect it (e.g., to build\n * per-protocol metric emitters).\n *\n * @public\n */\n\nimport type { AdCPProtocol } from '../../../types/core.generated';\n\ntype AdcpProtocol = AdCPProtocol;\n\n/**\n * Tool-name → protocol lookup. Keys are wire tool names (snake_case). Values\n * are the 6 closed-enum protocol categories from `enums/adcp-protocol.json`.\n *\n * Tools not in this map fall through to `'media-buy'` — sales is the\n * largest specialism and the safest default for unknown tools (anything\n * the framework dispatches but isn't catalogued here is most likely a new\n * sales tool added in a downstream release).\n */\nexport const TOOL_PROTOCOL_MAP: Readonly<Record<string, AdcpProtocol>> = {\n // sponsored-intelligence\n si_get_offering: 'sponsored-intelligence',\n si_initiate_session: 'sponsored-intelligence',\n si_send_message: 'sponsored-intelligence',\n si_terminate_session: 'sponsored-intelligence',\n\n // governance\n check_governance: 'governance',\n sync_plans: 'governance',\n report_plan_outcome: 'governance',\n get_plan_audit_logs: 'governance',\n get_media_buy_artifacts: 'governance',\n calibrate_content: 'governance',\n validate_content_delivery: 'governance',\n create_property_list: 'governance',\n update_property_list: 'governance',\n get_property_list: 'governance',\n list_property_lists: 'governance',\n delete_property_list: 'governance',\n create_collection_list: 'governance',\n update_collection_list: 'governance',\n get_collection_list: 'governance',\n list_collection_lists: 'governance',\n delete_collection_list: 'governance',\n create_content_standards: 'governance',\n update_content_standards: 'governance',\n get_content_standards: 'governance',\n\n // signals\n get_signals: 'signals',\n activate_signal: 'signals',\n\n // creative\n build_creative: 'creative',\n preview_creative: 'creative',\n get_creative_delivery: 'creative',\n list_creative_formats: 'creative',\n list_creatives: 'creative',\n sync_creatives: 'creative',\n\n // brand\n get_brand_identity: 'brand',\n search_brands: 'brand',\n get_rights: 'brand',\n acquire_rights: 'brand',\n\n // media-buy (explicit listing — anything not here falls back to media-buy)\n get_products: 'media-buy',\n create_media_buy: 'media-buy',\n update_media_buy: 'media-buy',\n get_media_buy_delivery: 'media-buy',\n sync_event_sources: 'media-buy',\n sync_audiences: 'media-buy',\n sync_catalogs: 'media-buy',\n log_event: 'media-buy',\n sync_accounts: 'media-buy',\n list_accounts: 'media-buy',\n get_account_financials: 'media-buy',\n report_usage: 'media-buy',\n provide_performance_feedback: 'media-buy',\n get_media_buys: 'media-buy',\n};\n\n/**\n * Map a v6 tool name to its AdCP protocol category. Falls back to\n * `'media-buy'` for unknown tools — see `TOOL_PROTOCOL_MAP` JSDoc.\n */\nexport function protocolForTool(tool: string): AdcpProtocol {\n return TOOL_PROTOCOL_MAP[tool] ?? 'media-buy';\n}\n\n/**\n * Tools whose `task_type` value is permitted in the v6.0 webhook payload\n * envelope. Spec `enums/task-type.json` is a closed enum — receivers\n * validate against it. Tools NOT in this set still\n * dispatch fine but the framework MUST NOT emit a webhook with a\n * non-spec `task_type` value (it would be rejected by spec-validating\n * subscribers).\n *\n * Tracking spec issue to widen the enum: filing as `adcontextprotocol/adcp`\n * follow-up. Until that lands the framework gates webhook delivery to\n * spec-listed tools and uses `publishStatusChange` for the rest.\n *\n * @internal\n */\nexport const SPEC_WEBHOOK_TASK_TYPES: ReadonlySet<string> = new Set([\n 'get_products',\n 'create_media_buy',\n 'update_media_buy',\n 'sync_creatives',\n 'activate_signal',\n 'get_signals',\n 'create_property_list',\n 'update_property_list',\n 'get_property_list',\n 'list_property_lists',\n 'delete_property_list',\n 'sync_accounts',\n 'get_account_financials',\n 'get_creative_delivery',\n 'sync_event_sources',\n 'sync_audiences',\n 'sync_catalogs',\n 'log_event',\n 'get_brand_identity',\n 'get_rights',\n 'acquire_rights',\n]);\n"],"mappings":"AA2BO,MAAM,oBAA4D;AAAA;AAAA,EAEvE,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,sBAAsB;AAAA;AAAA,EAGtB,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,mBAAmB;AAAA,EACnB,2BAA2B;AAAA,EAC3B,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,uBAAuB;AAAA;AAAA,EAGvB,aAAa;AAAA,EACb,iBAAiB;AAAA;AAAA,EAGjB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,uBAAuB;AAAA,EACvB,uBAAuB;AAAA,EACvB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,wBAAwB;AAAA,EACxB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,eAAe;AAAA,EACf,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,cAAc;AAAA,EACd,8BAA8B;AAAA,EAC9B,gBAAgB;AAClB;AAMO,SAAS,gBAAgB,MAA4B;AAC1D,SAAO,kBAAkB,IAAI,KAAK;AACpC;AAgBO,MAAM,0BAA+C,oBAAI,IAAI;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { randomUUID } from "node:crypto";
|
|
8
2
|
function createInMemoryTaskRegistry() {
|
|
9
3
|
const tasks = /* @__PURE__ */ new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/task-registry.ts"],"sourcesContent":["/**\n * In-memory task registry for the v6.0 alpha runtime.\n *\n * The framework owns task lifecycle. When an adopter method returns a\n * `TaskHandoff` marker, the framework:\n * 1. Allocates a `taskId` and writes a `submitted` record.\n * 2. Returns the submitted envelope to the buyer immediately.\n * 3. Runs the handoff function in the background.\n * 4. Updates the record on progress (`updateProgress`) and terminal\n * state (`complete` / `fail`) from the method's return/throw.\n *\n * Adopters never call into the registry directly. Wire-level `tasks/get`\n * integration (so buyers can poll the lifecycle) reads via `getTask`;\n * test harnesses use `awaitTask` to flush the background promise\n * deterministically.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AdcpStructuredError, TaskHandoffProgress } from '../async-outcome';\n\n/**\n * AdCP-spec task lifecycle states. Mirrors `enums/task-status.json` —\n * the v6 framework writes `'submitted'` on create, transitions to\n * `'working'` on the first `updateProgress()` call, and terminates at\n * `'completed'` / `'failed'`. The other states (`'input-required'`,\n * `'canceled'`, `'rejected'`, `'auth-required'`, `'unknown'`) are\n * reserved for adopter-emitted transitions via the forthcoming\n * `taskRegistry.transition()` API (v6.1).\n */\nexport type TaskStatus =\n | 'submitted'\n | 'working'\n | 'input-required'\n | 'completed'\n | 'canceled'\n | 'failed'\n | 'rejected'\n | 'auth-required'\n | 'unknown';\n\nexport interface TaskRecord<TResult = unknown, TError extends AdcpStructuredError = AdcpStructuredError> {\n taskId: string;\n /** Tool name that started the task (e.g., 'create_media_buy'). */\n tool: string;\n /** Account that started the task — sessionKey-like for cross-request scoping. */\n accountId: string;\n /** Tenant/principal owner scope used with accountId for list/read isolation. */\n ownerScope?: string;\n /** Current lifecycle state — full AdCP-spec `task-status` enum. */\n status: TaskStatus;\n /** Status message on the final arm (`error.message` on failed). */\n statusMessage?: string;\n /** Terminal result on `completed`. */\n result?: TResult;\n /** Terminal error on `failed`. */\n error?: TError;\n /**\n * Intermediate progress from `TaskHandoffContext.update(...)` calls.\n * Written by the background handoff function; surfaced to buyers polling\n * `tasks_get` via the spec `progress` field.\n */\n progress?: TaskHandoffProgress;\n /**\n * Whether the buyer wired `push_notification_config.url` on the original\n * request. Surfaced to the buyer via `tasks_get`'s spec-defined\n * `has_webhook: boolean` field so they can decide between long-poll vs.\n * single-shot polling.\n */\n hasWebhook?: boolean;\n /** ISO 8601 timestamps. */\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TaskRegistryListOptions {\n accountId: string;\n /**\n * Caller ownership scope derived from buyer agent, credential, session,\n * or the single-principal account fallback. Optional for source\n * compatibility with older custom registries, but buyer-visible protocol\n * task tools pass it whenever they can identify a caller and built-in\n * registries fail closed when it is absent.\n */\n ownerScope?: string;\n}\n\nexport interface TaskRegistryListResult<TResult = unknown> {\n tasks: TaskRecord<TResult>[];\n}\n\n// All read/write methods are async to accommodate storage-backed\n// implementations (`createPostgresTaskRegistry`). The in-memory impl\n// resolves immediately. The framework `await`s every call, so the\n// in-memory case pays one microtask per dispatch — negligible.\nexport interface TaskRegistry {\n /**\n * Allocate a new task record. Returns the `taskId` the framework hands\n * to `platform.xxxTask(taskId, ...)`. Initial status is `submitted`.\n *\n * `hasWebhook: true` when the buyer wired `push_notification_config.url`\n * — surfaced via `tasks_get`'s `has_webhook` field. Defaults to `false`.\n *\n * `overrideTaskId` — when set, the registry uses this exact string as the\n * task id instead of minting a fresh one. Throws if the id is already\n * registered (uniqueness is the caller's responsibility).\n */\n create(opts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }>;\n\n /** Read a task by id. Returns `null` if unknown. */\n getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null>;\n\n /**\n * List tasks owned by a resolved account. Buyer-facing AdCP task\n * reconciliation must use this scoped surface, never the transport-level\n * MCP TaskStore, because MCP task records do not carry AdCP ownership,\n * protocol, or tool metadata.\n *\n * Multi-tenant deployments that share an AdCP account across principals\n * must persist and filter by `ownerScope`. Rows without `ownerScope` are\n * treated as legacy account-scoped rows: built-in registries return them\n * only for the account-fallback owner scope (`account:${accountId}`), not\n * for credential-, agent-, or session-scoped callers.\n */\n list?(opts: TaskRegistryListOptions): Promise<TaskRegistryListResult>;\n\n /**\n * Mark a task `completed` with the method's return value. No-op if the\n * task is already terminal (idempotent).\n */\n complete<TResult>(taskId: string, result: TResult): Promise<void>;\n\n /**\n * Mark a task `failed` with the structured error. No-op if the task is\n * already terminal (idempotent).\n */\n fail(taskId: string, error: AdcpStructuredError): Promise<void>;\n\n /**\n * Record intermediate progress from `TaskHandoffContext.update(...)`.\n * Transitions the task from `'submitted'` → `'working'` on the first\n * call. No-op on already-terminal tasks. The `progress` payload is\n * written to the record and surfaced to buyers polling `tasks_get`.\n */\n updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void>;\n\n /**\n * Register the background completion promise the framework spawned for\n * the `*Task` invocation. Tests await this for deterministic settlement;\n * production callers don't need it.\n *\n * @internal\n */\n _registerBackground(taskId: string, completion: Promise<void>): void;\n\n /**\n * Await any registered background completion for a task. Resolves\n * immediately if no background is registered or it has already settled.\n * Used by test harnesses + `tasks/get` integration.\n */\n awaitTask(taskId: string): Promise<void>;\n\n /**\n * Optional test-harness flush. In-memory registries expose this so\n * `AdcpServer.compliance.reset()` can clear hardcoded overrideTaskId\n * records between repeated storyboard runs. Persistent registries should\n * omit it unless they can safely flush their configured backend.\n */\n clear?(): void | Promise<void>;\n}\n\nexport function createInMemoryTaskRegistry(): TaskRegistry {\n const tasks = new Map<string, TaskRecord<unknown>>();\n const backgrounds = new Map<string, Promise<void>>();\n\n return {\n async create(opts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }> {\n const taskId = opts.overrideTaskId ?? `task_${randomUUID()}`;\n if (tasks.has(taskId)) {\n throw new Error(`task_id already registered: ${taskId}`);\n }\n const now = new Date().toISOString();\n tasks.set(taskId, {\n taskId,\n tool: opts.tool,\n accountId: opts.accountId,\n ownerScope: opts.ownerScope ?? `account:${opts.accountId}`,\n status: 'submitted',\n ...(opts.hasWebhook && { hasWebhook: true }),\n createdAt: now,\n updatedAt: now,\n });\n return { taskId };\n },\n\n async getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null> {\n const record = tasks.get(taskId);\n return (record as TaskRecord<TResult> | undefined) ?? null;\n },\n\n async list(opts: TaskRegistryListOptions): Promise<TaskRegistryListResult> {\n if (opts.ownerScope === undefined) return { tasks: [] };\n return {\n tasks: Array.from(tasks.values()).filter(\n record =>\n record.accountId === opts.accountId &&\n (record.ownerScope === opts.ownerScope ||\n (record.ownerScope === undefined && opts.ownerScope === `account:${opts.accountId}`))\n ),\n };\n },\n\n async complete<TResult>(taskId: string, result: TResult): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n existing.status = 'completed';\n existing.result = result;\n existing.updatedAt = new Date().toISOString();\n },\n\n async fail(taskId: string, error: AdcpStructuredError): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n existing.status = 'failed';\n existing.error = error;\n existing.statusMessage = error.message;\n existing.updatedAt = new Date().toISOString();\n },\n\n async updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n if (existing.status === 'submitted') existing.status = 'working';\n existing.progress = progress;\n existing.updatedAt = new Date().toISOString();\n },\n\n _registerBackground(taskId: string, completion: Promise<void>): void {\n const composed: Promise<void> = completion.then(\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n },\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n }\n );\n backgrounds.set(taskId, composed);\n },\n\n async awaitTask(taskId: string): Promise<void> {\n const pending = backgrounds.get(taskId);\n if (pending) await pending;\n },\n\n clear(): void {\n tasks.clear();\n backgrounds.clear();\n },\n };\n}\n"],"mappings":";;;;;;AAqBA,SAAS,kBAAkB;AA+JpB,SAAS,6BAA2C;AACzD,QAAM,QAAQ,oBAAI,IAAiC;AACnD,QAAM,cAAc,oBAAI,IAA2B;AAEnD,SAAO;AAAA,IACL,MAAM,OAAO,MAMmB;AAC9B,YAAM,SAAS,KAAK,kBAAkB,QAAQ,WAAW,CAAC;AAC1D,UAAI,MAAM,IAAI,MAAM,GAAG;AACrB,cAAM,IAAI,MAAM,+BAA+B,MAAM,EAAE;AAAA,MACzD;AACA,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,IAAI,QAAQ;AAAA,QAChB;AAAA,QACA,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,QAChB,YAAY,KAAK,cAAc,WAAW,KAAK,SAAS;AAAA,QACxD,QAAQ;AAAA,QACR,GAAI,KAAK,cAAc,EAAE,YAAY,KAAK;AAAA,QAC1C,WAAW;AAAA,QACX,WAAW;AAAA,MACb,CAAC;AACD,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,MAAM,QAA2B,QAAqD;AACpF,YAAM,SAAS,MAAM,IAAI,MAAM;AAC/B,aAAQ,UAA8C;AAAA,IACxD;AAAA,IAEA,MAAM,KAAK,MAAgE;AACzE,UAAI,KAAK,eAAe,OAAW,QAAO,EAAE,OAAO,CAAC,EAAE;AACtD,aAAO;AAAA,QACL,OAAO,MAAM,KAAK,MAAM,OAAO,CAAC,EAAE;AAAA,UAChC,YACE,OAAO,cAAc,KAAK,cACzB,OAAO,eAAe,KAAK,cACzB,OAAO,eAAe,UAAa,KAAK,eAAe,WAAW,KAAK,SAAS;AAAA,QACvF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,SAAkB,QAAgB,QAAgC;AACtE,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,eAAS,SAAS;AAClB,eAAS,SAAS;AAClB,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,MAAM,KAAK,QAAgB,OAA2C;AACpE,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,eAAS,SAAS;AAClB,eAAS,QAAQ;AACjB,eAAS,gBAAgB,MAAM;AAC/B,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,MAAM,eAAe,QAAgB,UAA8C;AACjF,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,UAAI,SAAS,WAAW,YAAa,UAAS,SAAS;AACvD,eAAS,WAAW;AACpB,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,oBAAoB,QAAgB,YAAiC;AACnE,YAAM,WAA0B,WAAW;AAAA,QACzC,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,QACA,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,MACF;AACA,kBAAY,IAAI,QAAQ,QAAQ;AAAA,IAClC;AAAA,IAEA,MAAM,UAAU,QAA+B;AAC7C,YAAM,UAAU,YAAY,IAAI,MAAM;AACtC,UAAI,QAAS,OAAM;AAAA,IACrB;AAAA,IAEA,QAAc;AACZ,YAAM,MAAM;AACZ,kBAAY,MAAM;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/task-registry.ts"],"sourcesContent":["/**\n * In-memory task registry for the v6.0 alpha runtime.\n *\n * The framework owns task lifecycle. When an adopter method returns a\n * `TaskHandoff` marker, the framework:\n * 1. Allocates a `taskId` and writes a `submitted` record.\n * 2. Returns the submitted envelope to the buyer immediately.\n * 3. Runs the handoff function in the background.\n * 4. Updates the record on progress (`updateProgress`) and terminal\n * state (`complete` / `fail`) from the method's return/throw.\n *\n * Adopters never call into the registry directly. Wire-level `tasks/get`\n * integration (so buyers can poll the lifecycle) reads via `getTask`;\n * test harnesses use `awaitTask` to flush the background promise\n * deterministically.\n *\n * Status: Preview / 6.0.\n *\n * @public\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AdcpStructuredError, TaskHandoffProgress } from '../async-outcome';\n\n/**\n * AdCP-spec task lifecycle states. Mirrors `enums/task-status.json` —\n * the v6 framework writes `'submitted'` on create, transitions to\n * `'working'` on the first `updateProgress()` call, and terminates at\n * `'completed'` / `'failed'`. The other states (`'input-required'`,\n * `'canceled'`, `'rejected'`, `'auth-required'`, `'unknown'`) are\n * reserved for adopter-emitted transitions via the forthcoming\n * `taskRegistry.transition()` API (v6.1).\n */\nexport type TaskStatus =\n | 'submitted'\n | 'working'\n | 'input-required'\n | 'completed'\n | 'canceled'\n | 'failed'\n | 'rejected'\n | 'auth-required'\n | 'unknown';\n\nexport interface TaskRecord<TResult = unknown, TError extends AdcpStructuredError = AdcpStructuredError> {\n taskId: string;\n /** Tool name that started the task (e.g., 'create_media_buy'). */\n tool: string;\n /** Account that started the task — sessionKey-like for cross-request scoping. */\n accountId: string;\n /** Tenant/principal owner scope used with accountId for list/read isolation. */\n ownerScope?: string;\n /** Current lifecycle state — full AdCP-spec `task-status` enum. */\n status: TaskStatus;\n /** Status message on the final arm (`error.message` on failed). */\n statusMessage?: string;\n /** Terminal result on `completed`. */\n result?: TResult;\n /** Terminal error on `failed`. */\n error?: TError;\n /**\n * Intermediate progress from `TaskHandoffContext.update(...)` calls.\n * Written by the background handoff function; surfaced to buyers polling\n * `tasks_get` via the spec `progress` field.\n */\n progress?: TaskHandoffProgress;\n /**\n * Whether the buyer wired `push_notification_config.url` on the original\n * request. Surfaced to the buyer via `tasks_get`'s spec-defined\n * `has_webhook: boolean` field so they can decide between long-poll vs.\n * single-shot polling.\n */\n hasWebhook?: boolean;\n /** ISO 8601 timestamps. */\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TaskRegistryListOptions {\n accountId: string;\n /**\n * Caller ownership scope derived from buyer agent, credential, session,\n * or the single-principal account fallback. Optional for source\n * compatibility with older custom registries, but buyer-visible protocol\n * task tools pass it whenever they can identify a caller and built-in\n * registries fail closed when it is absent.\n */\n ownerScope?: string;\n}\n\nexport interface TaskRegistryListResult<TResult = unknown> {\n tasks: TaskRecord<TResult>[];\n}\n\n// All read/write methods are async to accommodate storage-backed\n// implementations (`createPostgresTaskRegistry`). The in-memory impl\n// resolves immediately. The framework `await`s every call, so the\n// in-memory case pays one microtask per dispatch — negligible.\nexport interface TaskRegistry {\n /**\n * Allocate a new task record. Returns the `taskId` the framework hands\n * to `platform.xxxTask(taskId, ...)`. Initial status is `submitted`.\n *\n * `hasWebhook: true` when the buyer wired `push_notification_config.url`\n * — surfaced via `tasks_get`'s `has_webhook` field. Defaults to `false`.\n *\n * `overrideTaskId` — when set, the registry uses this exact string as the\n * task id instead of minting a fresh one. Throws if the id is already\n * registered (uniqueness is the caller's responsibility).\n */\n create(opts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }>;\n\n /** Read a task by id. Returns `null` if unknown. */\n getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null>;\n\n /**\n * List tasks owned by a resolved account. Buyer-facing AdCP task\n * reconciliation must use this scoped surface, never the transport-level\n * MCP TaskStore, because MCP task records do not carry AdCP ownership,\n * protocol, or tool metadata.\n *\n * Multi-tenant deployments that share an AdCP account across principals\n * must persist and filter by `ownerScope`. Rows without `ownerScope` are\n * treated as legacy account-scoped rows: built-in registries return them\n * only for the account-fallback owner scope (`account:${accountId}`), not\n * for credential-, agent-, or session-scoped callers.\n */\n list?(opts: TaskRegistryListOptions): Promise<TaskRegistryListResult>;\n\n /**\n * Mark a task `completed` with the method's return value. No-op if the\n * task is already terminal (idempotent).\n */\n complete<TResult>(taskId: string, result: TResult): Promise<void>;\n\n /**\n * Mark a task `failed` with the structured error. No-op if the task is\n * already terminal (idempotent).\n */\n fail(taskId: string, error: AdcpStructuredError): Promise<void>;\n\n /**\n * Record intermediate progress from `TaskHandoffContext.update(...)`.\n * Transitions the task from `'submitted'` → `'working'` on the first\n * call. No-op on already-terminal tasks. The `progress` payload is\n * written to the record and surfaced to buyers polling `tasks_get`.\n */\n updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void>;\n\n /**\n * Register the background completion promise the framework spawned for\n * the `*Task` invocation. Tests await this for deterministic settlement;\n * production callers don't need it.\n *\n * @internal\n */\n _registerBackground(taskId: string, completion: Promise<void>): void;\n\n /**\n * Await any registered background completion for a task. Resolves\n * immediately if no background is registered or it has already settled.\n * Used by test harnesses + `tasks/get` integration.\n */\n awaitTask(taskId: string): Promise<void>;\n\n /**\n * Optional test-harness flush. In-memory registries expose this so\n * `AdcpServer.compliance.reset()` can clear hardcoded overrideTaskId\n * records between repeated storyboard runs. Persistent registries should\n * omit it unless they can safely flush their configured backend.\n */\n clear?(): void | Promise<void>;\n}\n\nexport function createInMemoryTaskRegistry(): TaskRegistry {\n const tasks = new Map<string, TaskRecord<unknown>>();\n const backgrounds = new Map<string, Promise<void>>();\n\n return {\n async create(opts: {\n tool: string;\n accountId: string;\n ownerScope?: string;\n hasWebhook?: boolean;\n overrideTaskId?: string;\n }): Promise<{ taskId: string }> {\n const taskId = opts.overrideTaskId ?? `task_${randomUUID()}`;\n if (tasks.has(taskId)) {\n throw new Error(`task_id already registered: ${taskId}`);\n }\n const now = new Date().toISOString();\n tasks.set(taskId, {\n taskId,\n tool: opts.tool,\n accountId: opts.accountId,\n ownerScope: opts.ownerScope ?? `account:${opts.accountId}`,\n status: 'submitted',\n ...(opts.hasWebhook && { hasWebhook: true }),\n createdAt: now,\n updatedAt: now,\n });\n return { taskId };\n },\n\n async getTask<TResult = unknown>(taskId: string): Promise<TaskRecord<TResult> | null> {\n const record = tasks.get(taskId);\n return (record as TaskRecord<TResult> | undefined) ?? null;\n },\n\n async list(opts: TaskRegistryListOptions): Promise<TaskRegistryListResult> {\n if (opts.ownerScope === undefined) return { tasks: [] };\n return {\n tasks: Array.from(tasks.values()).filter(\n record =>\n record.accountId === opts.accountId &&\n (record.ownerScope === opts.ownerScope ||\n (record.ownerScope === undefined && opts.ownerScope === `account:${opts.accountId}`))\n ),\n };\n },\n\n async complete<TResult>(taskId: string, result: TResult): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n existing.status = 'completed';\n existing.result = result;\n existing.updatedAt = new Date().toISOString();\n },\n\n async fail(taskId: string, error: AdcpStructuredError): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n existing.status = 'failed';\n existing.error = error;\n existing.statusMessage = error.message;\n existing.updatedAt = new Date().toISOString();\n },\n\n async updateProgress(taskId: string, progress: TaskHandoffProgress): Promise<void> {\n const existing = tasks.get(taskId);\n if (!existing) return;\n if (existing.status === 'completed' || existing.status === 'failed') return;\n if (existing.status === 'submitted') existing.status = 'working';\n existing.progress = progress;\n existing.updatedAt = new Date().toISOString();\n },\n\n _registerBackground(taskId: string, completion: Promise<void>): void {\n const composed: Promise<void> = completion.then(\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n },\n () => {\n if (backgrounds.get(taskId) === composed) backgrounds.delete(taskId);\n }\n );\n backgrounds.set(taskId, composed);\n },\n\n async awaitTask(taskId: string): Promise<void> {\n const pending = backgrounds.get(taskId);\n if (pending) await pending;\n },\n\n clear(): void {\n tasks.clear();\n backgrounds.clear();\n },\n };\n}\n"],"mappings":"AAqBA,SAAS,kBAAkB;AA+JpB,SAAS,6BAA2C;AACzD,QAAM,QAAQ,oBAAI,IAAiC;AACnD,QAAM,cAAc,oBAAI,IAA2B;AAEnD,SAAO;AAAA,IACL,MAAM,OAAO,MAMmB;AAC9B,YAAM,SAAS,KAAK,kBAAkB,QAAQ,WAAW,CAAC;AAC1D,UAAI,MAAM,IAAI,MAAM,GAAG;AACrB,cAAM,IAAI,MAAM,+BAA+B,MAAM,EAAE;AAAA,MACzD;AACA,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,IAAI,QAAQ;AAAA,QAChB;AAAA,QACA,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,QAChB,YAAY,KAAK,cAAc,WAAW,KAAK,SAAS;AAAA,QACxD,QAAQ;AAAA,QACR,GAAI,KAAK,cAAc,EAAE,YAAY,KAAK;AAAA,QAC1C,WAAW;AAAA,QACX,WAAW;AAAA,MACb,CAAC;AACD,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,MAAM,QAA2B,QAAqD;AACpF,YAAM,SAAS,MAAM,IAAI,MAAM;AAC/B,aAAQ,UAA8C;AAAA,IACxD;AAAA,IAEA,MAAM,KAAK,MAAgE;AACzE,UAAI,KAAK,eAAe,OAAW,QAAO,EAAE,OAAO,CAAC,EAAE;AACtD,aAAO;AAAA,QACL,OAAO,MAAM,KAAK,MAAM,OAAO,CAAC,EAAE;AAAA,UAChC,YACE,OAAO,cAAc,KAAK,cACzB,OAAO,eAAe,KAAK,cACzB,OAAO,eAAe,UAAa,KAAK,eAAe,WAAW,KAAK,SAAS;AAAA,QACvF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,SAAkB,QAAgB,QAAgC;AACtE,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,eAAS,SAAS;AAClB,eAAS,SAAS;AAClB,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,MAAM,KAAK,QAAgB,OAA2C;AACpE,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,eAAS,SAAS;AAClB,eAAS,QAAQ;AACjB,eAAS,gBAAgB,MAAM;AAC/B,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,MAAM,eAAe,QAAgB,UAA8C;AACjF,YAAM,WAAW,MAAM,IAAI,MAAM;AACjC,UAAI,CAAC,SAAU;AACf,UAAI,SAAS,WAAW,eAAe,SAAS,WAAW,SAAU;AACrE,UAAI,SAAS,WAAW,YAAa,UAAS,SAAS;AACvD,eAAS,WAAW;AACpB,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC9C;AAAA,IAEA,oBAAoB,QAAgB,YAAiC;AACnE,YAAM,WAA0B,WAAW;AAAA,QACzC,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,QACA,MAAM;AACJ,cAAI,YAAY,IAAI,MAAM,MAAM,SAAU,aAAY,OAAO,MAAM;AAAA,QACrE;AAAA,MACF;AACA,kBAAY,IAAI,QAAQ,QAAQ;AAAA,IAClC;AAAA,IAEA,MAAM,UAAU,QAA+B;AAC7C,YAAM,UAAU,YAAY,IAAI,MAAM;AACtC,UAAI,QAAS,OAAM;AAAA,IACrB;AAAA,IAEA,QAAc;AACZ,YAAM,MAAM;AACZ,kBAAY,MAAM;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import {
|
|
8
2
|
_createTaskHandoff
|
|
9
3
|
} from "../async-outcome.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/to-context.ts"],"sourcesContent":["/**\n * Translate the existing `HandlerContext` into the v6 `RequestContext` shape\n * that platform methods receive.\n *\n * The handler-style framework already resolves the account, sets sessionKey,\n * and exposes `store` + `authInfo` + `emitWebhook`. The new context layers\n * `state.*` (sync state reads), `resolve.*` (async framework-mediated\n * resolvers), and `handoffToTask(...)` (the unified hybrid-seller handoff\n * primitive) on top.\n *\n * **Stub status — v6.0 alpha.** `state.*` (workflow-step reads, proposal\n * lookups, governance JWS) and `resolve.*` (property/collection-list +\n * format fetchers) are NOT yet wired. The state readers return empty\n * results; the resolvers throw. Touching them in a platform method will\n * crash the request — the framework hasn't connected them to an underlying\n * store / fetch layer yet.\n *\n * Adopters spiking against the preview surface MUST avoid `ctx.state.*`\n * and `ctx.resolve.*` until the wire-up commits land in rc.1. Use\n * `ctx.account`, `ctx.handoffToTask(...)`, and the structured-error /\n * status-change primitives only.\n *\n * @internal — framework-internal wiring; not adopter surface. The\n * exported helpers (`buildRequestContext`, `buildHandoffContext`) are\n * called from the dispatch seam in `from-platform.ts`. Adopters should\n * never construct a `RequestContext` themselves; the framework supplies\n * one to every specialism method call.\n */\n\nimport type { HandlerContext } from '../../create-adcp-server';\nimport type { Account } from '../account';\nimport type { RequestContext, CtxMetadataAccessor } from '../context';\nimport type { TaskRegistry } from './task-registry';\nimport {\n _createTaskHandoff,\n type TaskHandoffContext,\n type TaskHandoff,\n type TaskHandoffOptions,\n} from '../async-outcome';\nimport type { CtxMetadataStore, ResourceKind, CtxMetadataRef } from '../../ctx-metadata';\n\n/**\n * Build an account-scoped CtxMetadataAccessor for a single request.\n *\n * Account scope comes from `ctx.account.id` — accessor methods don't take\n * an account param. When `account.id` is null/undefined (no-account tools),\n * the accessor methods reject — no-account tools cannot use ctx_metadata\n * (cross-tenant collision risk via missing scope).\n */\nfunction buildCtxMetadataAccessor(store: CtxMetadataStore, accountId: string): CtxMetadataAccessor {\n return {\n get(kind: ResourceKind, id: string) {\n return store.get(accountId, kind, id);\n },\n bulkGet(refs: readonly CtxMetadataRef[]) {\n return store.bulkGet(accountId, refs);\n },\n set(kind: ResourceKind, id: string, value: unknown, ttlSeconds?: number) {\n return store.set(accountId, kind, id, value, ttlSeconds);\n },\n delete(kind: ResourceKind, id: string) {\n return store.delete(accountId, kind, id);\n },\n account(id: string) {\n return store.get(accountId, 'account', id);\n },\n product(id: string) {\n return store.get(accountId, 'product', id);\n },\n mediaBuy(id: string) {\n return store.get(accountId, 'media_buy', id);\n },\n package(id: string) {\n return store.get(accountId, 'package', id);\n },\n creative(id: string) {\n return store.get(accountId, 'creative', id);\n },\n audience(id: string) {\n return store.get(accountId, 'audience', id);\n },\n signal(id: string) {\n return store.get(accountId, 'signal', id);\n },\n };\n}\n\nexport function buildRequestContext<TCtxMeta = Record<string, unknown>>(\n handlerCtx: HandlerContext<Account<TCtxMeta>>,\n ctxMetadataStore?: CtxMetadataStore,\n input?: Readonly<Record<string, unknown>>\n): RequestContext<Account<TCtxMeta>> {\n // `account` may legitimately be undefined for tools whose wire request\n // doesn't carry an `account` field AND whose `resolveAccountFromAuth`\n // returned null (`'explicit'`-mode adopters who don't model the\n // no-account tools, or buyers calling without auth). Adopter handlers\n // for those tools are responsible for either deriving the account\n // themselves (e.g., via `media_buy_id` ownership) or throwing\n // `AdcpError('ACCOUNT_NOT_FOUND')` if account is required.\n //\n // The `RequestContext.account` type is non-optional for ergonomic typing\n // — adopters writing handlers for the 90% case (tools with `account` on\n // the wire) shouldn't have to optional-chain everywhere. Adopters of\n // no-account tools either:\n // 1. Declare `resolution: 'derived'` and return a singleton from\n // `accounts.resolve(undefined)` — `ctx.account` is always set\n // 2. Implement only `'explicit'` and never claim no-account\n // specialisms — the tool is unreachable\n // 3. Read `ctx.account` defensively (`as Account | undefined` cast)\n // and look up by request body when missing\n const account = handlerCtx.account as Account<TCtxMeta>;\n\n const stubResolver = (name: string) => async (): Promise<never> => {\n throw new Error(\n `ctx.resolve.${name}: not yet wired in v6.0 alpha — landing in rc.1. ` +\n `Avoid touching ctx.resolve.* in adopter code until the framework ` +\n `connects this resolver to an underlying fetcher.`\n );\n };\n\n // Bind ctx-metadata accessor when store wired AND account scope present.\n // No-account tools (provide_performance_feedback, list_creative_formats)\n // get `ctx.ctxMetadata = undefined` even when the store is wired — cannot\n // use ctx_metadata without an account boundary (cross-tenant risk).\n const ctxMetadata =\n ctxMetadataStore != null && account != null && (account.id ?? '') !== ''\n ? buildCtxMetadataAccessor(ctxMetadataStore, account.id)\n : undefined;\n\n return {\n account,\n ...(handlerCtx.agent != null && { agent: handlerCtx.agent }),\n ...(input != null && { input }),\n state: {\n findByObject: () => [],\n findProposalById: () => null,\n governanceContext: () => null,\n workflowSteps: () => [],\n },\n resolve: {\n propertyList: stubResolver('propertyList'),\n collectionList: stubResolver('collectionList'),\n creativeFormat: stubResolver('creativeFormat'),\n },\n ctxMetadata,\n handoffToTask<TResult>(\n fn: (taskCtx: TaskHandoffContext) => Promise<TResult>,\n options?: TaskHandoffOptions\n ): TaskHandoff<TResult> {\n if (options?.task_id !== undefined) {\n if (typeof options.task_id !== 'string' || options.task_id.length === 0) {\n throw new Error('handoffToTask options.task_id must be a non-empty string');\n }\n if (options.task_id.length > 128) {\n throw new Error('handoffToTask options.task_id must be ≤ 128 characters');\n }\n }\n return _createTaskHandoff(fn, options);\n },\n };\n}\n\n/**\n * Construct a `TaskHandoffContext` from a registry + framework-issued\n * task id. The framework calls this AFTER detecting a `TaskHandoff`\n * marker on a method's return — the handoff function gets a context\n * carrying the framework-allocated `taskId` plus `update`/`heartbeat`\n * affordances.\n *\n * `update(progress)` writes the progress payload to the task record and\n * transitions status `submitted` → `working`. Buyers polling `tasks_get`\n * see the `progress` object and the `'working'` status — this is the\n * buyer-facing UX signal that distinguishes \"stuck/no news\" from\n * \"step 2/3, awaiting trafficker.\" Errors from the registry write are\n * swallowed so a transient DB hiccup doesn't abort the adopter's handoff\n * function.\n *\n * `heartbeat()` remains a no-op stub (v6.1); it is a liveness / TTL-reset\n * signal for operator infrastructure, not buyer-facing.\n */\nexport function buildHandoffContext(taskRegistry: TaskRegistry, taskId: string): TaskHandoffContext {\n return {\n id: taskId,\n update: async progress => {\n try {\n await taskRegistry.updateProgress(taskId, progress);\n } catch {\n // Swallow — a transient registry write failure must not abort the\n // adopter's background handoff function. The buyer-facing impact is\n // a missed progress event, not a failed task.\n }\n },\n heartbeat: async () => {\n await Promise.resolve();\n },\n };\n}\n"],"mappings":";;;;;;AAiCA;AAAA,EACE;AAAA,OAIK;AAWP,SAAS,yBAAyB,OAAyB,WAAwC;AACjG,SAAO;AAAA,IACL,IAAI,MAAoB,IAAY;AAClC,aAAO,MAAM,IAAI,WAAW,MAAM,EAAE;AAAA,IACtC;AAAA,IACA,QAAQ,MAAiC;AACvC,aAAO,MAAM,QAAQ,WAAW,IAAI;AAAA,IACtC;AAAA,IACA,IAAI,MAAoB,IAAY,OAAgB,YAAqB;AACvE,aAAO,MAAM,IAAI,WAAW,MAAM,IAAI,OAAO,UAAU;AAAA,IACzD;AAAA,IACA,OAAO,MAAoB,IAAY;AACrC,aAAO,MAAM,OAAO,WAAW,MAAM,EAAE;AAAA,IACzC;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,aAAa,EAAE;AAAA,IAC7C;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,YAAY,EAAE;AAAA,IAC5C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,YAAY,EAAE;AAAA,IAC5C;AAAA,IACA,OAAO,IAAY;AACjB,aAAO,MAAM,IAAI,WAAW,UAAU,EAAE;AAAA,IAC1C;AAAA,EACF;AACF;AAEO,SAAS,oBACd,YACA,kBACA,OACmC;AAmBnC,QAAM,UAAU,WAAW;AAE3B,QAAM,eAAe,CAAC,SAAiB,YAA4B;AACjE,UAAM,IAAI;AAAA,MACR,eAAe,IAAI;AAAA,IAGrB;AAAA,EACF;AAMA,QAAM,cACJ,oBAAoB,QAAQ,WAAW,SAAS,QAAQ,MAAM,QAAQ,KAClE,yBAAyB,kBAAkB,QAAQ,EAAE,IACrD;AAEN,SAAO;AAAA,IACL;AAAA,IACA,GAAI,WAAW,SAAS,QAAQ,EAAE,OAAO,WAAW,MAAM;AAAA,IAC1D,GAAI,SAAS,QAAQ,EAAE,MAAM;AAAA,IAC7B,OAAO;AAAA,MACL,cAAc,MAAM,CAAC;AAAA,MACrB,kBAAkB,MAAM;AAAA,MACxB,mBAAmB,MAAM;AAAA,MACzB,eAAe,MAAM,CAAC;AAAA,IACxB;AAAA,IACA,SAAS;AAAA,MACP,cAAc,aAAa,cAAc;AAAA,MACzC,gBAAgB,aAAa,gBAAgB;AAAA,MAC7C,gBAAgB,aAAa,gBAAgB;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,cACE,IACA,SACsB;AACtB,UAAI,SAAS,YAAY,QAAW;AAClC,YAAI,OAAO,QAAQ,YAAY,YAAY,QAAQ,QAAQ,WAAW,GAAG;AACvE,gBAAM,IAAI,MAAM,0DAA0D;AAAA,QAC5E;AACA,YAAI,QAAQ,QAAQ,SAAS,KAAK;AAChC,gBAAM,IAAI,MAAM,6DAAwD;AAAA,QAC1E;AAAA,MACF;AACA,aAAO,mBAAmB,IAAI,OAAO;AAAA,IACvC;AAAA,EACF;AACF;AAoBO,SAAS,oBAAoB,cAA4B,QAAoC;AAClG,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,OAAM,aAAY;AACxB,UAAI;AACF,cAAM,aAAa,eAAe,QAAQ,QAAQ;AAAA,MACpD,QAAQ;AAAA,MAIR;AAAA,IACF;AAAA,IACA,WAAW,YAAY;AACrB,YAAM,QAAQ,QAAQ;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/to-context.ts"],"sourcesContent":["/**\n * Translate the existing `HandlerContext` into the v6 `RequestContext` shape\n * that platform methods receive.\n *\n * The handler-style framework already resolves the account, sets sessionKey,\n * and exposes `store` + `authInfo` + `emitWebhook`. The new context layers\n * `state.*` (sync state reads), `resolve.*` (async framework-mediated\n * resolvers), and `handoffToTask(...)` (the unified hybrid-seller handoff\n * primitive) on top.\n *\n * **Stub status — v6.0 alpha.** `state.*` (workflow-step reads, proposal\n * lookups, governance JWS) and `resolve.*` (property/collection-list +\n * format fetchers) are NOT yet wired. The state readers return empty\n * results; the resolvers throw. Touching them in a platform method will\n * crash the request — the framework hasn't connected them to an underlying\n * store / fetch layer yet.\n *\n * Adopters spiking against the preview surface MUST avoid `ctx.state.*`\n * and `ctx.resolve.*` until the wire-up commits land in rc.1. Use\n * `ctx.account`, `ctx.handoffToTask(...)`, and the structured-error /\n * status-change primitives only.\n *\n * @internal — framework-internal wiring; not adopter surface. The\n * exported helpers (`buildRequestContext`, `buildHandoffContext`) are\n * called from the dispatch seam in `from-platform.ts`. Adopters should\n * never construct a `RequestContext` themselves; the framework supplies\n * one to every specialism method call.\n */\n\nimport type { HandlerContext } from '../../create-adcp-server';\nimport type { Account } from '../account';\nimport type { RequestContext, CtxMetadataAccessor } from '../context';\nimport type { TaskRegistry } from './task-registry';\nimport {\n _createTaskHandoff,\n type TaskHandoffContext,\n type TaskHandoff,\n type TaskHandoffOptions,\n} from '../async-outcome';\nimport type { CtxMetadataStore, ResourceKind, CtxMetadataRef } from '../../ctx-metadata';\n\n/**\n * Build an account-scoped CtxMetadataAccessor for a single request.\n *\n * Account scope comes from `ctx.account.id` — accessor methods don't take\n * an account param. When `account.id` is null/undefined (no-account tools),\n * the accessor methods reject — no-account tools cannot use ctx_metadata\n * (cross-tenant collision risk via missing scope).\n */\nfunction buildCtxMetadataAccessor(store: CtxMetadataStore, accountId: string): CtxMetadataAccessor {\n return {\n get(kind: ResourceKind, id: string) {\n return store.get(accountId, kind, id);\n },\n bulkGet(refs: readonly CtxMetadataRef[]) {\n return store.bulkGet(accountId, refs);\n },\n set(kind: ResourceKind, id: string, value: unknown, ttlSeconds?: number) {\n return store.set(accountId, kind, id, value, ttlSeconds);\n },\n delete(kind: ResourceKind, id: string) {\n return store.delete(accountId, kind, id);\n },\n account(id: string) {\n return store.get(accountId, 'account', id);\n },\n product(id: string) {\n return store.get(accountId, 'product', id);\n },\n mediaBuy(id: string) {\n return store.get(accountId, 'media_buy', id);\n },\n package(id: string) {\n return store.get(accountId, 'package', id);\n },\n creative(id: string) {\n return store.get(accountId, 'creative', id);\n },\n audience(id: string) {\n return store.get(accountId, 'audience', id);\n },\n signal(id: string) {\n return store.get(accountId, 'signal', id);\n },\n };\n}\n\nexport function buildRequestContext<TCtxMeta = Record<string, unknown>>(\n handlerCtx: HandlerContext<Account<TCtxMeta>>,\n ctxMetadataStore?: CtxMetadataStore,\n input?: Readonly<Record<string, unknown>>\n): RequestContext<Account<TCtxMeta>> {\n // `account` may legitimately be undefined for tools whose wire request\n // doesn't carry an `account` field AND whose `resolveAccountFromAuth`\n // returned null (`'explicit'`-mode adopters who don't model the\n // no-account tools, or buyers calling without auth). Adopter handlers\n // for those tools are responsible for either deriving the account\n // themselves (e.g., via `media_buy_id` ownership) or throwing\n // `AdcpError('ACCOUNT_NOT_FOUND')` if account is required.\n //\n // The `RequestContext.account` type is non-optional for ergonomic typing\n // — adopters writing handlers for the 90% case (tools with `account` on\n // the wire) shouldn't have to optional-chain everywhere. Adopters of\n // no-account tools either:\n // 1. Declare `resolution: 'derived'` and return a singleton from\n // `accounts.resolve(undefined)` — `ctx.account` is always set\n // 2. Implement only `'explicit'` and never claim no-account\n // specialisms — the tool is unreachable\n // 3. Read `ctx.account` defensively (`as Account | undefined` cast)\n // and look up by request body when missing\n const account = handlerCtx.account as Account<TCtxMeta>;\n\n const stubResolver = (name: string) => async (): Promise<never> => {\n throw new Error(\n `ctx.resolve.${name}: not yet wired in v6.0 alpha — landing in rc.1. ` +\n `Avoid touching ctx.resolve.* in adopter code until the framework ` +\n `connects this resolver to an underlying fetcher.`\n );\n };\n\n // Bind ctx-metadata accessor when store wired AND account scope present.\n // No-account tools (provide_performance_feedback, list_creative_formats)\n // get `ctx.ctxMetadata = undefined` even when the store is wired — cannot\n // use ctx_metadata without an account boundary (cross-tenant risk).\n const ctxMetadata =\n ctxMetadataStore != null && account != null && (account.id ?? '') !== ''\n ? buildCtxMetadataAccessor(ctxMetadataStore, account.id)\n : undefined;\n\n return {\n account,\n ...(handlerCtx.agent != null && { agent: handlerCtx.agent }),\n ...(input != null && { input }),\n state: {\n findByObject: () => [],\n findProposalById: () => null,\n governanceContext: () => null,\n workflowSteps: () => [],\n },\n resolve: {\n propertyList: stubResolver('propertyList'),\n collectionList: stubResolver('collectionList'),\n creativeFormat: stubResolver('creativeFormat'),\n },\n ctxMetadata,\n handoffToTask<TResult>(\n fn: (taskCtx: TaskHandoffContext) => Promise<TResult>,\n options?: TaskHandoffOptions\n ): TaskHandoff<TResult> {\n if (options?.task_id !== undefined) {\n if (typeof options.task_id !== 'string' || options.task_id.length === 0) {\n throw new Error('handoffToTask options.task_id must be a non-empty string');\n }\n if (options.task_id.length > 128) {\n throw new Error('handoffToTask options.task_id must be ≤ 128 characters');\n }\n }\n return _createTaskHandoff(fn, options);\n },\n };\n}\n\n/**\n * Construct a `TaskHandoffContext` from a registry + framework-issued\n * task id. The framework calls this AFTER detecting a `TaskHandoff`\n * marker on a method's return — the handoff function gets a context\n * carrying the framework-allocated `taskId` plus `update`/`heartbeat`\n * affordances.\n *\n * `update(progress)` writes the progress payload to the task record and\n * transitions status `submitted` → `working`. Buyers polling `tasks_get`\n * see the `progress` object and the `'working'` status — this is the\n * buyer-facing UX signal that distinguishes \"stuck/no news\" from\n * \"step 2/3, awaiting trafficker.\" Errors from the registry write are\n * swallowed so a transient DB hiccup doesn't abort the adopter's handoff\n * function.\n *\n * `heartbeat()` remains a no-op stub (v6.1); it is a liveness / TTL-reset\n * signal for operator infrastructure, not buyer-facing.\n */\nexport function buildHandoffContext(taskRegistry: TaskRegistry, taskId: string): TaskHandoffContext {\n return {\n id: taskId,\n update: async progress => {\n try {\n await taskRegistry.updateProgress(taskId, progress);\n } catch {\n // Swallow — a transient registry write failure must not abort the\n // adopter's background handoff function. The buyer-facing impact is\n // a missed progress event, not a failed task.\n }\n },\n heartbeat: async () => {\n await Promise.resolve();\n },\n };\n}\n"],"mappings":"AAiCA;AAAA,EACE;AAAA,OAIK;AAWP,SAAS,yBAAyB,OAAyB,WAAwC;AACjG,SAAO;AAAA,IACL,IAAI,MAAoB,IAAY;AAClC,aAAO,MAAM,IAAI,WAAW,MAAM,EAAE;AAAA,IACtC;AAAA,IACA,QAAQ,MAAiC;AACvC,aAAO,MAAM,QAAQ,WAAW,IAAI;AAAA,IACtC;AAAA,IACA,IAAI,MAAoB,IAAY,OAAgB,YAAqB;AACvE,aAAO,MAAM,IAAI,WAAW,MAAM,IAAI,OAAO,UAAU;AAAA,IACzD;AAAA,IACA,OAAO,MAAoB,IAAY;AACrC,aAAO,MAAM,OAAO,WAAW,MAAM,EAAE;AAAA,IACzC;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,aAAa,EAAE;AAAA,IAC7C;AAAA,IACA,QAAQ,IAAY;AAClB,aAAO,MAAM,IAAI,WAAW,WAAW,EAAE;AAAA,IAC3C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,YAAY,EAAE;AAAA,IAC5C;AAAA,IACA,SAAS,IAAY;AACnB,aAAO,MAAM,IAAI,WAAW,YAAY,EAAE;AAAA,IAC5C;AAAA,IACA,OAAO,IAAY;AACjB,aAAO,MAAM,IAAI,WAAW,UAAU,EAAE;AAAA,IAC1C;AAAA,EACF;AACF;AAEO,SAAS,oBACd,YACA,kBACA,OACmC;AAmBnC,QAAM,UAAU,WAAW;AAE3B,QAAM,eAAe,CAAC,SAAiB,YAA4B;AACjE,UAAM,IAAI;AAAA,MACR,eAAe,IAAI;AAAA,IAGrB;AAAA,EACF;AAMA,QAAM,cACJ,oBAAoB,QAAQ,WAAW,SAAS,QAAQ,MAAM,QAAQ,KAClE,yBAAyB,kBAAkB,QAAQ,EAAE,IACrD;AAEN,SAAO;AAAA,IACL;AAAA,IACA,GAAI,WAAW,SAAS,QAAQ,EAAE,OAAO,WAAW,MAAM;AAAA,IAC1D,GAAI,SAAS,QAAQ,EAAE,MAAM;AAAA,IAC7B,OAAO;AAAA,MACL,cAAc,MAAM,CAAC;AAAA,MACrB,kBAAkB,MAAM;AAAA,MACxB,mBAAmB,MAAM;AAAA,MACzB,eAAe,MAAM,CAAC;AAAA,IACxB;AAAA,IACA,SAAS;AAAA,MACP,cAAc,aAAa,cAAc;AAAA,MACzC,gBAAgB,aAAa,gBAAgB;AAAA,MAC7C,gBAAgB,aAAa,gBAAgB;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,cACE,IACA,SACsB;AACtB,UAAI,SAAS,YAAY,QAAW;AAClC,YAAI,OAAO,QAAQ,YAAY,YAAY,QAAQ,QAAQ,WAAW,GAAG;AACvE,gBAAM,IAAI,MAAM,0DAA0D;AAAA,QAC5E;AACA,YAAI,QAAQ,QAAQ,SAAS,KAAK;AAChC,gBAAM,IAAI,MAAM,6DAAwD;AAAA,QAC1E;AAAA,MACF;AACA,aAAO,mBAAmB,IAAI,OAAO;AAAA,IACvC;AAAA,EACF;AACF;AAoBO,SAAS,oBAAoB,cAA4B,QAAoC;AAClG,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,OAAM,aAAY;AACxB,UAAI;AACF,cAAM,aAAa,eAAe,QAAQ,QAAQ;AAAA,MACpD,QAAQ;AAAA,MAIR;AAAA,IACF;AAAA,IACA,WAAW,YAAY;AACrB,YAAM,QAAQ,QAAQ;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
function isSalesSpecialism(s) {
|
|
8
2
|
return s.startsWith("sales-");
|
|
9
3
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/validate-platform.ts"],"sourcesContent":["/**\n * Runtime validation that a `DecisioningPlatform` impl matches its\n * `capabilities.specialisms[]` declaration.\n *\n * Compile-time, `RequiredPlatformsFor<S>` enforces this in TypeScript adopter\n * code. Untyped JS callers, downstream packages with relaxed `tsconfig`, and\n * Python-port adopters running this through bindings need a runtime gate.\n *\n * Mirrors the v1.0 specialism × interface mapping in\n * `src/lib/server/decisioning/platform.ts`.\n *\n * @public\n */\n\nimport type { DecisioningPlatform } from '../platform';\nimport type { AdCPSpecialism } from '../../../types/tools.generated';\n\n// Sales specialisms require channels + pricingModels on capabilities because\n// buyers read those fields from get_adcp_capabilities to know what the seller\n// trades in. Signals/governance/creative-only platforms legitimately omit them\n// (hence the fields are optional on DecisioningCapabilities), but a media-buy\n// platform serving an empty or absent channels list is a mis-configured agent.\n// Derived from the `sales-` prefix on `AdCPSpecialism` rather than a hand-\n// maintained allowlist: when preview specialisms (`sales-streaming-tv`,\n// `sales-exchange`, `sales-retail-media`) graduate into the generated enum,\n// they automatically inherit the channels + pricingModels gate. A hand-list\n// would silently let mis-configured streaming/exchange platforms through.\nfunction isSalesSpecialism(s: AdCPSpecialism): boolean {\n return s.startsWith('sales-');\n}\n\nconst SPECIALISM_REQUIREMENTS: Partial<Record<AdCPSpecialism, ReadonlyArray<keyof DecisioningPlatform>>> = {\n // All sales-* specialisms share the SalesPlatform interface. Adopters\n // implement `sales` once; the specialism enum picks which buyer-side\n // storyboard the agent is validated against. Wired here per the AdCP 3.0\n // GA enum; preview specialisms (sales-streaming-tv, sales-exchange,\n // sales-retail-media) get added when they land in `AdCPSpecialism`.\n 'sales-non-guaranteed': ['sales'],\n 'sales-guaranteed': ['sales'],\n 'sales-broadcast-tv': ['sales'],\n 'sales-social': ['sales'],\n 'sales-catalog-driven': ['sales'],\n 'sales-proposal-mode': ['sales'],\n // Creative specialisms share the CreativeXxxPlatform field name; adopters\n // pick the right archetype (template / generative / ad-server) at\n // construction time.\n 'creative-template': ['creative'],\n 'creative-generative': ['creative'],\n 'creative-ad-server': ['creative'],\n 'creative-transformers': ['creative'],\n // Audience sync is a single specialism with a single platform interface.\n 'audience-sync': ['audiences'],\n // Signal specialisms — both share the SignalsPlatform interface.\n // Marketplace = third-party data brokers; owned = first-party providers.\n 'signal-marketplace': ['signals'],\n 'signal-owned': ['signals'],\n // Sponsored Intelligence — brand-side conversational sponsored\n // experiences.\n 'sponsored-intelligence': ['sponsoredIntelligence'],\n // Campaign governance — today's two specialisms share one platform\n // interface; consolidates to `campaign-governance` when adcp#3329 lands.\n 'governance-spend-authority': ['campaignGovernance'],\n 'governance-delivery-monitor': ['campaignGovernance'],\n // Property + collection list publishing.\n 'property-lists': ['propertyLists'],\n 'collection-lists': ['collectionLists'],\n // Content standards — brand-safety / policy compliance enforcement.\n 'content-standards': ['contentStandards'],\n // Brand-rights — identity discovery + licensing for branded inventory.\n // 4 wire tools wire through `brandRights` (`get_brand_identity`,\n // `get_rights`, `acquire_rights`, `update_rights`). `creative_approval`\n // is webhook-only (`reviewCreativeApproval` on the platform interface)\n // and not in `AdcpToolMap`.\n 'brand-rights': ['brandRights'],\n};\n\nexport class PlatformConfigError extends Error {\n readonly name = 'PlatformConfigError' as const;\n constructor(message: string) {\n super(message);\n }\n}\n\n// Note on HITL tools: the v6 unified shape collapses sync/HITL into a\n// single method per tool whose return type is `Success | TaskHandoff<Success>`.\n// Adopters branch in the body and call `ctx.handoffToTask(fn)` to defer\n// to a background task. The framework detects the handoff marker at the\n// dispatch seam — there's no exactly-one validation needed because the\n// shape is the same regardless of which path the adopter takes.\n//\n// This applies to `create_media_buy` and `sync_creatives` today (the 2\n// spec-listed tools whose per-tool response oneOf includes the Submitted\n// arm). When adcontextprotocol/adcp#3392 lands, the same shape extends\n// to `update_media_buy`, `build_creative`, `sync_catalogs`, `get_products`.\n\nexport function validatePlatform(platform: DecisioningPlatform): void {\n const claimed = platform.capabilities?.specialisms ?? [];\n const errors: string[] = [];\n\n // 1. Specialism declarations match required interfaces.\n for (const specialism of claimed) {\n const required = SPECIALISM_REQUIREMENTS[specialism];\n if (!required) continue; // forward-compat for unknown specialisms\n for (const field of required) {\n if (platform[field] == null) {\n errors.push(`capabilities.specialisms claims '${specialism}'; platform.${String(field)} is missing`);\n }\n }\n }\n\n // 2. Media-buy platforms require channels + pricingModels on capabilities.\n // These fields are optional on DecisioningCapabilities so non-media-buy\n // platforms (signals, governance, creative-only) can omit them, but a\n // sales platform that omits them will emit a broken get_adcp_capabilities\n // response that buyers cannot interpret.\n const claimedSales = claimed.filter(isSalesSpecialism);\n if (claimedSales.length > 0) {\n if (platform.capabilities?.channels == null) {\n errors.push(`capabilities.channels is required for media-buy platforms (claimed: ${claimedSales.join(', ')})`);\n }\n if (platform.capabilities?.pricingModels == null) {\n errors.push(\n `capabilities.pricingModels is required for media-buy platforms (claimed: ${claimedSales.join(', ')})`\n );\n }\n }\n\n if (errors.length > 0) {\n throw new PlatformConfigError(`DecisioningPlatform configuration is incomplete:\\n - ${errors.join('\\n - ')}`);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../../src/lib/server/decisioning/runtime/validate-platform.ts"],"sourcesContent":["/**\n * Runtime validation that a `DecisioningPlatform` impl matches its\n * `capabilities.specialisms[]` declaration.\n *\n * Compile-time, `RequiredPlatformsFor<S>` enforces this in TypeScript adopter\n * code. Untyped JS callers, downstream packages with relaxed `tsconfig`, and\n * Python-port adopters running this through bindings need a runtime gate.\n *\n * Mirrors the v1.0 specialism × interface mapping in\n * `src/lib/server/decisioning/platform.ts`.\n *\n * @public\n */\n\nimport type { DecisioningPlatform } from '../platform';\nimport type { AdCPSpecialism } from '../../../types/tools.generated';\n\n// Sales specialisms require channels + pricingModels on capabilities because\n// buyers read those fields from get_adcp_capabilities to know what the seller\n// trades in. Signals/governance/creative-only platforms legitimately omit them\n// (hence the fields are optional on DecisioningCapabilities), but a media-buy\n// platform serving an empty or absent channels list is a mis-configured agent.\n// Derived from the `sales-` prefix on `AdCPSpecialism` rather than a hand-\n// maintained allowlist: when preview specialisms (`sales-streaming-tv`,\n// `sales-exchange`, `sales-retail-media`) graduate into the generated enum,\n// they automatically inherit the channels + pricingModels gate. A hand-list\n// would silently let mis-configured streaming/exchange platforms through.\nfunction isSalesSpecialism(s: AdCPSpecialism): boolean {\n return s.startsWith('sales-');\n}\n\nconst SPECIALISM_REQUIREMENTS: Partial<Record<AdCPSpecialism, ReadonlyArray<keyof DecisioningPlatform>>> = {\n // All sales-* specialisms share the SalesPlatform interface. Adopters\n // implement `sales` once; the specialism enum picks which buyer-side\n // storyboard the agent is validated against. Wired here per the AdCP 3.0\n // GA enum; preview specialisms (sales-streaming-tv, sales-exchange,\n // sales-retail-media) get added when they land in `AdCPSpecialism`.\n 'sales-non-guaranteed': ['sales'],\n 'sales-guaranteed': ['sales'],\n 'sales-broadcast-tv': ['sales'],\n 'sales-social': ['sales'],\n 'sales-catalog-driven': ['sales'],\n 'sales-proposal-mode': ['sales'],\n // Creative specialisms share the CreativeXxxPlatform field name; adopters\n // pick the right archetype (template / generative / ad-server) at\n // construction time.\n 'creative-template': ['creative'],\n 'creative-generative': ['creative'],\n 'creative-ad-server': ['creative'],\n 'creative-transformers': ['creative'],\n // Audience sync is a single specialism with a single platform interface.\n 'audience-sync': ['audiences'],\n // Signal specialisms — both share the SignalsPlatform interface.\n // Marketplace = third-party data brokers; owned = first-party providers.\n 'signal-marketplace': ['signals'],\n 'signal-owned': ['signals'],\n // Sponsored Intelligence — brand-side conversational sponsored\n // experiences.\n 'sponsored-intelligence': ['sponsoredIntelligence'],\n // Campaign governance — today's two specialisms share one platform\n // interface; consolidates to `campaign-governance` when adcp#3329 lands.\n 'governance-spend-authority': ['campaignGovernance'],\n 'governance-delivery-monitor': ['campaignGovernance'],\n // Property + collection list publishing.\n 'property-lists': ['propertyLists'],\n 'collection-lists': ['collectionLists'],\n // Content standards — brand-safety / policy compliance enforcement.\n 'content-standards': ['contentStandards'],\n // Brand-rights — identity discovery + licensing for branded inventory.\n // 4 wire tools wire through `brandRights` (`get_brand_identity`,\n // `get_rights`, `acquire_rights`, `update_rights`). `creative_approval`\n // is webhook-only (`reviewCreativeApproval` on the platform interface)\n // and not in `AdcpToolMap`.\n 'brand-rights': ['brandRights'],\n};\n\nexport class PlatformConfigError extends Error {\n readonly name = 'PlatformConfigError' as const;\n constructor(message: string) {\n super(message);\n }\n}\n\n// Note on HITL tools: the v6 unified shape collapses sync/HITL into a\n// single method per tool whose return type is `Success | TaskHandoff<Success>`.\n// Adopters branch in the body and call `ctx.handoffToTask(fn)` to defer\n// to a background task. The framework detects the handoff marker at the\n// dispatch seam — there's no exactly-one validation needed because the\n// shape is the same regardless of which path the adopter takes.\n//\n// This applies to `create_media_buy` and `sync_creatives` today (the 2\n// spec-listed tools whose per-tool response oneOf includes the Submitted\n// arm). When adcontextprotocol/adcp#3392 lands, the same shape extends\n// to `update_media_buy`, `build_creative`, `sync_catalogs`, `get_products`.\n\nexport function validatePlatform(platform: DecisioningPlatform): void {\n const claimed = platform.capabilities?.specialisms ?? [];\n const errors: string[] = [];\n\n // 1. Specialism declarations match required interfaces.\n for (const specialism of claimed) {\n const required = SPECIALISM_REQUIREMENTS[specialism];\n if (!required) continue; // forward-compat for unknown specialisms\n for (const field of required) {\n if (platform[field] == null) {\n errors.push(`capabilities.specialisms claims '${specialism}'; platform.${String(field)} is missing`);\n }\n }\n }\n\n // 2. Media-buy platforms require channels + pricingModels on capabilities.\n // These fields are optional on DecisioningCapabilities so non-media-buy\n // platforms (signals, governance, creative-only) can omit them, but a\n // sales platform that omits them will emit a broken get_adcp_capabilities\n // response that buyers cannot interpret.\n const claimedSales = claimed.filter(isSalesSpecialism);\n if (claimedSales.length > 0) {\n if (platform.capabilities?.channels == null) {\n errors.push(`capabilities.channels is required for media-buy platforms (claimed: ${claimedSales.join(', ')})`);\n }\n if (platform.capabilities?.pricingModels == null) {\n errors.push(\n `capabilities.pricingModels is required for media-buy platforms (claimed: ${claimedSales.join(', ')})`\n );\n }\n }\n\n if (errors.length > 0) {\n throw new PlatformConfigError(`DecisioningPlatform configuration is incomplete:\\n - ${errors.join('\\n - ')}`);\n }\n}\n"],"mappings":"AA2BA,SAAS,kBAAkB,GAA4B;AACrD,SAAO,EAAE,WAAW,QAAQ;AAC9B;AAEA,MAAM,0BAAqG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzG,wBAAwB,CAAC,OAAO;AAAA,EAChC,oBAAoB,CAAC,OAAO;AAAA,EAC5B,sBAAsB,CAAC,OAAO;AAAA,EAC9B,gBAAgB,CAAC,OAAO;AAAA,EACxB,wBAAwB,CAAC,OAAO;AAAA,EAChC,uBAAuB,CAAC,OAAO;AAAA;AAAA;AAAA;AAAA,EAI/B,qBAAqB,CAAC,UAAU;AAAA,EAChC,uBAAuB,CAAC,UAAU;AAAA,EAClC,sBAAsB,CAAC,UAAU;AAAA,EACjC,yBAAyB,CAAC,UAAU;AAAA;AAAA,EAEpC,iBAAiB,CAAC,WAAW;AAAA;AAAA;AAAA,EAG7B,sBAAsB,CAAC,SAAS;AAAA,EAChC,gBAAgB,CAAC,SAAS;AAAA;AAAA;AAAA,EAG1B,0BAA0B,CAAC,uBAAuB;AAAA;AAAA;AAAA,EAGlD,8BAA8B,CAAC,oBAAoB;AAAA,EACnD,+BAA+B,CAAC,oBAAoB;AAAA;AAAA,EAEpD,kBAAkB,CAAC,eAAe;AAAA,EAClC,oBAAoB,CAAC,iBAAiB;AAAA;AAAA,EAEtC,qBAAqB,CAAC,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxC,gBAAgB,CAAC,aAAa;AAChC;AAEO,MAAM,4BAA4B,MAAM;AAAA,EACpC,OAAO;AAAA,EAChB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AAAA,EACf;AACF;AAcO,SAAS,iBAAiB,UAAqC;AACpE,QAAM,UAAU,SAAS,cAAc,eAAe,CAAC;AACvD,QAAM,SAAmB,CAAC;AAG1B,aAAW,cAAc,SAAS;AAChC,UAAM,WAAW,wBAAwB,UAAU;AACnD,QAAI,CAAC,SAAU;AACf,eAAW,SAAS,UAAU;AAC5B,UAAI,SAAS,KAAK,KAAK,MAAM;AAC3B,eAAO,KAAK,oCAAoC,UAAU,eAAe,OAAO,KAAK,CAAC,aAAa;AAAA,MACrG;AAAA,IACF;AAAA,EACF;AAOA,QAAM,eAAe,QAAQ,OAAO,iBAAiB;AACrD,MAAI,aAAa,SAAS,GAAG;AAC3B,QAAI,SAAS,cAAc,YAAY,MAAM;AAC3C,aAAO,KAAK,uEAAuE,aAAa,KAAK,IAAI,CAAC,GAAG;AAAA,IAC/G;AACA,QAAI,SAAS,cAAc,iBAAiB,MAAM;AAChD,aAAO;AAAA,QACL,4EAA4E,aAAa,KAAK,IAAI,CAAC;AAAA,MACrG;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,IAAI,oBAAoB;AAAA,MAAyD,OAAO,KAAK,QAAQ,CAAC,EAAE;AAAA,EAChH;AACF;","names":[]}
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=audiences.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=brand-rights.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=campaign-governance.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=content-standards.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=creative-ad-server.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=creative.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=lists.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=sales.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=signals.mjs.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
//# sourceMappingURL=sponsored-intelligence.mjs.map
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
import { AdcpError } from "./async-outcome.mjs";
|
|
8
2
|
function resolveStartTime(raw, opts = {}) {
|
|
9
3
|
const asapLead = opts.asapLeadTimeMs ?? 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/server/decisioning/start-time.ts"],"sourcesContent":["/**\n * Resolve a wire `start_time` into a concrete `Date`, with platform-aware\n * ASAP semantics.\n *\n * The wire shape is `string | undefined` where the string is either an\n * ISO 8601 timestamp OR the literal `'asap'`. Every platform method that\n * touches `start_time` has to:\n * 1. Handle the union (and the undefined case)\n * 2. Validate that an ISO timestamp parses + isn't in the past\n * 3. Interpret `'asap'` as a sensible date for THIS platform\n *\n * Step 3 is platform-specific. For programmatic sellers, ASAP means\n * `now()`. For guaranteed/broadcast sellers with a 1-3 day trafficker\n * approval pipeline, ASAP means `now() + approval lead time` because the\n * buy can't physically start before the operator signs off. This helper\n * takes a config object so each adopter injects their own semantics\n * consistently across `createMediaBuy(Task)` and `updateMediaBuy`.\n *\n * @example Programmatic seller (no approval)\n * ```ts\n * const startAt = resolveStartTime(req.start_time, {});\n * // 'asap' → now()\n * // '2026-05-01T00:00:00Z' → that date\n * // undefined → now()\n * ```\n *\n * @example Broadcast seller with 2-day IO sign-off + 1-day default lead\n * ```ts\n * const startAt = resolveStartTime(req.start_time, {\n * asapLeadTimeMs: 2 * 86_400_000,\n * defaultLeadTimeMs: 86_400_000,\n * notBefore: new Date(),\n * });\n * // 'asap' → now() + 2 days\n * // past date → throws AdcpError(INVALID_REQUEST)\n * // undefined → now() + 1 day\n * ```\n *\n * @public\n */\n\nimport { AdcpError } from './async-outcome';\n\nexport interface ResolveStartTimeOptions {\n /**\n * When `start_time` is the literal `'asap'`, return `now() + this`.\n * Models the platform's approval / trafficking pipeline that runs\n * before a buy can actually start. Default `0` (interpret asap as\n * truly now, suitable for programmatic platforms).\n */\n asapLeadTimeMs?: number;\n /**\n * When `start_time` is `undefined`, return `now() + this`. Lets adopters\n * pick whether \"no start_time specified\" means \"asap\" (use the same\n * lead time) or some other default. Defaults to the value of\n * `asapLeadTimeMs`.\n */\n defaultLeadTimeMs?: number;\n /**\n * Reject parsed timestamps strictly before this. Most adopters pass\n * `new Date()` to forbid past start times. Omit to skip the check.\n */\n notBefore?: Date;\n /**\n * Override the field name on the error message when validation throws.\n * Defaults to `'start_time'`. Set to `'patch.start_time'` (or similar)\n * when calling from `updateMediaBuy`.\n */\n fieldName?: string;\n}\n\n/**\n * Normalize the wire `start_time` value into a guaranteed-non-null Date.\n *\n * Throws `AdcpError('INVALID_REQUEST')` when the string isn't a parseable\n * ISO 8601 timestamp OR when the parsed date is before `opts.notBefore`.\n * Returns `now() + lead time` for `'asap'` and `undefined` inputs.\n */\nexport function resolveStartTime(raw: string | undefined, opts: ResolveStartTimeOptions = {}): Date {\n const asapLead = opts.asapLeadTimeMs ?? 0;\n const defaultLead = opts.defaultLeadTimeMs ?? asapLead;\n const fieldName = opts.fieldName ?? 'start_time';\n\n if (raw === undefined) {\n return new Date(Date.now() + defaultLead);\n }\n if (raw === 'asap') {\n return new Date(Date.now() + asapLead);\n }\n\n const parsed = new Date(raw);\n if (isNaN(parsed.getTime())) {\n throw new AdcpError('INVALID_REQUEST', {\n message: `${fieldName} is not a valid ISO 8601 timestamp: '${raw}'`,\n field: fieldName,\n suggestion: \"Use 'asap' or an ISO 8601 timestamp (e.g., '2026-05-01T00:00:00Z')\",\n });\n }\n\n if (opts.notBefore && parsed.getTime() < opts.notBefore.getTime()) {\n throw new AdcpError('INVALID_REQUEST', {\n message: `${fieldName} is in the past: ${parsed.toISOString()} (cutoff ${opts.notBefore.toISOString()})`,\n field: fieldName,\n suggestion: 'Use a future timestamp or `asap`',\n });\n }\n\n return parsed;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/server/decisioning/start-time.ts"],"sourcesContent":["/**\n * Resolve a wire `start_time` into a concrete `Date`, with platform-aware\n * ASAP semantics.\n *\n * The wire shape is `string | undefined` where the string is either an\n * ISO 8601 timestamp OR the literal `'asap'`. Every platform method that\n * touches `start_time` has to:\n * 1. Handle the union (and the undefined case)\n * 2. Validate that an ISO timestamp parses + isn't in the past\n * 3. Interpret `'asap'` as a sensible date for THIS platform\n *\n * Step 3 is platform-specific. For programmatic sellers, ASAP means\n * `now()`. For guaranteed/broadcast sellers with a 1-3 day trafficker\n * approval pipeline, ASAP means `now() + approval lead time` because the\n * buy can't physically start before the operator signs off. This helper\n * takes a config object so each adopter injects their own semantics\n * consistently across `createMediaBuy(Task)` and `updateMediaBuy`.\n *\n * @example Programmatic seller (no approval)\n * ```ts\n * const startAt = resolveStartTime(req.start_time, {});\n * // 'asap' → now()\n * // '2026-05-01T00:00:00Z' → that date\n * // undefined → now()\n * ```\n *\n * @example Broadcast seller with 2-day IO sign-off + 1-day default lead\n * ```ts\n * const startAt = resolveStartTime(req.start_time, {\n * asapLeadTimeMs: 2 * 86_400_000,\n * defaultLeadTimeMs: 86_400_000,\n * notBefore: new Date(),\n * });\n * // 'asap' → now() + 2 days\n * // past date → throws AdcpError(INVALID_REQUEST)\n * // undefined → now() + 1 day\n * ```\n *\n * @public\n */\n\nimport { AdcpError } from './async-outcome';\n\nexport interface ResolveStartTimeOptions {\n /**\n * When `start_time` is the literal `'asap'`, return `now() + this`.\n * Models the platform's approval / trafficking pipeline that runs\n * before a buy can actually start. Default `0` (interpret asap as\n * truly now, suitable for programmatic platforms).\n */\n asapLeadTimeMs?: number;\n /**\n * When `start_time` is `undefined`, return `now() + this`. Lets adopters\n * pick whether \"no start_time specified\" means \"asap\" (use the same\n * lead time) or some other default. Defaults to the value of\n * `asapLeadTimeMs`.\n */\n defaultLeadTimeMs?: number;\n /**\n * Reject parsed timestamps strictly before this. Most adopters pass\n * `new Date()` to forbid past start times. Omit to skip the check.\n */\n notBefore?: Date;\n /**\n * Override the field name on the error message when validation throws.\n * Defaults to `'start_time'`. Set to `'patch.start_time'` (or similar)\n * when calling from `updateMediaBuy`.\n */\n fieldName?: string;\n}\n\n/**\n * Normalize the wire `start_time` value into a guaranteed-non-null Date.\n *\n * Throws `AdcpError('INVALID_REQUEST')` when the string isn't a parseable\n * ISO 8601 timestamp OR when the parsed date is before `opts.notBefore`.\n * Returns `now() + lead time` for `'asap'` and `undefined` inputs.\n */\nexport function resolveStartTime(raw: string | undefined, opts: ResolveStartTimeOptions = {}): Date {\n const asapLead = opts.asapLeadTimeMs ?? 0;\n const defaultLead = opts.defaultLeadTimeMs ?? asapLead;\n const fieldName = opts.fieldName ?? 'start_time';\n\n if (raw === undefined) {\n return new Date(Date.now() + defaultLead);\n }\n if (raw === 'asap') {\n return new Date(Date.now() + asapLead);\n }\n\n const parsed = new Date(raw);\n if (isNaN(parsed.getTime())) {\n throw new AdcpError('INVALID_REQUEST', {\n message: `${fieldName} is not a valid ISO 8601 timestamp: '${raw}'`,\n field: fieldName,\n suggestion: \"Use 'asap' or an ISO 8601 timestamp (e.g., '2026-05-01T00:00:00Z')\",\n });\n }\n\n if (opts.notBefore && parsed.getTime() < opts.notBefore.getTime()) {\n throw new AdcpError('INVALID_REQUEST', {\n message: `${fieldName} is in the past: ${parsed.toISOString()} (cutoff ${opts.notBefore.toISOString()})`,\n field: fieldName,\n suggestion: 'Use a future timestamp or `asap`',\n });\n }\n\n return parsed;\n}\n"],"mappings":"AAyCA,SAAS,iBAAiB;AAqCnB,SAAS,iBAAiB,KAAyB,OAAgC,CAAC,GAAS;AAClG,QAAM,WAAW,KAAK,kBAAkB;AACxC,QAAM,cAAc,KAAK,qBAAqB;AAC9C,QAAM,YAAY,KAAK,aAAa;AAEpC,MAAI,QAAQ,QAAW;AACrB,WAAO,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW;AAAA,EAC1C;AACA,MAAI,QAAQ,QAAQ;AAClB,WAAO,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ;AAAA,EACvC;AAEA,QAAM,SAAS,IAAI,KAAK,GAAG;AAC3B,MAAI,MAAM,OAAO,QAAQ,CAAC,GAAG;AAC3B,UAAM,IAAI,UAAU,mBAAmB;AAAA,MACrC,SAAS,GAAG,SAAS,wCAAwC,GAAG;AAAA,MAChE,OAAO;AAAA,MACP,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,MAAI,KAAK,aAAa,OAAO,QAAQ,IAAI,KAAK,UAAU,QAAQ,GAAG;AACjE,UAAM,IAAI,UAAU,mBAAmB;AAAA,MACrC,SAAS,GAAG,SAAS,oBAAoB,OAAO,YAAY,CAAC,YAAY,KAAK,UAAU,YAAY,CAAC;AAAA,MACrG,OAAO;AAAA,MACP,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
const DEFAULT_RECENT_LIMIT = 1e3;
|
|
8
2
|
function createInMemoryStatusChangeBus(opts) {
|
|
9
3
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/server/decisioning/status-changes.ts"],"sourcesContent":["/**\n * Status-change event bus for the v6.0 decisioning runtime.\n *\n * Adopters call `publishStatusChange(...)` from anywhere — webhook handler,\n * cron, in-process worker, the body of a `*Task` method — to push lifecycle\n * updates on a resource the framework knows about. The framework records\n * the change against the resource and projects it to subscribed buyers via\n * the MCP Resources subscription extension (`notifications/resources/updated`)\n * and the equivalent A2A DataPart-typed message contract.\n *\n * Ten resource types are wired in v6.0 (matches AdCP 3.0 lifecycle\n * channels):\n *\n * - `media_buy` — pending → active → completed; paused, canceled\n * - `creative` — pending_review → approved/rejected\n * - `audience` — matching → matched → activating → active\n * - `signal` — pending → activated → expired\n * - `proposal` — issued → accepted/expired/withdrawn\n * - `plan` — draft → submitted → approved/rejected\n * - `rights_grant` — pending → granted/denied/expired\n * - `delivery_report`— staging → published (manual report-runs)\n * - `property_list` — list-changed events (cache invalidation, fetch_token revoke)\n * - `collection_list`— list-changed events (cache invalidation, fetch_token revoke)\n *\n * The bus is module-level so adopters can call `publishStatusChange(...)`\n * without holding a reference to the server. The framework wires the bus\n * into the server's resource registry at construction; in tests, the\n * registry can be swapped via `setStatusChangeBus(...)`.\n *\n * Status: Preview / 6.0. Wire-level MCP Resources subscription handlers\n * and the A2A backport land in a subsequent commit; this file ships the\n * adopter-facing primitive and an in-memory subscriber model the runtime\n * can consume.\n *\n * @public\n */\n\n/**\n * Resource categories whose lifecycle changes can be published on the\n * status-change bus and projected to subscribed buyers.\n *\n * **Spec status (v6.0):** The AdCP spec doesn't yet ship a closed enum\n * for `resource_type`. The values below are the v6 SDK's working set —\n * the resource categories adopters publish lifecycle events against\n * today. They become wire-visible via the URI scheme\n * `adcp://{account_id}/{resource_type}/{resource_id}` projected to MCP\n * Resources subscriptions.\n *\n * Filed upstream as adcontextprotocol/adcp#3412 proposing a normative\n * `enums/status-change-resource-type.json`. When the spec lands the\n * enum, this type becomes a `$ref` to the generated schema. Until then\n * adopters subscribing across multiple AdCP agents may see drift; the\n * SDK's set is the working canonical until the spec consolidates.\n *\n * Adopters publishing custom resource types not in this list should\n * prefix with `x-` (e.g., `'x-pcim_session'`) to reduce collision risk\n * with the eventual normative enum. The framework accepts any string\n * (the type is widened with `(string & {})` for forward-compat) but\n * only the values listed here have stable cross-SDK semantics.\n */\nexport type StatusChangeResourceType =\n | 'media_buy'\n | 'creative'\n | 'audience'\n | 'signal'\n | 'proposal'\n | 'plan'\n | 'rights_grant'\n | 'delivery_report'\n | 'property_list'\n | 'collection_list'\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {});\n\n/**\n * A single status-change event.\n *\n * `account_id` scopes the event to a tenant; subscribers receive only\n * events for their resolved account. `resource_uri` follows the MCP\n * Resources URI scheme: `adcp://{account_id}/{resource_type}/{resource_id}`.\n */\nexport interface StatusChange<TPayload = unknown> {\n account_id: string;\n resource_type: StatusChangeResourceType;\n resource_id: string;\n /** Canonical MCP Resources URI for this resource. */\n resource_uri: string;\n /** ISO 8601 timestamp the change was observed. */\n at: string;\n /**\n * Resource-type-specific change payload. Shape is the wire fragment the\n * subscribed buyer will see — e.g., for `media_buy` it's the AdCP\n * `media_buy_status_changes` message body.\n */\n payload: TPayload;\n /**\n * Correlation id linking this change back to the buyer request that\n * caused it. Useful for \"show me everything that happened from this\n * `create_media_buy` call\" observability across HITL flows. Adopters\n * pass through `ctx.task.id` (for `*Task`-driven changes) or any\n * stable request identifier they generate at dispatch time.\n *\n * Optional — many status changes originate from cron / webhook /\n * upstream-platform events that have no buyer-request correlation.\n */\n caused_by_request_id?: string;\n /**\n * Status the resource was transitioning FROM. Lets subscribers assert\n * legal transitions (`from: 'matching' → to: 'active'` is fine;\n * `from: 'failed' → to: 'matching'` is a state-machine bug). The\n * framework doesn't validate transitions in v6.0 (no per-resource\n * state machine yet); the field is captured and projected to the\n * wire so downstream consumers can.\n */\n previous_status?: string;\n}\n\nexport interface PublishStatusChangeOpts<TPayload = unknown> {\n account_id: string;\n resource_type: StatusChangeResourceType;\n resource_id: string;\n payload: TPayload;\n /** Override the timestamp (defaults to now). Useful for replay/backfill. */\n at?: string;\n /**\n * Correlation id linking this change to the buyer request that caused\n * it. Inside `*Task` method bodies, pass `ctx.task.id` to thread the\n * task lifecycle. Outside HITL flows, pass any stable request id you\n * derive at dispatch time. Optional.\n */\n caused_by_request_id?: string;\n /** Status the resource was transitioning FROM. Optional. */\n previous_status?: string;\n}\n\nexport type StatusChangeListener = (event: StatusChange) => void | Promise<void>;\n\nexport interface StatusChangeBus {\n publish<TPayload>(opts: PublishStatusChangeOpts<TPayload>): void;\n /**\n * Subscribe a listener. Returns an unsubscribe function. Listeners are\n * fire-and-forget; rejected promises are caught and logged so one bad\n * subscriber doesn't break delivery to others.\n */\n subscribe(listener: StatusChangeListener): () => void;\n /** Snapshot the most-recent N events (in-memory cache for `tasks/get` + replay). */\n recent(limit?: number): readonly StatusChange[];\n}\n\nconst DEFAULT_RECENT_LIMIT = 1000;\n\nexport function createInMemoryStatusChangeBus(opts?: { recentLimit?: number }): StatusChangeBus {\n const listeners = new Set<StatusChangeListener>();\n const recent: StatusChange[] = [];\n const recentLimit = opts?.recentLimit ?? DEFAULT_RECENT_LIMIT;\n\n return {\n publish<TPayload>(eventOpts: PublishStatusChangeOpts<TPayload>): void {\n const event: StatusChange<TPayload> = {\n account_id: eventOpts.account_id,\n resource_type: eventOpts.resource_type,\n resource_id: eventOpts.resource_id,\n resource_uri: `adcp://${eventOpts.account_id}/${eventOpts.resource_type}/${eventOpts.resource_id}`,\n at: eventOpts.at ?? new Date().toISOString(),\n payload: eventOpts.payload,\n ...(eventOpts.caused_by_request_id !== undefined && { caused_by_request_id: eventOpts.caused_by_request_id }),\n ...(eventOpts.previous_status !== undefined && { previous_status: eventOpts.previous_status }),\n };\n recent.push(event as StatusChange);\n if (recent.length > recentLimit) recent.shift();\n\n for (const listener of listeners) {\n try {\n const result = listener(event as StatusChange);\n if (result && typeof (result as Promise<void>).catch === 'function') {\n (result as Promise<void>).catch((err: unknown) => {\n // eslint-disable-next-line no-console\n console.warn('[adcp] status-change listener rejected:', err);\n });\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn('[adcp] status-change listener threw:', err);\n }\n }\n },\n\n subscribe(listener: StatusChangeListener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n recent(limit?: number): readonly StatusChange[] {\n const n = limit ?? recent.length;\n return recent.slice(-n);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Module-level adopter-facing primitive\n// ---------------------------------------------------------------------------\n\nlet activeBus: StatusChangeBus = createInMemoryStatusChangeBus();\n\n/**\n * Push a status change for a resource. Adopters call this from anywhere —\n * webhook handler, cron, in-process worker — to surface lifecycle changes\n * the framework projects to subscribed buyers.\n *\n * ```ts\n * // After GAM webhook reports order activation:\n * publishStatusChange({\n * account_id: account.id,\n * resource_type: 'media_buy',\n * resource_id: gamOrderToBuyId(order),\n * payload: { status: 'active', activated_at: order.startTime },\n * });\n * ```\n *\n * Buyers subscribed via MCP `resources/subscribe` (or the A2A equivalent)\n * receive the change as a `notifications/resources/updated` notification\n * carrying the `payload` as the resource's wire fragment.\n */\nexport function publishStatusChange<TPayload>(opts: PublishStatusChangeOpts<TPayload>): void {\n activeBus.publish(opts);\n}\n\n/**\n * Replace the active bus. The framework calls this at server construction\n * to wire its own bus implementation; tests can call it to swap in a fake.\n *\n * Returns the previous bus so the caller can restore it (e.g., in a test\n * teardown).\n */\nexport function setStatusChangeBus(bus: StatusChangeBus): StatusChangeBus {\n const prev = activeBus;\n activeBus = bus;\n return prev;\n}\n\n/** Read the active bus (for the framework to wire subscribers). */\nexport function getStatusChangeBus(): StatusChangeBus {\n return activeBus;\n}\n"],"mappings":";;;;;;AAqJA,MAAM,uBAAuB;AAEtB,SAAS,8BAA8B,MAAkD;AAC9F,QAAM,YAAY,oBAAI,IAA0B;AAChD,QAAM,SAAyB,CAAC;AAChC,QAAM,cAAc,MAAM,eAAe;AAEzC,SAAO;AAAA,IACL,QAAkB,WAAoD;AACpE,YAAM,QAAgC;AAAA,QACpC,YAAY,UAAU;AAAA,QACtB,eAAe,UAAU;AAAA,QACzB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU,UAAU,UAAU,IAAI,UAAU,aAAa,IAAI,UAAU,WAAW;AAAA,QAChG,IAAI,UAAU,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC3C,SAAS,UAAU;AAAA,QACnB,GAAI,UAAU,yBAAyB,UAAa,EAAE,sBAAsB,UAAU,qBAAqB;AAAA,QAC3G,GAAI,UAAU,oBAAoB,UAAa,EAAE,iBAAiB,UAAU,gBAAgB;AAAA,MAC9F;AACA,aAAO,KAAK,KAAqB;AACjC,UAAI,OAAO,SAAS,YAAa,QAAO,MAAM;AAE9C,iBAAW,YAAY,WAAW;AAChC,YAAI;AACF,gBAAM,SAAS,SAAS,KAAqB;AAC7C,cAAI,UAAU,OAAQ,OAAyB,UAAU,YAAY;AACnE,YAAC,OAAyB,MAAM,CAAC,QAAiB;AAEhD,sBAAQ,KAAK,2CAA2C,GAAG;AAAA,YAC7D,CAAC;AAAA,UACH;AAAA,QACF,SAAS,KAAK;AAEZ,kBAAQ,KAAK,wCAAwC,GAAG;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,UAA4C;AACpD,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,IAEA,OAAO,OAAyC;AAC9C,YAAM,IAAI,SAAS,OAAO;AAC1B,aAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACxB;AAAA,EACF;AACF;AAMA,IAAI,YAA6B,8BAA8B;AAqBxD,SAAS,oBAA8B,MAA+C;AAC3F,YAAU,QAAQ,IAAI;AACxB;AASO,SAAS,mBAAmB,KAAuC;AACxE,QAAM,OAAO;AACb,cAAY;AACZ,SAAO;AACT;AAGO,SAAS,qBAAsC;AACpD,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/server/decisioning/status-changes.ts"],"sourcesContent":["/**\n * Status-change event bus for the v6.0 decisioning runtime.\n *\n * Adopters call `publishStatusChange(...)` from anywhere — webhook handler,\n * cron, in-process worker, the body of a `*Task` method — to push lifecycle\n * updates on a resource the framework knows about. The framework records\n * the change against the resource and projects it to subscribed buyers via\n * the MCP Resources subscription extension (`notifications/resources/updated`)\n * and the equivalent A2A DataPart-typed message contract.\n *\n * Ten resource types are wired in v6.0 (matches AdCP 3.0 lifecycle\n * channels):\n *\n * - `media_buy` — pending → active → completed; paused, canceled\n * - `creative` — pending_review → approved/rejected\n * - `audience` — matching → matched → activating → active\n * - `signal` — pending → activated → expired\n * - `proposal` — issued → accepted/expired/withdrawn\n * - `plan` — draft → submitted → approved/rejected\n * - `rights_grant` — pending → granted/denied/expired\n * - `delivery_report`— staging → published (manual report-runs)\n * - `property_list` — list-changed events (cache invalidation, fetch_token revoke)\n * - `collection_list`— list-changed events (cache invalidation, fetch_token revoke)\n *\n * The bus is module-level so adopters can call `publishStatusChange(...)`\n * without holding a reference to the server. The framework wires the bus\n * into the server's resource registry at construction; in tests, the\n * registry can be swapped via `setStatusChangeBus(...)`.\n *\n * Status: Preview / 6.0. Wire-level MCP Resources subscription handlers\n * and the A2A backport land in a subsequent commit; this file ships the\n * adopter-facing primitive and an in-memory subscriber model the runtime\n * can consume.\n *\n * @public\n */\n\n/**\n * Resource categories whose lifecycle changes can be published on the\n * status-change bus and projected to subscribed buyers.\n *\n * **Spec status (v6.0):** The AdCP spec doesn't yet ship a closed enum\n * for `resource_type`. The values below are the v6 SDK's working set —\n * the resource categories adopters publish lifecycle events against\n * today. They become wire-visible via the URI scheme\n * `adcp://{account_id}/{resource_type}/{resource_id}` projected to MCP\n * Resources subscriptions.\n *\n * Filed upstream as adcontextprotocol/adcp#3412 proposing a normative\n * `enums/status-change-resource-type.json`. When the spec lands the\n * enum, this type becomes a `$ref` to the generated schema. Until then\n * adopters subscribing across multiple AdCP agents may see drift; the\n * SDK's set is the working canonical until the spec consolidates.\n *\n * Adopters publishing custom resource types not in this list should\n * prefix with `x-` (e.g., `'x-pcim_session'`) to reduce collision risk\n * with the eventual normative enum. The framework accepts any string\n * (the type is widened with `(string & {})` for forward-compat) but\n * only the values listed here have stable cross-SDK semantics.\n */\nexport type StatusChangeResourceType =\n | 'media_buy'\n | 'creative'\n | 'audience'\n | 'signal'\n | 'proposal'\n | 'plan'\n | 'rights_grant'\n | 'delivery_report'\n | 'property_list'\n | 'collection_list'\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {});\n\n/**\n * A single status-change event.\n *\n * `account_id` scopes the event to a tenant; subscribers receive only\n * events for their resolved account. `resource_uri` follows the MCP\n * Resources URI scheme: `adcp://{account_id}/{resource_type}/{resource_id}`.\n */\nexport interface StatusChange<TPayload = unknown> {\n account_id: string;\n resource_type: StatusChangeResourceType;\n resource_id: string;\n /** Canonical MCP Resources URI for this resource. */\n resource_uri: string;\n /** ISO 8601 timestamp the change was observed. */\n at: string;\n /**\n * Resource-type-specific change payload. Shape is the wire fragment the\n * subscribed buyer will see — e.g., for `media_buy` it's the AdCP\n * `media_buy_status_changes` message body.\n */\n payload: TPayload;\n /**\n * Correlation id linking this change back to the buyer request that\n * caused it. Useful for \"show me everything that happened from this\n * `create_media_buy` call\" observability across HITL flows. Adopters\n * pass through `ctx.task.id` (for `*Task`-driven changes) or any\n * stable request identifier they generate at dispatch time.\n *\n * Optional — many status changes originate from cron / webhook /\n * upstream-platform events that have no buyer-request correlation.\n */\n caused_by_request_id?: string;\n /**\n * Status the resource was transitioning FROM. Lets subscribers assert\n * legal transitions (`from: 'matching' → to: 'active'` is fine;\n * `from: 'failed' → to: 'matching'` is a state-machine bug). The\n * framework doesn't validate transitions in v6.0 (no per-resource\n * state machine yet); the field is captured and projected to the\n * wire so downstream consumers can.\n */\n previous_status?: string;\n}\n\nexport interface PublishStatusChangeOpts<TPayload = unknown> {\n account_id: string;\n resource_type: StatusChangeResourceType;\n resource_id: string;\n payload: TPayload;\n /** Override the timestamp (defaults to now). Useful for replay/backfill. */\n at?: string;\n /**\n * Correlation id linking this change to the buyer request that caused\n * it. Inside `*Task` method bodies, pass `ctx.task.id` to thread the\n * task lifecycle. Outside HITL flows, pass any stable request id you\n * derive at dispatch time. Optional.\n */\n caused_by_request_id?: string;\n /** Status the resource was transitioning FROM. Optional. */\n previous_status?: string;\n}\n\nexport type StatusChangeListener = (event: StatusChange) => void | Promise<void>;\n\nexport interface StatusChangeBus {\n publish<TPayload>(opts: PublishStatusChangeOpts<TPayload>): void;\n /**\n * Subscribe a listener. Returns an unsubscribe function. Listeners are\n * fire-and-forget; rejected promises are caught and logged so one bad\n * subscriber doesn't break delivery to others.\n */\n subscribe(listener: StatusChangeListener): () => void;\n /** Snapshot the most-recent N events (in-memory cache for `tasks/get` + replay). */\n recent(limit?: number): readonly StatusChange[];\n}\n\nconst DEFAULT_RECENT_LIMIT = 1000;\n\nexport function createInMemoryStatusChangeBus(opts?: { recentLimit?: number }): StatusChangeBus {\n const listeners = new Set<StatusChangeListener>();\n const recent: StatusChange[] = [];\n const recentLimit = opts?.recentLimit ?? DEFAULT_RECENT_LIMIT;\n\n return {\n publish<TPayload>(eventOpts: PublishStatusChangeOpts<TPayload>): void {\n const event: StatusChange<TPayload> = {\n account_id: eventOpts.account_id,\n resource_type: eventOpts.resource_type,\n resource_id: eventOpts.resource_id,\n resource_uri: `adcp://${eventOpts.account_id}/${eventOpts.resource_type}/${eventOpts.resource_id}`,\n at: eventOpts.at ?? new Date().toISOString(),\n payload: eventOpts.payload,\n ...(eventOpts.caused_by_request_id !== undefined && { caused_by_request_id: eventOpts.caused_by_request_id }),\n ...(eventOpts.previous_status !== undefined && { previous_status: eventOpts.previous_status }),\n };\n recent.push(event as StatusChange);\n if (recent.length > recentLimit) recent.shift();\n\n for (const listener of listeners) {\n try {\n const result = listener(event as StatusChange);\n if (result && typeof (result as Promise<void>).catch === 'function') {\n (result as Promise<void>).catch((err: unknown) => {\n // eslint-disable-next-line no-console\n console.warn('[adcp] status-change listener rejected:', err);\n });\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn('[adcp] status-change listener threw:', err);\n }\n }\n },\n\n subscribe(listener: StatusChangeListener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n recent(limit?: number): readonly StatusChange[] {\n const n = limit ?? recent.length;\n return recent.slice(-n);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Module-level adopter-facing primitive\n// ---------------------------------------------------------------------------\n\nlet activeBus: StatusChangeBus = createInMemoryStatusChangeBus();\n\n/**\n * Push a status change for a resource. Adopters call this from anywhere —\n * webhook handler, cron, in-process worker — to surface lifecycle changes\n * the framework projects to subscribed buyers.\n *\n * ```ts\n * // After GAM webhook reports order activation:\n * publishStatusChange({\n * account_id: account.id,\n * resource_type: 'media_buy',\n * resource_id: gamOrderToBuyId(order),\n * payload: { status: 'active', activated_at: order.startTime },\n * });\n * ```\n *\n * Buyers subscribed via MCP `resources/subscribe` (or the A2A equivalent)\n * receive the change as a `notifications/resources/updated` notification\n * carrying the `payload` as the resource's wire fragment.\n */\nexport function publishStatusChange<TPayload>(opts: PublishStatusChangeOpts<TPayload>): void {\n activeBus.publish(opts);\n}\n\n/**\n * Replace the active bus. The framework calls this at server construction\n * to wire its own bus implementation; tests can call it to swap in a fake.\n *\n * Returns the previous bus so the caller can restore it (e.g., in a test\n * teardown).\n */\nexport function setStatusChangeBus(bus: StatusChangeBus): StatusChangeBus {\n const prev = activeBus;\n activeBus = bus;\n return prev;\n}\n\n/** Read the active bus (for the framework to wire subscribers). */\nexport function getStatusChangeBus(): StatusChangeBus {\n return activeBus;\n}\n"],"mappings":"AAqJA,MAAM,uBAAuB;AAEtB,SAAS,8BAA8B,MAAkD;AAC9F,QAAM,YAAY,oBAAI,IAA0B;AAChD,QAAM,SAAyB,CAAC;AAChC,QAAM,cAAc,MAAM,eAAe;AAEzC,SAAO;AAAA,IACL,QAAkB,WAAoD;AACpE,YAAM,QAAgC;AAAA,QACpC,YAAY,UAAU;AAAA,QACtB,eAAe,UAAU;AAAA,QACzB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU,UAAU,UAAU,IAAI,UAAU,aAAa,IAAI,UAAU,WAAW;AAAA,QAChG,IAAI,UAAU,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC3C,SAAS,UAAU;AAAA,QACnB,GAAI,UAAU,yBAAyB,UAAa,EAAE,sBAAsB,UAAU,qBAAqB;AAAA,QAC3G,GAAI,UAAU,oBAAoB,UAAa,EAAE,iBAAiB,UAAU,gBAAgB;AAAA,MAC9F;AACA,aAAO,KAAK,KAAqB;AACjC,UAAI,OAAO,SAAS,YAAa,QAAO,MAAM;AAE9C,iBAAW,YAAY,WAAW;AAChC,YAAI;AACF,gBAAM,SAAS,SAAS,KAAqB;AAC7C,cAAI,UAAU,OAAQ,OAAyB,UAAU,YAAY;AACnE,YAAC,OAAyB,MAAM,CAAC,QAAiB;AAEhD,sBAAQ,KAAK,2CAA2C,GAAG;AAAA,YAC7D,CAAC;AAAA,UACH;AAAA,QACF,SAAS,KAAK;AAEZ,kBAAQ,KAAK,wCAAwC,GAAG;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,UAA4C;AACpD,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,IAEA,OAAO,OAAyC;AAC9C,YAAM,IAAI,SAAS,OAAO;AAC1B,aAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACxB;AAAA,EACF;AACF;AAMA,IAAI,YAA6B,8BAA8B;AAqBxD,SAAS,oBAA8B,MAA+C;AAC3F,YAAU,QAAQ,IAAI;AACxB;AASO,SAAS,mBAAmB,KAAuC;AACxE,QAAM,OAAO;AACb,cAAY;AACZ,SAAO;AACT;AAGO,SAAS,qBAAsC;AACpD,SAAO;AACT;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { fileURLToPath as __adcpFileURLToPath } from 'node:url';
|
|
2
|
-
import { dirname as __adcpDirname } from 'node:path';
|
|
3
|
-
import { createRequire as __adcpCreateRequire } from 'node:module';
|
|
4
|
-
const __filename = __adcpFileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = __adcpDirname(__filename);
|
|
6
|
-
const require = __adcpCreateRequire(import.meta.url);
|
|
7
1
|
const identityStatusMappers = {
|
|
8
2
|
mediaBuy: (native) => ["pending_creatives", "pending_start", "active", "paused", "completed", "rejected", "canceled"].includes(native) ? native : "pending_creatives",
|
|
9
3
|
creative: (native) => ["pending_review", "approved", "rejected", "archived"].includes(native) ? native : "pending_review",
|