@adcp/sdk 14.0.0-rc.37 → 14.0.0-rc.39
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/bin/adcp-storyboard-summary.js +286 -0
- package/bin/adcp.js +221 -10
- package/dist/lib/conformance/schemaLoader.d.mts +1 -1
- package/dist/lib/conformance/schemaLoader.d.ts +1 -1
- package/dist/lib/core/AgentClient.d.mts +6 -1
- package/dist/lib/core/AgentClient.d.ts +6 -1
- package/dist/lib/core/AgentClient.js +9 -0
- package/dist/lib/core/AgentClient.mjs +9 -0
- package/dist/lib/core/ConversationTypes.d.mts +29 -0
- package/dist/lib/core/ConversationTypes.d.ts +29 -0
- package/dist/lib/core/SingleAgentClient.d.mts +3 -1
- package/dist/lib/core/SingleAgentClient.d.ts +3 -1
- package/dist/lib/core/SingleAgentClient.js +9 -1
- package/dist/lib/core/SingleAgentClient.mjs +9 -1
- package/dist/lib/core/TaskExecutor.d.mts +13 -1
- package/dist/lib/core/TaskExecutor.d.ts +13 -1
- package/dist/lib/core/TaskExecutor.js +216 -18
- package/dist/lib/core/TaskExecutor.mjs +216 -19
- package/dist/lib/index.d.mts +5 -2
- package/dist/lib/index.d.ts +5 -2
- package/dist/lib/index.js +10 -1
- package/dist/lib/index.mjs +10 -1
- package/dist/lib/media-buy/action-assessment.d.mts +77 -0
- package/dist/lib/media-buy/action-assessment.d.ts +77 -0
- package/dist/lib/media-buy/action-assessment.js +300 -0
- package/dist/lib/media-buy/action-assessment.mjs +284 -0
- package/dist/lib/media-buy/action-constraints.d.mts +9 -0
- package/dist/lib/media-buy/action-constraints.d.ts +9 -0
- package/dist/lib/media-buy/action-constraints.js +170 -0
- package/dist/lib/media-buy/action-constraints.mjs +146 -0
- package/dist/lib/media-buy/action-contracts.d.mts +40 -0
- package/dist/lib/media-buy/action-contracts.d.ts +40 -0
- package/dist/lib/media-buy/action-contracts.js +304 -0
- package/dist/lib/media-buy/action-contracts.mjs +267 -0
- package/dist/lib/media-buy/action-metadata.generated.d.mts +37 -0
- package/dist/lib/media-buy/action-metadata.generated.d.ts +37 -0
- package/dist/lib/media-buy/action-metadata.generated.js +128 -0
- package/dist/lib/media-buy/action-metadata.generated.mjs +101 -0
- package/dist/lib/media-buy/action-types.d.mts +106 -0
- package/dist/lib/media-buy/action-types.d.ts +106 -0
- package/dist/lib/{types/v3-1-beta/tools.generated.js → media-buy/action-types.js} +2 -2
- package/dist/lib/media-buy/actions.d.mts +6 -0
- package/dist/lib/media-buy/actions.d.ts +6 -0
- package/dist/lib/media-buy/actions.js +38 -0
- package/dist/lib/media-buy/actions.mjs +9 -0
- package/dist/lib/media-buy/available-actions.d.mts +2 -1
- package/dist/lib/media-buy/available-actions.d.ts +2 -1
- package/dist/lib/media-buy/available-actions.js +4 -3
- package/dist/lib/media-buy/available-actions.mjs +4 -3
- package/dist/lib/media-buy/compatibility.js +3 -0
- package/dist/lib/media-buy/compatibility.mjs +3 -0
- package/dist/lib/media-buy/index.d.mts +4 -0
- package/dist/lib/media-buy/index.d.ts +4 -0
- package/dist/lib/media-buy/index.js +3 -1
- package/dist/lib/media-buy/index.mjs +1 -0
- package/dist/lib/media-buy/legacy-action-ids.d.mts +1 -0
- package/dist/lib/media-buy/legacy-action-ids.d.ts +1 -0
- package/dist/lib/media-buy/legacy-action-ids.js +50 -0
- package/dist/lib/media-buy/legacy-action-ids.mjs +26 -0
- package/dist/lib/media-buy/mutations.d.mts +70 -0
- package/dist/lib/media-buy/mutations.d.ts +70 -0
- package/dist/lib/media-buy/mutations.js +525 -0
- package/dist/lib/media-buy/mutations.mjs +498 -0
- package/dist/lib/media-buy/preflight.d.mts +20 -69
- package/dist/lib/media-buy/preflight.d.ts +20 -69
- package/dist/lib/media-buy/preflight.js +100 -336
- package/dist/lib/media-buy/preflight.mjs +111 -333
- package/dist/lib/media-buy/targeting-input.d.mts +7 -4
- package/dist/lib/media-buy/targeting-input.d.ts +7 -4
- package/dist/lib/media-buy/types.d.mts +55 -7
- package/dist/lib/media-buy/types.d.ts +55 -7
- package/dist/lib/protocols/rawResponseCapture.d.mts +12 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +12 -0
- package/dist/lib/protocols/rawResponseCapture.js +33 -3
- package/dist/lib/protocols/rawResponseCapture.mjs +32 -3
- package/dist/lib/registry/types.generated.d.mts +377 -9
- package/dist/lib/registry/types.generated.d.ts +377 -9
- package/dist/lib/reporting/content-mismatch.d.mts +126 -0
- package/dist/lib/reporting/content-mismatch.d.ts +126 -0
- package/dist/lib/reporting/content-mismatch.js +90 -0
- package/dist/lib/reporting/content-mismatch.mjs +66 -0
- package/dist/lib/reporting/evidence.d.mts +1 -0
- package/dist/lib/reporting/evidence.d.ts +1 -0
- package/dist/lib/reporting/evidence.js +32 -3
- package/dist/lib/reporting/evidence.mjs +31 -3
- package/dist/lib/reporting/index.d.mts +3 -1
- package/dist/lib/reporting/index.d.ts +3 -1
- package/dist/lib/reporting/index.js +3 -0
- package/dist/lib/reporting/index.mjs +2 -0
- package/dist/lib/reporting/ledger/handler.d.mts +51 -1
- package/dist/lib/reporting/ledger/handler.d.ts +51 -1
- package/dist/lib/reporting/ledger/handler.js +306 -38
- package/dist/lib/reporting/ledger/handler.mjs +304 -37
- package/dist/lib/reporting/ledger/health.d.mts +12 -0
- package/dist/lib/reporting/ledger/health.d.ts +12 -0
- package/dist/lib/reporting/ledger/health.js +15 -2
- package/dist/lib/reporting/ledger/health.mjs +13 -1
- package/dist/lib/reporting/ledger/index.d.mts +3 -0
- package/dist/lib/reporting/ledger/index.d.ts +3 -0
- package/dist/lib/reporting/ledger/index.js +7 -1
- package/dist/lib/reporting/ledger/index.mjs +3 -0
- package/dist/lib/reporting/ledger/lifecycle.d.mts +31 -4
- package/dist/lib/reporting/ledger/lifecycle.d.ts +31 -4
- package/dist/lib/reporting/ledger/lifecycle.js +244 -37
- package/dist/lib/reporting/ledger/lifecycle.mjs +244 -37
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +231 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +231 -0
- package/dist/lib/reporting/ledger/managed-postgres.js +1797 -0
- package/dist/lib/reporting/ledger/managed-postgres.mjs +1776 -0
- package/dist/lib/reporting/ledger/managed.d.mts +355 -0
- package/dist/lib/reporting/ledger/managed.d.ts +355 -0
- package/dist/lib/reporting/ledger/managed.js +661 -0
- package/dist/lib/reporting/ledger/managed.mjs +633 -0
- package/dist/lib/reporting/ledger/notification-activity.d.mts +222 -0
- package/dist/lib/reporting/ledger/notification-activity.d.ts +222 -0
- package/dist/lib/reporting/ledger/notification-activity.js +1139 -0
- package/dist/lib/reporting/ledger/notification-activity.mjs +1110 -0
- package/dist/lib/reporting/ledger/postgres.d.mts +161 -1
- package/dist/lib/reporting/ledger/postgres.d.ts +161 -1
- package/dist/lib/reporting/ledger/postgres.js +1153 -21
- package/dist/lib/reporting/ledger/postgres.mjs +1152 -21
- package/dist/lib/reporting/ledger/producer.d.mts +8 -0
- package/dist/lib/reporting/ledger/producer.d.ts +8 -0
- package/dist/lib/reporting/ledger/producer.js +146 -52
- package/dist/lib/reporting/ledger/producer.mjs +146 -51
- package/dist/lib/reporting/ledger/types.d.mts +358 -1
- package/dist/lib/reporting/ledger/types.d.ts +358 -1
- package/dist/lib/reporting/ledger/types.js +3 -0
- package/dist/lib/reporting/ledger/types.mjs +2 -0
- package/dist/lib/reporting/reconciliation.d.mts +362 -2
- package/dist/lib/reporting/reconciliation.d.ts +362 -2
- package/dist/lib/reporting/reconciliation.js +1051 -7
- package/dist/lib/reporting/reconciliation.mjs +1053 -7
- package/dist/lib/reporting/service/conformance.d.mts +35 -0
- package/dist/lib/reporting/service/conformance.d.ts +35 -0
- package/dist/lib/reporting/service/conformance.js +89 -0
- package/dist/lib/reporting/service/conformance.mjs +68 -0
- package/dist/lib/reporting/service/index.d.mts +182 -0
- package/dist/lib/reporting/service/index.d.ts +182 -0
- package/dist/lib/reporting/service/index.js +793 -0
- package/dist/lib/reporting/service/index.mjs +787 -0
- package/dist/lib/reporting/source/index.d.mts +2 -1
- package/dist/lib/reporting/source/index.d.ts +2 -1
- package/dist/lib/reporting/source/index.js +16 -3
- package/dist/lib/reporting/source/index.mjs +12 -1
- package/dist/lib/reporting/source/inline.d.mts +88 -1
- package/dist/lib/reporting/source/inline.d.ts +88 -1
- package/dist/lib/reporting/source/inline.js +1161 -163
- package/dist/lib/reporting/source/inline.mjs +1166 -163
- package/dist/lib/reporting/source/manifest.js +12 -7
- package/dist/lib/reporting/source/manifest.mjs +12 -7
- package/dist/lib/reporting/source/source.d.mts +26 -0
- package/dist/lib/reporting/source/source.d.ts +26 -0
- package/dist/lib/reporting/source/source.js +71 -2
- package/dist/lib/reporting/source/source.mjs +65 -1
- package/dist/lib/schemas/index.d.mts +22 -1
- package/dist/lib/schemas/index.d.ts +22 -1
- package/dist/lib/schemas/index.js +7 -0
- package/dist/lib/schemas/index.mjs +7 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +18 -0
- package/dist/lib/server/create-adcp-server.d.ts +18 -0
- package/dist/lib/server/create-adcp-server.js +52 -2
- package/dist/lib/server/create-adcp-server.mjs +52 -2
- package/dist/lib/server/decisioning/account.d.mts +1 -1
- package/dist/lib/server/decisioning/account.d.ts +1 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -0
- package/dist/lib/server/decisioning/index.d.ts +1 -0
- package/dist/lib/server/decisioning/platform.d.mts +3 -0
- package/dist/lib/server/decisioning/platform.d.ts +3 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +88 -10
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +88 -10
- package/dist/lib/server/decisioning/specialisms/reporting.d.mts +38 -0
- package/dist/lib/server/decisioning/specialisms/reporting.d.ts +38 -0
- package/dist/lib/{types/v3-1-beta/index.js → server/decisioning/specialisms/reporting.js} +2 -8
- package/dist/lib/server/decisioning/specialisms/reporting.mjs +0 -0
- package/dist/lib/server/index.d.mts +4 -2
- package/dist/lib/server/index.d.ts +4 -2
- package/dist/lib/server/index.js +5 -0
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/media-buy-action-resolver.d.mts +63 -0
- package/dist/lib/server/media-buy-action-resolver.d.ts +63 -0
- package/dist/lib/server/media-buy-action-resolver.js +297 -0
- package/dist/lib/server/media-buy-action-resolver.mjs +285 -0
- package/dist/lib/server/media-buy-actions.d.mts +7 -8
- package/dist/lib/server/media-buy-actions.d.ts +7 -8
- package/dist/lib/server/media-buy-actions.js +57 -14
- package/dist/lib/server/media-buy-actions.mjs +63 -14
- package/dist/lib/server/notification-subscriptions/index.d.mts +2 -2
- package/dist/lib/server/notification-subscriptions/index.d.ts +2 -2
- package/dist/lib/server/notification-subscriptions/index.js +2 -0
- package/dist/lib/server/notification-subscriptions/index.mjs +2 -0
- package/dist/lib/server/notification-subscriptions/postgres-runtime.d.mts +3 -1
- package/dist/lib/server/notification-subscriptions/postgres-runtime.d.ts +3 -1
- package/dist/lib/server/notification-subscriptions/postgres-runtime.js +1 -0
- package/dist/lib/server/notification-subscriptions/postgres-runtime.mjs +1 -0
- package/dist/lib/server/notification-subscriptions/runtime.d.mts +12 -1
- package/dist/lib/server/notification-subscriptions/runtime.d.ts +12 -1
- package/dist/lib/server/notification-subscriptions/runtime.js +102 -16
- package/dist/lib/server/notification-subscriptions/runtime.mjs +101 -16
- package/dist/lib/server/notification-subscriptions/types.d.mts +104 -1
- package/dist/lib/server/notification-subscriptions/types.d.ts +104 -1
- package/dist/lib/server/webhook-emitter.d.mts +40 -5
- package/dist/lib/server/webhook-emitter.d.ts +40 -5
- package/dist/lib/server/webhook-emitter.js +23 -12
- package/dist/lib/server/webhook-emitter.mjs +23 -12
- package/dist/lib/storage/interfaces.d.mts +14 -2
- package/dist/lib/storage/interfaces.d.ts +14 -2
- package/dist/lib/testing/compliance/comply.d.mts +9 -3
- package/dist/lib/testing/compliance/comply.d.ts +9 -3
- package/dist/lib/testing/compliance/comply.js +158 -3
- package/dist/lib/testing/compliance/comply.mjs +159 -4
- package/dist/lib/testing/compliance/storyboard-tracks.js +7 -5
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +7 -5
- package/dist/lib/testing/compliance/summary.js +10 -1
- package/dist/lib/testing/compliance/summary.mjs +10 -1
- package/dist/lib/testing/index.d.mts +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.js +2 -0
- package/dist/lib/testing/index.mjs +3 -1
- package/dist/lib/testing/storyboard/agent-routing.d.mts +12 -43
- package/dist/lib/testing/storyboard/agent-routing.d.ts +12 -43
- package/dist/lib/testing/storyboard/agent-routing.js +75 -13
- package/dist/lib/testing/storyboard/agent-routing.mjs +70 -12
- package/dist/lib/testing/storyboard/index.d.mts +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +1 -0
- package/dist/lib/testing/storyboard/index.js +3 -0
- package/dist/lib/testing/storyboard/index.mjs +2 -0
- package/dist/lib/testing/storyboard/junit.d.mts +1 -1
- package/dist/lib/testing/storyboard/junit.d.ts +1 -1
- package/dist/lib/testing/storyboard/junit.js +21 -2
- package/dist/lib/testing/storyboard/junit.mjs +21 -2
- package/dist/lib/testing/storyboard/probes.d.mts +130 -0
- package/dist/lib/testing/storyboard/probes.d.ts +130 -0
- package/dist/lib/testing/storyboard/probes.js +682 -10
- package/dist/lib/testing/storyboard/probes.mjs +683 -3
- package/dist/lib/testing/storyboard/request-signing/builder.d.mts +16 -5
- package/dist/lib/testing/storyboard/request-signing/builder.d.ts +16 -5
- package/dist/lib/testing/storyboard/request-signing/grader.d.mts +44 -1
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts +44 -1
- package/dist/lib/testing/storyboard/request-signing/grader.js +46 -22
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +43 -21
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.mts +86 -11
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts +86 -11
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +119 -25
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +117 -26
- package/dist/lib/testing/storyboard/request-signing/synthesize.js +22 -2
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +22 -2
- package/dist/lib/testing/storyboard/runner.d.mts +103 -0
- package/dist/lib/testing/storyboard/runner.d.ts +103 -0
- package/dist/lib/testing/storyboard/runner.js +1090 -268
- package/dist/lib/testing/storyboard/runner.mjs +1096 -261
- package/dist/lib/testing/storyboard/seeding.d.mts +4 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +4 -1
- package/dist/lib/testing/storyboard/seeding.js +55 -24
- package/dist/lib/testing/storyboard/seeding.mjs +55 -24
- package/dist/lib/testing/storyboard/test-kit.d.mts +37 -3
- package/dist/lib/testing/storyboard/test-kit.d.ts +37 -3
- package/dist/lib/testing/storyboard/test-kit.js +8 -2
- package/dist/lib/testing/storyboard/test-kit.mjs +7 -2
- package/dist/lib/testing/storyboard/types.d.mts +132 -10
- package/dist/lib/testing/storyboard/types.d.ts +132 -10
- package/dist/lib/testing/storyboard/types.js +17 -0
- package/dist/lib/testing/storyboard/types.mjs +16 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +16 -0
- package/dist/lib/testing/storyboard/validations.mjs +16 -0
- package/dist/lib/testing/test-controller.d.mts +1 -1
- package/dist/lib/testing/test-controller.d.ts +1 -1
- package/dist/lib/types/buy-products.d.ts +71 -6
- package/dist/lib/types/control-media-buy.d.ts +25 -11
- package/dist/lib/types/core.generated.d.mts +69 -10
- package/dist/lib/types/core.generated.d.ts +69 -10
- package/dist/lib/types/create-media-buy.d.ts +71 -6
- package/dist/lib/types/forward-compat-error-codes.d.mts +7 -6
- package/dist/lib/types/forward-compat-error-codes.d.ts +7 -6
- package/dist/lib/types/index.d.mts +2 -2
- package/dist/lib/types/index.d.ts +2 -2
- package/dist/lib/types/schemas.generated.d.ts +8040 -8116
- package/dist/lib/types/schemas.generated.js +1074 -309
- package/dist/lib/types/schemas.generated.mjs +1068 -309
- package/dist/lib/types/tools.generated.d.mts +65 -6
- package/dist/lib/types/tools.generated.d.ts +65 -6
- package/dist/lib/types/update-media-buy.d.ts +71 -6
- package/dist/lib/utils/redact-secrets.d.mts +1 -1
- package/dist/lib/utils/redact-secrets.d.ts +1 -1
- package/dist/lib/utils/redact-secrets.js +1 -1
- package/dist/lib/utils/redact-secrets.mjs +1 -1
- package/dist/lib/v2/projection/cache-versions.d.mts +0 -1
- package/dist/lib/v2/projection/cache-versions.d.ts +0 -1
- package/dist/lib/v2/projection/cache-versions.js +1 -15
- package/dist/lib/v2/projection/cache-versions.mjs +1 -14
- package/dist/lib/v2/projection/canonical-properties.js +2 -2
- package/dist/lib/v2/projection/canonical-properties.mjs +3 -3
- package/dist/lib/v2/projection/registry.d.mts +1 -1
- package/dist/lib/v2/projection/registry.d.ts +1 -1
- package/dist/lib/v2/projection/registry.js +2 -2
- package/dist/lib/v2/projection/registry.mjs +3 -3
- package/dist/lib/validation/schema-loader.d.mts +9 -1
- package/dist/lib/validation/schema-loader.d.ts +9 -1
- package/dist/lib/validation/schema-loader.js +65 -8
- package/dist/lib/validation/schema-loader.mjs +64 -8
- package/dist/lib/version.d.mts +5 -5
- package/dist/lib/version.d.ts +5 -5
- package/dist/lib/version.js +3 -8
- package/dist/lib/version.mjs +3 -8
- package/dist/lib/wholesale-feed-sync/index.d.mts +1 -0
- package/dist/lib/wholesale-feed-sync/index.d.ts +1 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.d.mts +42 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.d.ts +42 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.js +16 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.mjs +0 -0
- package/dist/lib/wholesale-feed-sync/sync.d.mts +6 -6
- package/dist/lib/wholesale-feed-sync/sync.d.ts +6 -6
- package/dist/lib/wholesale-feed-sync/sync.js +3 -1
- package/dist/lib/wholesale-feed-sync/sync.mjs +3 -1
- package/dist/lib/wholesale-feed-sync/types.d.mts +15 -14
- package/dist/lib/wholesale-feed-sync/types.d.ts +15 -14
- package/dist/lib/wholesale-feed-sync/webhook-notification.d.mts +7 -5
- package/dist/lib/wholesale-feed-sync/webhook-notification.d.ts +7 -5
- package/dist/lib/wholesale-feed-sync/webhook-notification.js +45 -0
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +44 -0
- package/docs/CLI.md +1 -1
- package/docs/TYPE-SUMMARY.md +118 -4
- package/docs/guides/ASYNC-API-REFERENCE.md +62 -1
- package/docs/guides/ASYNC-DEVELOPER-GUIDE.md +25 -0
- package/docs/guides/ASYNC-DOCUMENTATION-INDEX.md +3 -0
- package/docs/guides/BUYER-QUICKSTART-3.2.md +5 -0
- package/docs/guides/DURABLE-BUYER-WRITES.md +337 -0
- package/docs/guides/EXISTING-PLATFORM.md +80 -1
- package/docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md +57 -0
- package/docs/guides/MEDIA-BUY-ACTION-ASSESSMENT.md +300 -0
- package/docs/guides/REPORTING-LEDGER.md +654 -3
- package/docs/guides/REPORTING-RECONCILIATION.md +50 -0
- package/docs/guides/REPORTING-SOURCE-EXECUTOR.md +63 -1
- package/docs/guides/SELLER-QUICKSTART-3.2.md +2 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +35 -0
- package/docs/guides/idempotency-crash-recovery.md +4 -0
- package/docs/llms.txt +4 -2
- package/docs/migration-14.x-rc-worksheet.md +60 -5
- package/docs/migration-7.9-to-7.10.md +7 -5
- package/examples/README.md +17 -0
- package/examples/durable-buyer-writes/caller.ts +745 -0
- package/examples/durable-buyer-writes/worker.ts +240 -0
- package/examples/reliable-reporting-service/README.md +100 -0
- package/examples/seller-3.2-starter.ts +7 -8
- package/examples/targeting-input-existing-platform.ts +153 -0
- package/package.json +41 -29
- package/skills/build-seller-agent/SKILL.md +2 -0
- package/skills/build-seller-agent/specialisms/signed-requests.md +11 -1
- package/skills/cross-cutting.md +28 -11
- package/compliance/cache/3.1.0-beta.7/domains/brand/index.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/distributed_brand_resolution.yaml +0 -415
- package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/single_side_trust_extension.yaml +0 -454
- package/compliance/cache/3.1.0-beta.7/domains/creative/index.yaml +0 -339
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/billing_out_of_band.yaml +0 -153
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/native_in_feed.yaml +0 -543
- package/compliance/cache/3.1.0-beta.7/domains/governance/index.yaml +0 -682
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/index.yaml +0 -781
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/audience_buy_flow.yaml +0 -380
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/available_actions.yaml +0 -565
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/canonical_formats.yaml +0 -711
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/create_media_buy_async.yaml +0 -234
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_reception.yaml +0 -247
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/delivery_reporting.yaml +0 -357
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment.yaml +0 -633
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/event_dedup_flow.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_approved.yaml +0 -214
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_conditions.yaml +0 -199
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied.yaml +0 -204
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/invalid_transitions.yaml +0 -289
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_accountability.yaml +0 -244
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow.yaml +0 -428
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/product_signal_targeting.yaml +0 -373
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_enforcement.yaml +0 -517
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/reach_buy_flow.yaml +0 -823
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_products.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/state-machine.yaml +0 -442
- package/compliance/cache/3.1.0-beta.7/domains/signals/index.yaml +0 -266
- package/compliance/cache/3.1.0-beta.7/domains/sponsored-intelligence/index.yaml +0 -256
- package/compliance/cache/3.1.0-beta.7/index.json +0 -356
- package/compliance/cache/3.1.0-beta.7/protocols/brand/index.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/distributed_brand_resolution.yaml +0 -415
- package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/single_side_trust_extension.yaml +0 -454
- package/compliance/cache/3.1.0-beta.7/protocols/creative/index.yaml +0 -339
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/billing_out_of_band.yaml +0 -153
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/native_in_feed.yaml +0 -543
- package/compliance/cache/3.1.0-beta.7/protocols/governance/index.yaml +0 -682
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/index.yaml +0 -781
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/audience_buy_flow.yaml +0 -380
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/available_actions.yaml +0 -565
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/canonical_formats.yaml +0 -711
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/create_media_buy_async.yaml +0 -234
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_reception.yaml +0 -247
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/delivery_reporting.yaml +0 -357
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment.yaml +0 -633
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/event_dedup_flow.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_approved.yaml +0 -214
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_conditions.yaml +0 -199
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied.yaml +0 -204
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/invalid_transitions.yaml +0 -289
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_accountability.yaml +0 -244
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow.yaml +0 -428
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/product_signal_targeting.yaml +0 -373
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_enforcement.yaml +0 -517
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/reach_buy_flow.yaml +0 -823
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_products.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/state-machine.yaml +0 -442
- package/compliance/cache/3.1.0-beta.7/protocols/signals/index.yaml +0 -266
- package/compliance/cache/3.1.0-beta.7/protocols/sponsored-intelligence/index.yaml +0 -256
- package/compliance/cache/3.1.0-beta.7/specialisms/audience-sync/index.yaml +0 -313
- package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/index.yaml +0 -350
- package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/scenarios/governance_denied.yaml +0 -226
- package/compliance/cache/3.1.0-beta.7/specialisms/collection-lists/index.yaml +0 -359
- package/compliance/cache/3.1.0-beta.7/specialisms/content-standards/index.yaml +0 -572
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-ad-server/index.yaml +0 -409
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/generative-seller.yaml +0 -807
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/index.yaml +0 -758
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-template/index.yaml +0 -510
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/index.yaml +0 -143
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +0 -117
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-delivery-monitor/index.yaml +0 -441
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/denied.yaml +0 -221
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/index.yaml +0 -330
- package/compliance/cache/3.1.0-beta.7/specialisms/property-lists/index.yaml +0 -482
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-broadcast-tv/index.yaml +0 -738
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-catalog-driven/index.yaml +0 -840
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-guaranteed/index.yaml +0 -601
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-non-guaranteed/index.yaml +0 -546
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-proposal-mode/index.yaml +0 -586
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-social/index.yaml +0 -919
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/index.yaml +0 -424
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/scenarios/governance_denied.yaml +0 -211
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-owned/index.yaml +0 -317
- package/compliance/cache/3.1.0-beta.7/specialisms/sponsored-intelligence/index.yaml +0 -59
- package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor-live.yaml +0 -78
- package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor.yaml +0 -223
- package/compliance/cache/3.1.0-beta.7/test-kits/billing-gate-runner.yaml +0 -115
- package/compliance/cache/3.1.0-beta.7/test-kits/bistro-oranje.yaml +0 -126
- package/compliance/cache/3.1.0-beta.7/test-kits/distributed-brand-runner.yaml +0 -281
- package/compliance/cache/3.1.0-beta.7/test-kits/nova-motors.yaml +0 -262
- package/compliance/cache/3.1.0-beta.7/test-kits/osei-natural.yaml +0 -126
- package/compliance/cache/3.1.0-beta.7/test-kits/parallel-dispatch-runner.yaml +0 -196
- package/compliance/cache/3.1.0-beta.7/test-kits/rate-limit-trip-runner.yaml +0 -172
- package/compliance/cache/3.1.0-beta.7/test-kits/signed-requests-runner.yaml +0 -155
- package/compliance/cache/3.1.0-beta.7/test-kits/single-side-trust-runner.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/test-kits/substitution-observer-runner.yaml +0 -688
- package/compliance/cache/3.1.0-beta.7/test-kits/summit-foods.yaml +0 -125
- package/compliance/cache/3.1.0-beta.7/test-kits/webhook-receiver-runner.yaml +0 -265
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/001-minimal-plan.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/002-full-plan.json +0 -217
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/003-bookkeeping-stripped.json +0 -60
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004a-human-review-omitted.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004b-human-review-explicit-null.json +0 -49
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005a-policy-categories-order-1.json +0 -53
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005b-policy-categories-order-2.json +0 -57
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006a-ext-trace-v1.json +0 -49
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006b-ext-trace-v2.json +0 -53
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/007-unicode-objectives.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/008-numeric-canonicalization.json +0 -65
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/README.md +0 -220
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/canonicalization.json +0 -241
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/keys.json +0 -60
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/001-no-signature-header.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/002-wrong-tag.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/003-expired-signature.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/004-window-too-long.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/005-alg-not-allowed.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/006-missing-covered-component.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/007-missing-content-digest.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/008-unknown-keyid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/010-content-digest-mismatch.json +0 -33
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/011-malformed-header.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/012-missing-expires-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/013-expires-le-created.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/014-missing-nonce-param.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/015-signature-invalid.json +0 -28
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/016-replayed-nonce.json +0 -35
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/017-key-revoked.json +0 -38
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +0 -28
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/019-signature-without-signature-input.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/020-rate-abuse.json +0 -34
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/022-multi-valued-content-type.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/024-unquoted-string-param.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/026-non-ascii-host.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/001-basic-post.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/002-post-with-content-digest.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/003-es256-post.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/004-multiple-signature-labels.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/005-default-port-stripped.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/006-dot-segment-path.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/007-query-byte-preserved.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/008-percent-encoded-path.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/011-ipv6-authority.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/README.md +0 -211
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/keys.json +0 -61
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/001-wrong-tag.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/002-expired-signature.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/003-window-too-long.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/005-missing-authority-component.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/006-missing-content-digest.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/007-unknown-keyid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/011-signature-without-input.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/012-missing-expires-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/013-expires-le-created.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/015-signature-invalid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/016-replayed-nonce.json +0 -37
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/017-key-revoked.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/018-rate-abuse.json +0 -33
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/019-revocation-stale.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +0 -41
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/001-basic-post.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/002-es256-post.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/004-default-port-stripped.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +0 -25
- package/compliance/cache/3.1.0-beta.7/universal/billing-gate-dispatch.yaml +0 -450
- package/compliance/cache/3.1.0-beta.7/universal/canonical-format-validate-input.yaml +0 -640
- package/compliance/cache/3.1.0-beta.7/universal/capability-discovery.yaml +0 -125
- package/compliance/cache/3.1.0-beta.7/universal/collection-lists-pagination-integrity.yaml +0 -306
- package/compliance/cache/3.1.0-beta.7/universal/comply-controller-mode-gate.yaml +0 -141
- package/compliance/cache/3.1.0-beta.7/universal/content-standards-pagination-integrity.yaml +0 -326
- package/compliance/cache/3.1.0-beta.7/universal/deterministic-testing.yaml +0 -1430
- package/compliance/cache/3.1.0-beta.7/universal/error-compliance-signals.yaml +0 -377
- package/compliance/cache/3.1.0-beta.7/universal/error-compliance.yaml +0 -528
- package/compliance/cache/3.1.0-beta.7/universal/fictional-entities.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/universal/get-media-buys-pagination-integrity.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/universal/get-signals-pagination-integrity.yaml +0 -211
- package/compliance/cache/3.1.0-beta.7/universal/idempotency.yaml +0 -861
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-event-scope.yaml +0 -119
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-lifecycle.yaml +0 -337
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-rejections.yaml +0 -107
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-creative-formats.yaml +0 -265
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-list-accounts.yaml +0 -245
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity.yaml +0 -263
- package/compliance/cache/3.1.0-beta.7/universal/property-lists-pagination-integrity.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/universal/read-tool-idempotency.yaml +0 -405
- package/compliance/cache/3.1.0-beta.7/universal/runner-output-contract.yaml +0 -1266
- package/compliance/cache/3.1.0-beta.7/universal/schema-validation-signals.yaml +0 -181
- package/compliance/cache/3.1.0-beta.7/universal/schema-validation.yaml +0 -548
- package/compliance/cache/3.1.0-beta.7/universal/security.yaml +0 -539
- package/compliance/cache/3.1.0-beta.7/universal/signed-requests.yaml +0 -217
- package/compliance/cache/3.1.0-beta.7/universal/stale-response-advisory.yaml +0 -295
- package/compliance/cache/3.1.0-beta.7/universal/storyboard-schema.yaml +0 -2136
- package/compliance/cache/3.1.0-beta.7/universal/v3-envelope-integrity.yaml +0 -117
- package/compliance/cache/3.1.0-beta.7/universal/version-negotiation.yaml +0 -130
- package/compliance/cache/3.1.0-beta.7/universal/webhook-emission.yaml +0 -411
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-bulk-webhooks.yaml +0 -82
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-product-webhooks.yaml +0 -83
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-products.yaml +0 -151
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signal-webhooks.yaml +0 -83
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signals.yaml +0 -149
- package/dist/lib/types/v3-1-beta/index.d.mts +0 -1
- package/dist/lib/types/v3-1-beta/index.d.ts +0 -1
- package/dist/lib/types/v3-1-beta/index.mjs +0 -1
- package/dist/lib/types/v3-1-beta/tools.generated.d.mts +0 -26788
- package/dist/lib/types/v3-1-beta/tools.generated.d.ts +0 -26788
- /package/dist/lib/{types/v3-1-beta/tools.generated.mjs → media-buy/action-types.mjs} +0 -0
|
@@ -32,6 +32,7 @@ function createPostgresPersistentNotificationRuntime(options) {
|
|
|
32
32
|
store,
|
|
33
33
|
proofAdapter: options.proofAdapter,
|
|
34
34
|
...options.credentialAdapter === void 0 ? {} : { credentialAdapter: options.credentialAdapter },
|
|
35
|
+
...options.checkpointDeliveryAttempt === void 0 ? {} : { checkpointDeliveryAttempt: options.checkpointDeliveryAttempt },
|
|
35
36
|
authorizeDelivery: options.authorizeDelivery,
|
|
36
37
|
...options.validateDestination === void 0 ? {} : { validateDestination: options.validateDestination },
|
|
37
38
|
...options.supportedCallerEventTypes === void 0 ? {} : { supportedCallerEventTypes: options.supportedCallerEventTypes },
|
|
@@ -14,6 +14,7 @@ function createPostgresPersistentNotificationRuntime(options) {
|
|
|
14
14
|
store,
|
|
15
15
|
proofAdapter: options.proofAdapter,
|
|
16
16
|
...options.credentialAdapter === void 0 ? {} : { credentialAdapter: options.credentialAdapter },
|
|
17
|
+
...options.checkpointDeliveryAttempt === void 0 ? {} : { checkpointDeliveryAttempt: options.checkpointDeliveryAttempt },
|
|
17
18
|
authorizeDelivery: options.authorizeDelivery,
|
|
18
19
|
...options.validateDestination === void 0 ? {} : { validateDestination: options.validateDestination },
|
|
19
20
|
...options.supportedCallerEventTypes === void 0 ? {} : { supportedCallerEventTypes: options.supportedCallerEventTypes },
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { WebhookAttemptSuppressionReason } from '../webhook-emitter.mjs';
|
|
2
|
+
import type { NotificationSubscriptionConfigInput, NotificationSubscriptionView, NotificationSuppressionDisposition, PersistentNotificationRuntime, PersistentNotificationRuntimeOptions } from './types.mjs';
|
|
2
3
|
export declare const CALLER_NOTIFICATION_TYPES: readonly ["capabilities.changed", "principal.changed"];
|
|
3
4
|
export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
|
|
4
5
|
/**
|
|
@@ -10,6 +11,16 @@ export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_chan
|
|
|
10
11
|
export declare function createPersistentNotificationRuntime(options: PersistentNotificationRuntimeOptions): PersistentNotificationRuntime;
|
|
11
12
|
/** Strip SDK operational generations for generated AdCP response projections. */
|
|
12
13
|
export declare function projectNotificationSubscriptionReadback(views: readonly NotificationSubscriptionView[]): NotificationSubscriptionConfigInput[];
|
|
14
|
+
/**
|
|
15
|
+
* Classifies a live-authority suppression so an emission owner can tell a
|
|
16
|
+
* deliberate decision not to deliver from an operational failure.
|
|
17
|
+
*
|
|
18
|
+
* Treating every suppression as terminal silently drops notifications whenever
|
|
19
|
+
* a store read or an authorization/credential callback has a bad minute, and
|
|
20
|
+
* treating every suppression as retryable poisons the queue for a subscriber
|
|
21
|
+
* that was legitimately revoked or denied.
|
|
22
|
+
*/
|
|
23
|
+
export declare function notificationSuppressionDisposition(reason: WebhookAttemptSuppressionReason): NotificationSuppressionDisposition;
|
|
13
24
|
/** Point-in-time registration validation; delivery still re-resolves and pins every attempt. */
|
|
14
25
|
export declare function validatePersistentNotificationDestination(input: {
|
|
15
26
|
url: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { WebhookAttemptSuppressionReason } from '../webhook-emitter';
|
|
2
|
+
import type { NotificationSubscriptionConfigInput, NotificationSubscriptionView, NotificationSuppressionDisposition, PersistentNotificationRuntime, PersistentNotificationRuntimeOptions } from './types';
|
|
2
3
|
export declare const CALLER_NOTIFICATION_TYPES: readonly ["capabilities.changed", "principal.changed"];
|
|
3
4
|
export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_changed", "creative.assignment_changed", "indicators.changed", "creative.purged", "account.status_changed", "account.change_recorded", "product.created", "product.updated", "product.priced", "product.removed", "signal.created", "signal.updated", "signal.priced", "signal.removed", "wholesale_feed.bulk_change", "reporting.delivery_ready", "reporting.status_changed", "reporting.ledger_changed"];
|
|
4
5
|
/**
|
|
@@ -10,6 +11,16 @@ export declare const ACCOUNT_NOTIFICATION_TYPES: readonly ["creative.status_chan
|
|
|
10
11
|
export declare function createPersistentNotificationRuntime(options: PersistentNotificationRuntimeOptions): PersistentNotificationRuntime;
|
|
11
12
|
/** Strip SDK operational generations for generated AdCP response projections. */
|
|
12
13
|
export declare function projectNotificationSubscriptionReadback(views: readonly NotificationSubscriptionView[]): NotificationSubscriptionConfigInput[];
|
|
14
|
+
/**
|
|
15
|
+
* Classifies a live-authority suppression so an emission owner can tell a
|
|
16
|
+
* deliberate decision not to deliver from an operational failure.
|
|
17
|
+
*
|
|
18
|
+
* Treating every suppression as terminal silently drops notifications whenever
|
|
19
|
+
* a store read or an authorization/credential callback has a bad minute, and
|
|
20
|
+
* treating every suppression as retryable poisons the queue for a subscriber
|
|
21
|
+
* that was legitimately revoked or denied.
|
|
22
|
+
*/
|
|
23
|
+
export declare function notificationSuppressionDisposition(reason: WebhookAttemptSuppressionReason): NotificationSuppressionDisposition;
|
|
13
24
|
/** Point-in-time registration validation; delivery still re-resolves and pins every attempt. */
|
|
14
25
|
export declare function validatePersistentNotificationDestination(input: {
|
|
15
26
|
url: string;
|
|
@@ -21,6 +21,7 @@ __export(runtime_exports, {
|
|
|
21
21
|
ACCOUNT_NOTIFICATION_TYPES: () => ACCOUNT_NOTIFICATION_TYPES,
|
|
22
22
|
CALLER_NOTIFICATION_TYPES: () => CALLER_NOTIFICATION_TYPES,
|
|
23
23
|
createPersistentNotificationRuntime: () => createPersistentNotificationRuntime,
|
|
24
|
+
notificationSuppressionDisposition: () => notificationSuppressionDisposition,
|
|
24
25
|
projectNotificationSubscriptionReadback: () => projectNotificationSubscriptionReadback,
|
|
25
26
|
validatePersistentNotificationDestination: () => validatePersistentNotificationDestination
|
|
26
27
|
});
|
|
@@ -28,6 +29,7 @@ module.exports = __toCommonJS(runtime_exports);
|
|
|
28
29
|
var import_node_crypto = require("node:crypto");
|
|
29
30
|
var import_promises = require("node:dns/promises");
|
|
30
31
|
var import_jcs = require('../../utils/jcs.js');
|
|
32
|
+
var import_common = require('../webhook-delivery/common.js');
|
|
31
33
|
var import_ssrf = require('../../substitution/observer/ssrf.js');
|
|
32
34
|
var import_pin_and_bind_fetch = require('../pin-and-bind-fetch.js');
|
|
33
35
|
var import_types = require('./types.js');
|
|
@@ -96,6 +98,30 @@ function createPersistentNotificationRuntime(options) {
|
|
|
96
98
|
...futureCallerInvalidationEventTypes
|
|
97
99
|
]);
|
|
98
100
|
const validateDestination = options.validateDestination ?? validatePersistentNotificationDestination;
|
|
101
|
+
const checkpointAttempt = async (context) => {
|
|
102
|
+
if (!options.checkpointDeliveryAttempt) return true;
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
try {
|
|
105
|
+
await options.checkpointDeliveryAttempt({
|
|
106
|
+
scope: structuredClone(context.scope),
|
|
107
|
+
eventAnchor: context.eventAnchor,
|
|
108
|
+
...context.accountId === void 0 ? {} : { accountId: context.accountId },
|
|
109
|
+
subscriberId: context.subscriberId,
|
|
110
|
+
destinationGeneration: context.destinationGeneration,
|
|
111
|
+
eventType: context.eventType,
|
|
112
|
+
notificationId: context.notificationId,
|
|
113
|
+
signal: controller.signal
|
|
114
|
+
});
|
|
115
|
+
return true;
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const suppress = (reason) => ({
|
|
121
|
+
decision: "suppress",
|
|
122
|
+
reason,
|
|
123
|
+
...notificationSuppressionDisposition(reason) === "retryable" ? { retryable: true } : {}
|
|
124
|
+
});
|
|
99
125
|
const authorizeWebhookAttempt = async (attempt) => {
|
|
100
126
|
const context = parseAttemptContext(attempt.attemptAuthorizationContext);
|
|
101
127
|
if (!context) return { decision: "suppress", reason: "authorization_error" };
|
|
@@ -103,22 +129,22 @@ function createPersistentNotificationRuntime(options) {
|
|
|
103
129
|
try {
|
|
104
130
|
set = await options.store.get(context.scope);
|
|
105
131
|
} catch {
|
|
106
|
-
return
|
|
132
|
+
return suppress("authorization_error");
|
|
107
133
|
}
|
|
108
|
-
if (!set) return
|
|
134
|
+
if (!set) return suppress("subscription_missing");
|
|
109
135
|
const subscription = set.subscriptions.find((item) => item.subscriberId === context.subscriberId);
|
|
110
|
-
if (!subscription) return
|
|
136
|
+
if (!subscription) return suppress("subscription_missing");
|
|
111
137
|
if (subscription.destinationGeneration !== context.destinationGeneration) {
|
|
112
|
-
return { decision: "suppress", reason: "subscription_stale" };
|
|
138
|
+
return attempt.recovered === true ? { decision: "suppress", reason: "subscription_stale" } : suppress("subscription_stale");
|
|
113
139
|
}
|
|
114
140
|
if (!subscription.active || subscription.proofGeneration !== subscription.destinationGeneration) {
|
|
115
|
-
return
|
|
141
|
+
return suppress("subscription_inactive");
|
|
116
142
|
}
|
|
117
143
|
if (!subscription.eventTypes.includes(context.eventType) && !(context.futureCallerInvalidation === true && futureCallerInvalidationEventTypes.has(context.eventType) && subscription.includeFutureEventTypes)) {
|
|
118
|
-
return
|
|
144
|
+
return suppress("event_not_allowed");
|
|
119
145
|
}
|
|
120
146
|
if (context.eventAnchor === "account" && !context.accountId || context.eventAnchor === "caller" && context.accountId !== void 0 || context.scope.kind === "account" && (context.eventAnchor !== "account" || context.scope.accountId !== context.accountId) || context.scope.kind === "caller" && context.eventAnchor === "account" && !subscription.allAuthorizedAccounts) {
|
|
121
|
-
return
|
|
147
|
+
return suppress("event_not_allowed");
|
|
122
148
|
}
|
|
123
149
|
let decision;
|
|
124
150
|
try {
|
|
@@ -137,16 +163,17 @@ function createPersistentNotificationRuntime(options) {
|
|
|
137
163
|
})
|
|
138
164
|
);
|
|
139
165
|
} catch {
|
|
140
|
-
return
|
|
166
|
+
return suppress("authorization_error");
|
|
141
167
|
}
|
|
142
|
-
if (decision?.authorized !== true) return
|
|
168
|
+
if (decision?.authorized !== true) return suppress("authorization_denied");
|
|
143
169
|
const authenticationMode = subscription.authentication.mode;
|
|
144
170
|
if (authenticationMode === "rfc9421") {
|
|
171
|
+
if (!await checkpointAttempt(context)) return suppress("attempt_checkpoint_unavailable");
|
|
145
172
|
return { decision: "allow", authentication: null };
|
|
146
173
|
}
|
|
147
174
|
const bindingId = subscription.authentication.bindingId;
|
|
148
175
|
if (!bindingId || !options.credentialAdapter) {
|
|
149
|
-
return
|
|
176
|
+
return suppress("credential_unavailable");
|
|
150
177
|
}
|
|
151
178
|
try {
|
|
152
179
|
const authentication = await runAdopterCallback(
|
|
@@ -162,11 +189,12 @@ function createPersistentNotificationRuntime(options) {
|
|
|
162
189
|
})
|
|
163
190
|
);
|
|
164
191
|
if (!resolvedAuthenticationMatches(authenticationMode, authentication)) {
|
|
165
|
-
return
|
|
192
|
+
return suppress("credential_unavailable");
|
|
166
193
|
}
|
|
194
|
+
if (!await checkpointAttempt(context)) return suppress("attempt_checkpoint_unavailable");
|
|
167
195
|
return { decision: "allow", authentication };
|
|
168
196
|
} catch {
|
|
169
|
-
return
|
|
197
|
+
return suppress("credential_unavailable");
|
|
170
198
|
}
|
|
171
199
|
};
|
|
172
200
|
const emitter = options.createEmitter(authorizeWebhookAttempt);
|
|
@@ -177,6 +205,8 @@ function createPersistentNotificationRuntime(options) {
|
|
|
177
205
|
store: options.store,
|
|
178
206
|
emitter,
|
|
179
207
|
authorizeWebhookAttempt,
|
|
208
|
+
hasDeliveryAttemptCheckpoint: options.checkpointDeliveryAttempt !== void 0,
|
|
209
|
+
...options.checkpointDeliveryAttempt === void 0 ? {} : { deliveryAttemptCheckpoint: options.checkpointDeliveryAttempt },
|
|
180
210
|
async replace(scope, configs, replaceOptions = {}) {
|
|
181
211
|
assertScope(scope);
|
|
182
212
|
assertUniqueSubscribers(configs);
|
|
@@ -316,14 +346,15 @@ function createPersistentNotificationRuntime(options) {
|
|
|
316
346
|
if (candidateSets.length > maxFanoutCandidates) {
|
|
317
347
|
throw new Error("Persistent notification fanout exceeded maxFanoutCandidates; no deliveries were attempted");
|
|
318
348
|
}
|
|
319
|
-
const
|
|
349
|
+
const resolved = candidateSets.flatMap(
|
|
320
350
|
(set) => set.subscriptions.filter(
|
|
321
351
|
(subscription) => subscription.active && subscription.proofGeneration === subscription.destinationGeneration && (subscription.eventTypes.includes(event.notificationType) || futureCallerInvalidation && subscription.includeFutureEventTypes) && (set.scope.kind !== "caller" || event.anchor !== "account" || subscription.allAuthorizedAccounts)
|
|
322
352
|
).map((subscription) => ({ set, subscription }))
|
|
323
353
|
);
|
|
324
|
-
if (
|
|
354
|
+
if (resolved.length > maxFanoutCandidates) {
|
|
325
355
|
throw new Error("Persistent notification fanout exceeded maxFanoutCandidates; no deliveries were attempted");
|
|
326
356
|
}
|
|
357
|
+
const targets = event.freezeRecipients ? await pinResolvedRecipients(resolved, event.freezeRecipients) : resolved;
|
|
327
358
|
const deliveries = await mapConcurrent(targets, fanoutConcurrency, async ({ set, subscription }) => {
|
|
328
359
|
const deliveryId = deliveryIdentity(event.emissionId, set.scope, subscription);
|
|
329
360
|
const payload = notificationPayload(event, subscription.subscriberId);
|
|
@@ -353,10 +384,10 @@ function createPersistentNotificationRuntime(options) {
|
|
|
353
384
|
attemptAuthorizationContext: context
|
|
354
385
|
});
|
|
355
386
|
return { ...delivery, result };
|
|
356
|
-
} catch {
|
|
387
|
+
} catch (error) {
|
|
357
388
|
return {
|
|
358
389
|
...delivery,
|
|
359
|
-
failure: { reason: "delivery_runtime_error" }
|
|
390
|
+
failure: (0, import_common.isWebhookDeliveryTerminalError)(error) ? { reason: "delivery_binding_retired", terminal: true } : { reason: "delivery_runtime_error" }
|
|
360
391
|
};
|
|
361
392
|
}
|
|
362
393
|
});
|
|
@@ -622,6 +653,60 @@ function assertPayloadField(payload, field, expected) {
|
|
|
622
653
|
);
|
|
623
654
|
}
|
|
624
655
|
}
|
|
656
|
+
async function pinResolvedRecipients(resolved, freezeRecipients) {
|
|
657
|
+
const frozen = await freezeRecipients(
|
|
658
|
+
resolved.map((target) => ({
|
|
659
|
+
scope: structuredClone(target.set.scope),
|
|
660
|
+
subscriberId: target.subscription.subscriberId,
|
|
661
|
+
destinationGeneration: target.subscription.destinationGeneration
|
|
662
|
+
}))
|
|
663
|
+
);
|
|
664
|
+
if (!Array.isArray(frozen)) {
|
|
665
|
+
throw new TypeError("freezeRecipients must return the durably committed recipient set");
|
|
666
|
+
}
|
|
667
|
+
const committed = new Set(
|
|
668
|
+
frozen.map((recipient) => {
|
|
669
|
+
if (!recipient || typeof recipient.subscriberId !== "string" || typeof recipient.destinationGeneration !== "string" || !recipient.scope) {
|
|
670
|
+
throw new TypeError("freezeRecipients returned a malformed recipient reference");
|
|
671
|
+
}
|
|
672
|
+
return recipientKey(recipient);
|
|
673
|
+
})
|
|
674
|
+
);
|
|
675
|
+
return resolved.filter(
|
|
676
|
+
(target) => committed.has(
|
|
677
|
+
recipientKey({
|
|
678
|
+
scope: target.set.scope,
|
|
679
|
+
subscriberId: target.subscription.subscriberId,
|
|
680
|
+
destinationGeneration: target.subscription.destinationGeneration
|
|
681
|
+
})
|
|
682
|
+
)
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
function notificationSuppressionDisposition(reason) {
|
|
686
|
+
switch (reason) {
|
|
687
|
+
case "authorization_error":
|
|
688
|
+
case "credential_unavailable":
|
|
689
|
+
return "retryable";
|
|
690
|
+
case "subscription_stale":
|
|
691
|
+
return "retryable";
|
|
692
|
+
case "attempt_checkpoint_unavailable":
|
|
693
|
+
return "retryable";
|
|
694
|
+
case "subscription_missing":
|
|
695
|
+
case "subscription_inactive":
|
|
696
|
+
case "event_not_allowed":
|
|
697
|
+
case "authorization_denied":
|
|
698
|
+
return "terminal";
|
|
699
|
+
default:
|
|
700
|
+
return "retryable";
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function recipientKey(recipient) {
|
|
704
|
+
return (0, import_jcs.canonicalJsonSha256)({
|
|
705
|
+
scope: recipient.scope,
|
|
706
|
+
subscriberId: recipient.subscriberId,
|
|
707
|
+
destinationGeneration: recipient.destinationGeneration
|
|
708
|
+
});
|
|
709
|
+
}
|
|
625
710
|
function deliveryIdentity(emissionId, scope, subscription) {
|
|
626
711
|
return `notification_${(0, import_jcs.canonicalJsonSha256)({
|
|
627
712
|
emissionId,
|
|
@@ -844,6 +929,7 @@ function validation(message, index, field) {
|
|
|
844
929
|
ACCOUNT_NOTIFICATION_TYPES,
|
|
845
930
|
CALLER_NOTIFICATION_TYPES,
|
|
846
931
|
createPersistentNotificationRuntime,
|
|
932
|
+
notificationSuppressionDisposition,
|
|
847
933
|
projectNotificationSubscriptionReadback,
|
|
848
934
|
validatePersistentNotificationDestination
|
|
849
935
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { lookup } from "node:dns/promises";
|
|
3
3
|
import { canonicalJsonSha256 } from "../../utils/jcs.mjs";
|
|
4
|
+
import { isWebhookDeliveryTerminalError } from "../webhook-delivery/common.mjs";
|
|
4
5
|
import { enforceSsrfPolicy, enforceSsrfPolicyResolved } from "../../substitution/observer/ssrf.mjs";
|
|
5
6
|
import { WEBHOOK_SSRF_POLICY } from "../pin-and-bind-fetch.mjs";
|
|
6
7
|
import { NotificationSubscriptionValidationError } from "./types.mjs";
|
|
@@ -69,6 +70,30 @@ function createPersistentNotificationRuntime(options) {
|
|
|
69
70
|
...futureCallerInvalidationEventTypes
|
|
70
71
|
]);
|
|
71
72
|
const validateDestination = options.validateDestination ?? validatePersistentNotificationDestination;
|
|
73
|
+
const checkpointAttempt = async (context) => {
|
|
74
|
+
if (!options.checkpointDeliveryAttempt) return true;
|
|
75
|
+
const controller = new AbortController();
|
|
76
|
+
try {
|
|
77
|
+
await options.checkpointDeliveryAttempt({
|
|
78
|
+
scope: structuredClone(context.scope),
|
|
79
|
+
eventAnchor: context.eventAnchor,
|
|
80
|
+
...context.accountId === void 0 ? {} : { accountId: context.accountId },
|
|
81
|
+
subscriberId: context.subscriberId,
|
|
82
|
+
destinationGeneration: context.destinationGeneration,
|
|
83
|
+
eventType: context.eventType,
|
|
84
|
+
notificationId: context.notificationId,
|
|
85
|
+
signal: controller.signal
|
|
86
|
+
});
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const suppress = (reason) => ({
|
|
93
|
+
decision: "suppress",
|
|
94
|
+
reason,
|
|
95
|
+
...notificationSuppressionDisposition(reason) === "retryable" ? { retryable: true } : {}
|
|
96
|
+
});
|
|
72
97
|
const authorizeWebhookAttempt = async (attempt) => {
|
|
73
98
|
const context = parseAttemptContext(attempt.attemptAuthorizationContext);
|
|
74
99
|
if (!context) return { decision: "suppress", reason: "authorization_error" };
|
|
@@ -76,22 +101,22 @@ function createPersistentNotificationRuntime(options) {
|
|
|
76
101
|
try {
|
|
77
102
|
set = await options.store.get(context.scope);
|
|
78
103
|
} catch {
|
|
79
|
-
return
|
|
104
|
+
return suppress("authorization_error");
|
|
80
105
|
}
|
|
81
|
-
if (!set) return
|
|
106
|
+
if (!set) return suppress("subscription_missing");
|
|
82
107
|
const subscription = set.subscriptions.find((item) => item.subscriberId === context.subscriberId);
|
|
83
|
-
if (!subscription) return
|
|
108
|
+
if (!subscription) return suppress("subscription_missing");
|
|
84
109
|
if (subscription.destinationGeneration !== context.destinationGeneration) {
|
|
85
|
-
return { decision: "suppress", reason: "subscription_stale" };
|
|
110
|
+
return attempt.recovered === true ? { decision: "suppress", reason: "subscription_stale" } : suppress("subscription_stale");
|
|
86
111
|
}
|
|
87
112
|
if (!subscription.active || subscription.proofGeneration !== subscription.destinationGeneration) {
|
|
88
|
-
return
|
|
113
|
+
return suppress("subscription_inactive");
|
|
89
114
|
}
|
|
90
115
|
if (!subscription.eventTypes.includes(context.eventType) && !(context.futureCallerInvalidation === true && futureCallerInvalidationEventTypes.has(context.eventType) && subscription.includeFutureEventTypes)) {
|
|
91
|
-
return
|
|
116
|
+
return suppress("event_not_allowed");
|
|
92
117
|
}
|
|
93
118
|
if (context.eventAnchor === "account" && !context.accountId || context.eventAnchor === "caller" && context.accountId !== void 0 || context.scope.kind === "account" && (context.eventAnchor !== "account" || context.scope.accountId !== context.accountId) || context.scope.kind === "caller" && context.eventAnchor === "account" && !subscription.allAuthorizedAccounts) {
|
|
94
|
-
return
|
|
119
|
+
return suppress("event_not_allowed");
|
|
95
120
|
}
|
|
96
121
|
let decision;
|
|
97
122
|
try {
|
|
@@ -110,16 +135,17 @@ function createPersistentNotificationRuntime(options) {
|
|
|
110
135
|
})
|
|
111
136
|
);
|
|
112
137
|
} catch {
|
|
113
|
-
return
|
|
138
|
+
return suppress("authorization_error");
|
|
114
139
|
}
|
|
115
|
-
if (decision?.authorized !== true) return
|
|
140
|
+
if (decision?.authorized !== true) return suppress("authorization_denied");
|
|
116
141
|
const authenticationMode = subscription.authentication.mode;
|
|
117
142
|
if (authenticationMode === "rfc9421") {
|
|
143
|
+
if (!await checkpointAttempt(context)) return suppress("attempt_checkpoint_unavailable");
|
|
118
144
|
return { decision: "allow", authentication: null };
|
|
119
145
|
}
|
|
120
146
|
const bindingId = subscription.authentication.bindingId;
|
|
121
147
|
if (!bindingId || !options.credentialAdapter) {
|
|
122
|
-
return
|
|
148
|
+
return suppress("credential_unavailable");
|
|
123
149
|
}
|
|
124
150
|
try {
|
|
125
151
|
const authentication = await runAdopterCallback(
|
|
@@ -135,11 +161,12 @@ function createPersistentNotificationRuntime(options) {
|
|
|
135
161
|
})
|
|
136
162
|
);
|
|
137
163
|
if (!resolvedAuthenticationMatches(authenticationMode, authentication)) {
|
|
138
|
-
return
|
|
164
|
+
return suppress("credential_unavailable");
|
|
139
165
|
}
|
|
166
|
+
if (!await checkpointAttempt(context)) return suppress("attempt_checkpoint_unavailable");
|
|
140
167
|
return { decision: "allow", authentication };
|
|
141
168
|
} catch {
|
|
142
|
-
return
|
|
169
|
+
return suppress("credential_unavailable");
|
|
143
170
|
}
|
|
144
171
|
};
|
|
145
172
|
const emitter = options.createEmitter(authorizeWebhookAttempt);
|
|
@@ -150,6 +177,8 @@ function createPersistentNotificationRuntime(options) {
|
|
|
150
177
|
store: options.store,
|
|
151
178
|
emitter,
|
|
152
179
|
authorizeWebhookAttempt,
|
|
180
|
+
hasDeliveryAttemptCheckpoint: options.checkpointDeliveryAttempt !== void 0,
|
|
181
|
+
...options.checkpointDeliveryAttempt === void 0 ? {} : { deliveryAttemptCheckpoint: options.checkpointDeliveryAttempt },
|
|
153
182
|
async replace(scope, configs, replaceOptions = {}) {
|
|
154
183
|
assertScope(scope);
|
|
155
184
|
assertUniqueSubscribers(configs);
|
|
@@ -289,14 +318,15 @@ function createPersistentNotificationRuntime(options) {
|
|
|
289
318
|
if (candidateSets.length > maxFanoutCandidates) {
|
|
290
319
|
throw new Error("Persistent notification fanout exceeded maxFanoutCandidates; no deliveries were attempted");
|
|
291
320
|
}
|
|
292
|
-
const
|
|
321
|
+
const resolved = candidateSets.flatMap(
|
|
293
322
|
(set) => set.subscriptions.filter(
|
|
294
323
|
(subscription) => subscription.active && subscription.proofGeneration === subscription.destinationGeneration && (subscription.eventTypes.includes(event.notificationType) || futureCallerInvalidation && subscription.includeFutureEventTypes) && (set.scope.kind !== "caller" || event.anchor !== "account" || subscription.allAuthorizedAccounts)
|
|
295
324
|
).map((subscription) => ({ set, subscription }))
|
|
296
325
|
);
|
|
297
|
-
if (
|
|
326
|
+
if (resolved.length > maxFanoutCandidates) {
|
|
298
327
|
throw new Error("Persistent notification fanout exceeded maxFanoutCandidates; no deliveries were attempted");
|
|
299
328
|
}
|
|
329
|
+
const targets = event.freezeRecipients ? await pinResolvedRecipients(resolved, event.freezeRecipients) : resolved;
|
|
300
330
|
const deliveries = await mapConcurrent(targets, fanoutConcurrency, async ({ set, subscription }) => {
|
|
301
331
|
const deliveryId = deliveryIdentity(event.emissionId, set.scope, subscription);
|
|
302
332
|
const payload = notificationPayload(event, subscription.subscriberId);
|
|
@@ -326,10 +356,10 @@ function createPersistentNotificationRuntime(options) {
|
|
|
326
356
|
attemptAuthorizationContext: context
|
|
327
357
|
});
|
|
328
358
|
return { ...delivery, result };
|
|
329
|
-
} catch {
|
|
359
|
+
} catch (error) {
|
|
330
360
|
return {
|
|
331
361
|
...delivery,
|
|
332
|
-
failure: { reason: "delivery_runtime_error" }
|
|
362
|
+
failure: isWebhookDeliveryTerminalError(error) ? { reason: "delivery_binding_retired", terminal: true } : { reason: "delivery_runtime_error" }
|
|
333
363
|
};
|
|
334
364
|
}
|
|
335
365
|
});
|
|
@@ -595,6 +625,60 @@ function assertPayloadField(payload, field, expected) {
|
|
|
595
625
|
);
|
|
596
626
|
}
|
|
597
627
|
}
|
|
628
|
+
async function pinResolvedRecipients(resolved, freezeRecipients) {
|
|
629
|
+
const frozen = await freezeRecipients(
|
|
630
|
+
resolved.map((target) => ({
|
|
631
|
+
scope: structuredClone(target.set.scope),
|
|
632
|
+
subscriberId: target.subscription.subscriberId,
|
|
633
|
+
destinationGeneration: target.subscription.destinationGeneration
|
|
634
|
+
}))
|
|
635
|
+
);
|
|
636
|
+
if (!Array.isArray(frozen)) {
|
|
637
|
+
throw new TypeError("freezeRecipients must return the durably committed recipient set");
|
|
638
|
+
}
|
|
639
|
+
const committed = new Set(
|
|
640
|
+
frozen.map((recipient) => {
|
|
641
|
+
if (!recipient || typeof recipient.subscriberId !== "string" || typeof recipient.destinationGeneration !== "string" || !recipient.scope) {
|
|
642
|
+
throw new TypeError("freezeRecipients returned a malformed recipient reference");
|
|
643
|
+
}
|
|
644
|
+
return recipientKey(recipient);
|
|
645
|
+
})
|
|
646
|
+
);
|
|
647
|
+
return resolved.filter(
|
|
648
|
+
(target) => committed.has(
|
|
649
|
+
recipientKey({
|
|
650
|
+
scope: target.set.scope,
|
|
651
|
+
subscriberId: target.subscription.subscriberId,
|
|
652
|
+
destinationGeneration: target.subscription.destinationGeneration
|
|
653
|
+
})
|
|
654
|
+
)
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
function notificationSuppressionDisposition(reason) {
|
|
658
|
+
switch (reason) {
|
|
659
|
+
case "authorization_error":
|
|
660
|
+
case "credential_unavailable":
|
|
661
|
+
return "retryable";
|
|
662
|
+
case "subscription_stale":
|
|
663
|
+
return "retryable";
|
|
664
|
+
case "attempt_checkpoint_unavailable":
|
|
665
|
+
return "retryable";
|
|
666
|
+
case "subscription_missing":
|
|
667
|
+
case "subscription_inactive":
|
|
668
|
+
case "event_not_allowed":
|
|
669
|
+
case "authorization_denied":
|
|
670
|
+
return "terminal";
|
|
671
|
+
default:
|
|
672
|
+
return "retryable";
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function recipientKey(recipient) {
|
|
676
|
+
return canonicalJsonSha256({
|
|
677
|
+
scope: recipient.scope,
|
|
678
|
+
subscriberId: recipient.subscriberId,
|
|
679
|
+
destinationGeneration: recipient.destinationGeneration
|
|
680
|
+
});
|
|
681
|
+
}
|
|
598
682
|
function deliveryIdentity(emissionId, scope, subscription) {
|
|
599
683
|
return `notification_${canonicalJsonSha256({
|
|
600
684
|
emissionId,
|
|
@@ -816,6 +900,7 @@ export {
|
|
|
816
900
|
ACCOUNT_NOTIFICATION_TYPES,
|
|
817
901
|
CALLER_NOTIFICATION_TYPES,
|
|
818
902
|
createPersistentNotificationRuntime,
|
|
903
|
+
notificationSuppressionDisposition,
|
|
819
904
|
projectNotificationSubscriptionReadback,
|
|
820
905
|
validatePersistentNotificationDestination
|
|
821
906
|
};
|
|
@@ -208,6 +208,16 @@ export type NotificationDeliveryAuthorizer = (input: Readonly<NotificationDelive
|
|
|
208
208
|
} | {
|
|
209
209
|
authorized: false;
|
|
210
210
|
}>;
|
|
211
|
+
/**
|
|
212
|
+
* One resolved delivery target. Together with the event's `emissionId` these
|
|
213
|
+
* three fields are exactly the inputs to the per-subscriber delivery identity,
|
|
214
|
+
* so pinning them pins the idempotency key the subscriber sees.
|
|
215
|
+
*/
|
|
216
|
+
export interface NotificationRecipientRef {
|
|
217
|
+
scope: NotificationSubscriptionScope;
|
|
218
|
+
subscriberId: string;
|
|
219
|
+
destinationGeneration: string;
|
|
220
|
+
}
|
|
211
221
|
export interface NotificationEvent {
|
|
212
222
|
/** Application-stable identity for this delivery event; reuse on crash retry, rotate on re-emission. */
|
|
213
223
|
emissionId: string;
|
|
@@ -221,7 +231,69 @@ export interface NotificationEvent {
|
|
|
221
231
|
/** Required for account-anchored events. */
|
|
222
232
|
accountId?: string;
|
|
223
233
|
payload: Record<string, unknown>;
|
|
234
|
+
/**
|
|
235
|
+
* Durably freezes the recipient set before any external send.
|
|
236
|
+
*
|
|
237
|
+
* The runtime resolves its candidates, hands them to this callback, and then
|
|
238
|
+
* delivers to exactly the intersection of those candidates and what the
|
|
239
|
+
* callback returns. An emitter that persists the first resolved set and
|
|
240
|
+
* replays it verbatim therefore keeps every `delivery_id` — and so every
|
|
241
|
+
* subscriber-visible idempotency key — stable across an ambiguous retry: a
|
|
242
|
+
* subscription replaced or revoked after the first send is skipped rather
|
|
243
|
+
* than addressed under a new destination generation, so a replay can never
|
|
244
|
+
* add a second logical delivery of the same notification.
|
|
245
|
+
*
|
|
246
|
+
* Called at most once per `emit`, before the first attempt. It is a
|
|
247
|
+
* durability barrier owned by the emitting subsystem, not an adopter policy
|
|
248
|
+
* hook, so it is deliberately not bounded by `adopterCallbackTimeoutMs`: the
|
|
249
|
+
* runtime cannot safely abandon a write that may still commit. Implementations
|
|
250
|
+
* must enforce their own transaction-level deadline. Throwing aborts the
|
|
251
|
+
* emission before anything is sent.
|
|
252
|
+
*/
|
|
253
|
+
freezeRecipients?: (candidates: readonly NotificationRecipientRef[]) => MaybePromise<readonly NotificationRecipientRef[]>;
|
|
224
254
|
}
|
|
255
|
+
/** Durable record that one recipient is about to receive an external POST. */
|
|
256
|
+
export interface NotificationDeliveryAttemptCheckpointInput {
|
|
257
|
+
scope: Readonly<NotificationSubscriptionScope>;
|
|
258
|
+
eventAnchor: NotificationEventAnchor;
|
|
259
|
+
accountId?: string;
|
|
260
|
+
subscriberId: string;
|
|
261
|
+
destinationGeneration: string;
|
|
262
|
+
eventType: string;
|
|
263
|
+
notificationId: string;
|
|
264
|
+
signal: AbortSignal;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Durably records that a delivery is about to be attempted, awaited on the
|
|
268
|
+
* allow path of live delivery authority immediately before every external POST.
|
|
269
|
+
*
|
|
270
|
+
* It is keyed on the durable attempt context rather than on a per-emission
|
|
271
|
+
* closure precisely so that recovered outbox attempts participate: an emission
|
|
272
|
+
* snapshot cannot carry a function, so a per-emission barrier would be silently
|
|
273
|
+
* skipped by the very path — a restarted outbox worker — where an ambiguous send
|
|
274
|
+
* is most likely.
|
|
275
|
+
*
|
|
276
|
+
* This is what makes a frozen recipient set safely revisable. Suppression fails
|
|
277
|
+
* closed before this point, so a recipient with no checkpoint provably never
|
|
278
|
+
* received a POST and may be replaced; a recipient with one is pinned forever,
|
|
279
|
+
* because a crash after it is an ambiguous send. Rejecting suppresses that
|
|
280
|
+
* delivery as retryable with no external attempt.
|
|
281
|
+
*/
|
|
282
|
+
export type NotificationDeliveryAttemptCheckpoint = (input: Readonly<NotificationDeliveryAttemptCheckpointInput>) => MaybePromise<void>;
|
|
283
|
+
/**
|
|
284
|
+
* Whether a live-authority suppression is a deliberate decision not to deliver
|
|
285
|
+
* or an operational failure that says nothing about the subscriber.
|
|
286
|
+
*
|
|
287
|
+
* `terminal` — the subscriber must not receive this event: it is gone, inactive,
|
|
288
|
+
* not subscribed to the type, or the adopter denied it. Settle the emission.
|
|
289
|
+
*
|
|
290
|
+
* `retryable` — the runtime could not establish authority: a store read failed,
|
|
291
|
+
* an authorization or credential callback threw or timed out, or the
|
|
292
|
+
* subscription generation moved while the emission was in flight. Nothing was
|
|
293
|
+
* sent (`attempts: 0`), so the owner must release and retry rather than record
|
|
294
|
+
* the notification as delivered.
|
|
295
|
+
*/
|
|
296
|
+
export type NotificationSuppressionDisposition = 'terminal' | 'retryable';
|
|
225
297
|
export interface NotificationSubscriptionView {
|
|
226
298
|
subscriber_id: string;
|
|
227
299
|
url: string;
|
|
@@ -264,8 +336,14 @@ export type NotificationFanoutDelivery = NotificationFanoutDeliveryBase & ({
|
|
|
264
336
|
failure?: never;
|
|
265
337
|
} | {
|
|
266
338
|
result?: never;
|
|
339
|
+
/**
|
|
340
|
+
* `delivery_binding_retired` is terminal: the delivery identity is
|
|
341
|
+
* retired or past its retry horizon and can never succeed. Anything
|
|
342
|
+
* else is an operational failure worth retrying.
|
|
343
|
+
*/
|
|
267
344
|
failure: {
|
|
268
|
-
reason: 'delivery_runtime_error';
|
|
345
|
+
reason: 'delivery_runtime_error' | 'delivery_binding_retired';
|
|
346
|
+
terminal?: boolean;
|
|
269
347
|
};
|
|
270
348
|
});
|
|
271
349
|
export interface NotificationFanoutResult {
|
|
@@ -279,6 +357,14 @@ export interface PersistentNotificationRuntimeOptions {
|
|
|
279
357
|
proofAdapter: NotificationProofAdapter;
|
|
280
358
|
credentialAdapter?: NotificationCredentialBindingAdapter;
|
|
281
359
|
authorizeDelivery: NotificationDeliveryAuthorizer;
|
|
360
|
+
/**
|
|
361
|
+
* Durable pre-POST checkpoint. Required by any emission owner that freezes a
|
|
362
|
+
* recipient set and needs to know whether a recipient was ever addressed;
|
|
363
|
+
* `PersistentNotificationRuntime.hasDeliveryAttemptCheckpoint` reports whether
|
|
364
|
+
* it is wired so such an owner can fail closed at startup instead of silently
|
|
365
|
+
* losing the guarantee.
|
|
366
|
+
*/
|
|
367
|
+
checkpointDeliveryAttempt?: NotificationDeliveryAttemptCheckpoint;
|
|
282
368
|
/** Defaults to DNS resolution plus the SDK's strict webhook SSRF policy. */
|
|
283
369
|
validateDestination?: NotificationDestinationValidator;
|
|
284
370
|
/** Build the emitter with the supplied mandatory per-attempt authorizer. */
|
|
@@ -317,6 +403,23 @@ export interface PersistentNotificationRuntime {
|
|
|
317
403
|
readonly store: NotificationSubscriptionStore;
|
|
318
404
|
readonly emitter: RecoverableWebhookEmitter;
|
|
319
405
|
readonly authorizeWebhookAttempt: WebhookAttemptAuthorizer;
|
|
406
|
+
/**
|
|
407
|
+
* True when a durable pre-POST attempt checkpoint is wired.
|
|
408
|
+
*
|
|
409
|
+
* Optional so a custom implementation written against an earlier release
|
|
410
|
+
* still satisfies this interface structurally. An emission owner that needs
|
|
411
|
+
* the checkpoint treats an absent flag as "not proven" and fails closed.
|
|
412
|
+
*/
|
|
413
|
+
readonly hasDeliveryAttemptCheckpoint?: boolean;
|
|
414
|
+
/**
|
|
415
|
+
* The checkpoint this runtime actually invokes, exposed so an emission owner
|
|
416
|
+
* can verify by identity that its own checkpoint is the one that runs.
|
|
417
|
+
* Declaring the capability is not the same as wiring the right function:
|
|
418
|
+
* two correctly-built checkpoints pointing at different stores each look
|
|
419
|
+
* valid in isolation, and the mismatch only shows up as deliveries that
|
|
420
|
+
* checkpoint nothing.
|
|
421
|
+
*/
|
|
422
|
+
readonly deliveryAttemptCheckpoint?: NotificationDeliveryAttemptCheckpoint;
|
|
320
423
|
replace(scope: Readonly<NotificationSubscriptionScope>, configs: readonly NotificationSubscriptionConfigInput[], options?: {
|
|
321
424
|
expectedGeneration?: string;
|
|
322
425
|
dryRun?: boolean;
|