@adcp/sdk 5.25.0 → 6.0.0
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/README.md +45 -7
- package/dist/lib/compliance-fixtures/index.d.ts +1 -1
- package/dist/lib/compliance-fixtures/index.js +1 -1
- package/dist/lib/conformance/runners.d.ts.map +1 -1
- package/dist/lib/conformance/runners.js +13 -1
- package/dist/lib/conformance/runners.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +15 -0
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/TaskExecutor.d.ts +7 -0
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +9 -2
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +7 -8
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts +3 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +23 -14
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/schemas/index.d.ts +1 -1
- package/dist/lib/schemas/index.js +1 -1
- package/dist/lib/server/create-adcp-server.d.ts +142 -11
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +211 -2
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/ctx-metadata/backends/memory.d.ts +27 -0
- package/dist/lib/server/ctx-metadata/backends/memory.d.ts.map +1 -0
- package/dist/lib/server/ctx-metadata/backends/memory.js +72 -0
- package/dist/lib/server/ctx-metadata/backends/memory.js.map +1 -0
- package/dist/lib/server/ctx-metadata/backends/pg.d.ts +62 -0
- package/dist/lib/server/ctx-metadata/backends/pg.d.ts.map +1 -0
- package/dist/lib/server/ctx-metadata/backends/pg.js +145 -0
- package/dist/lib/server/ctx-metadata/backends/pg.js.map +1 -0
- package/dist/lib/server/ctx-metadata/index.d.ts +15 -0
- package/dist/lib/server/ctx-metadata/index.d.ts.map +1 -0
- package/dist/lib/server/ctx-metadata/index.js +28 -0
- package/dist/lib/server/ctx-metadata/index.js.map +1 -0
- package/dist/lib/server/ctx-metadata/store.d.ts +177 -0
- package/dist/lib/server/ctx-metadata/store.d.ts.map +1 -0
- package/dist/lib/server/ctx-metadata/store.js +327 -0
- package/dist/lib/server/ctx-metadata/store.js.map +1 -0
- package/dist/lib/server/ctx-metadata/wire-shape.d.ts +55 -0
- package/dist/lib/server/ctx-metadata/wire-shape.d.ts.map +1 -0
- package/dist/lib/server/ctx-metadata/wire-shape.js +121 -0
- package/dist/lib/server/ctx-metadata/wire-shape.js.map +1 -0
- package/dist/lib/server/decisioning/account.d.ts +309 -0
- package/dist/lib/server/decisioning/account.d.ts.map +1 -0
- package/dist/lib/server/decisioning/account.js +102 -0
- package/dist/lib/server/decisioning/account.js.map +1 -0
- package/dist/lib/server/decisioning/admin-router.d.ts +75 -0
- package/dist/lib/server/decisioning/admin-router.d.ts.map +1 -0
- package/dist/lib/server/decisioning/admin-router.js +120 -0
- package/dist/lib/server/decisioning/admin-router.js.map +1 -0
- package/dist/lib/server/decisioning/assembly-helpers.d.ts +204 -0
- package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -0
- package/dist/lib/server/decisioning/assembly-helpers.js +173 -0
- package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts +154 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -0
- package/dist/lib/server/decisioning/async-outcome.js +239 -0
- package/dist/lib/server/decisioning/async-outcome.js.map +1 -0
- package/dist/lib/server/decisioning/capabilities.d.ts +251 -0
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -0
- package/dist/lib/server/decisioning/capabilities.js +16 -0
- package/dist/lib/server/decisioning/capabilities.js.map +1 -0
- package/dist/lib/server/decisioning/context.d.ts +212 -0
- package/dist/lib/server/decisioning/context.d.ts.map +1 -0
- package/dist/lib/server/decisioning/context.js +26 -0
- package/dist/lib/server/decisioning/context.js.map +1 -0
- package/dist/lib/server/decisioning/errors-typed.d.ts +104 -0
- package/dist/lib/server/decisioning/errors-typed.d.ts.map +1 -0
- package/dist/lib/server/decisioning/errors-typed.js +304 -0
- package/dist/lib/server/decisioning/errors-typed.js.map +1 -0
- package/dist/lib/server/decisioning/helpers.d.ts +131 -0
- package/dist/lib/server/decisioning/helpers.d.ts.map +1 -0
- package/dist/lib/server/decisioning/helpers.js +134 -0
- package/dist/lib/server/decisioning/helpers.js.map +1 -0
- package/dist/lib/server/decisioning/index.d.ts +46 -0
- package/dist/lib/server/decisioning/index.d.ts.map +1 -0
- package/dist/lib/server/decisioning/index.js +120 -0
- package/dist/lib/server/decisioning/index.js.map +1 -0
- package/dist/lib/server/decisioning/list-helpers.d.ts +53 -0
- package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -0
- package/dist/lib/server/decisioning/list-helpers.js +96 -0
- package/dist/lib/server/decisioning/list-helpers.js.map +1 -0
- package/dist/lib/server/decisioning/manifest-helpers.d.ts +56 -0
- package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -0
- package/dist/lib/server/decisioning/manifest-helpers.js +78 -0
- package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -0
- package/dist/lib/server/decisioning/pagination.d.ts +21 -0
- package/dist/lib/server/decisioning/pagination.d.ts.map +1 -0
- package/dist/lib/server/decisioning/pagination.js +12 -0
- package/dist/lib/server/decisioning/pagination.js.map +1 -0
- package/dist/lib/server/decisioning/platform.d.ts +188 -0
- package/dist/lib/server/decisioning/platform.d.ts.map +1 -0
- package/dist/lib/server/decisioning/platform.js +19 -0
- package/dist/lib/server/decisioning/platform.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +510 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +2196 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +114 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +247 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts +32 -0
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.js +127 -0
- package/dist/lib/server/decisioning/runtime/protocol-for-tool.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +105 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/task-registry.js +96 -0
- package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/to-context.d.ts +54 -0
- package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/to-context.js +166 -0
- package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +20 -0
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -0
- package/dist/lib/server/decisioning/runtime/validate-platform.js +93 -0
- package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/audiences.d.ts +72 -0
- package/dist/lib/server/decisioning/specialisms/audiences.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/audiences.js +15 -0
- package/dist/lib/server/decisioning/specialisms/audiences.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +92 -0
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/brand-rights.js +28 -0
- package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts +67 -0
- package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/campaign-governance.js +31 -0
- package/dist/lib/server/decisioning/specialisms/campaign-governance.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +78 -0
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/content-standards.js +35 -0
- package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +81 -0
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.js +28 -0
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/creative.d.ts +144 -0
- package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/creative.js +19 -0
- package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/lists.d.ts +61 -0
- package/dist/lib/server/decisioning/specialisms/lists.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/lists.js +30 -0
- package/dist/lib/server/decisioning/specialisms/lists.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +163 -0
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/sales.js +64 -0
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -0
- package/dist/lib/server/decisioning/specialisms/signals.d.ts +64 -0
- package/dist/lib/server/decisioning/specialisms/signals.d.ts.map +1 -0
- package/dist/lib/server/decisioning/specialisms/signals.js +28 -0
- package/dist/lib/server/decisioning/specialisms/signals.js.map +1 -0
- package/dist/lib/server/decisioning/start-time.d.ts +76 -0
- package/dist/lib/server/decisioning/start-time.d.ts.map +1 -0
- package/dist/lib/server/decisioning/start-time.js +81 -0
- package/dist/lib/server/decisioning/start-time.js.map +1 -0
- package/dist/lib/server/decisioning/status-changes.d.ts +165 -0
- package/dist/lib/server/decisioning/status-changes.d.ts.map +1 -0
- package/dist/lib/server/decisioning/status-changes.js +131 -0
- package/dist/lib/server/decisioning/status-changes.js.map +1 -0
- package/dist/lib/server/decisioning/status-mappers.d.ts +46 -0
- package/dist/lib/server/decisioning/status-mappers.d.ts.map +1 -0
- package/dist/lib/server/decisioning/status-mappers.js +46 -0
- package/dist/lib/server/decisioning/status-mappers.js.map +1 -0
- package/dist/lib/server/decisioning/tenant-registry.d.ts +289 -0
- package/dist/lib/server/decisioning/tenant-registry.d.ts.map +1 -0
- package/dist/lib/server/decisioning/tenant-registry.js +503 -0
- package/dist/lib/server/decisioning/tenant-registry.js.map +1 -0
- package/dist/lib/server/express-adapter.d.ts +1 -1
- package/dist/lib/server/express-adapter.js +1 -1
- package/dist/lib/server/governance.d.ts +1 -1
- package/dist/lib/server/governance.js +1 -1
- package/dist/lib/server/idempotency/store.d.ts +1 -1
- package/dist/lib/server/idempotency/store.js +1 -1
- package/dist/lib/server/index.d.ts +9 -2
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +79 -4
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.ts +38 -0
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -0
- package/dist/lib/server/legacy/v5/index.js +60 -0
- package/dist/lib/server/legacy/v5/index.js.map +1 -0
- package/dist/lib/server/normalize-errors.d.ts +88 -0
- package/dist/lib/server/normalize-errors.d.ts.map +1 -0
- package/dist/lib/server/normalize-errors.js +146 -0
- package/dist/lib/server/normalize-errors.js.map +1 -0
- package/dist/lib/server/pick-safe-details.d.ts +90 -0
- package/dist/lib/server/pick-safe-details.d.ts.map +1 -0
- package/dist/lib/server/pick-safe-details.js +148 -0
- package/dist/lib/server/pick-safe-details.js.map +1 -0
- package/dist/lib/server/postgres-state-store.d.ts +1 -1
- package/dist/lib/server/postgres-state-store.js +1 -1
- package/dist/lib/server/responses.d.ts +38 -0
- package/dist/lib/server/responses.d.ts.map +1 -1
- package/dist/lib/server/responses.js +38 -0
- package/dist/lib/server/responses.js.map +1 -1
- package/dist/lib/server/state-store.d.ts +1 -1
- package/dist/lib/server/state-store.js +1 -1
- package/dist/lib/server/test-controller.d.ts +10 -3
- package/dist/lib/server/test-controller.d.ts.map +1 -1
- package/dist/lib/server/test-controller.js +10 -3
- package/dist/lib/server/test-controller.js.map +1 -1
- package/dist/lib/testing/comply-controller.d.ts +47 -1
- package/dist/lib/testing/comply-controller.d.ts.map +1 -1
- package/dist/lib/testing/comply-controller.js +11 -4
- package/dist/lib/testing/comply-controller.js.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/personas/index.d.ts +143 -0
- package/dist/lib/testing/personas/index.d.ts.map +1 -0
- package/dist/lib/testing/personas/index.js +190 -0
- package/dist/lib/testing/personas/index.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +1 -1
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +3 -2
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts +13 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +179 -7
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/types/adcp.d.ts.map +1 -1
- package/dist/lib/types/adcp.js +1 -0
- package/dist/lib/types/adcp.js.map +1 -1
- package/dist/lib/types/asset-instances.d.ts +1 -0
- package/dist/lib/types/asset-instances.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +203 -98
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/schemas.generated.d.ts +599 -159
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +175 -94
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +315 -46
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.d.ts +1 -1
- package/dist/lib/utils/capabilities.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.js +6 -0
- package/dist/lib/utils/capabilities.js.map +1 -1
- package/dist/lib/validation/schema-validator.d.ts +13 -0
- package/dist/lib/validation/schema-validator.d.ts.map +1 -1
- package/dist/lib/validation/schema-validator.js +240 -3
- package/dist/lib/validation/schema-validator.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/docs/guides/BUILD-AN-AGENT.md +30 -5
- package/docs/llms.txt +28 -17
- package/examples/README.md +3 -1
- package/examples/decisioning-platform-broadcast-tv.ts +300 -0
- package/examples/decisioning-platform-identity-graph.ts +214 -0
- package/examples/decisioning-platform-mock-seller.ts +332 -0
- package/examples/decisioning-platform-multi-tenant.ts +128 -0
- package/examples/decisioning-platform-programmatic.ts +254 -0
- package/examples/signals-agent.ts +1 -1
- package/package.json +13 -2
- package/skills/build-brand-rights-agent/SKILL.md +10 -3
- package/skills/build-creative-agent/SKILL.md +94 -64
- package/skills/build-decisioning-creative-template/SKILL.md +554 -0
- package/skills/build-decisioning-platform/SKILL.md +304 -0
- package/skills/build-decisioning-platform/advanced/BRAND-RIGHTS.md +25 -0
- package/skills/build-decisioning-platform/advanced/COMPLIANCE.md +23 -0
- package/skills/build-decisioning-platform/advanced/GOVERNANCE.md +24 -0
- package/skills/build-decisioning-platform/advanced/HITL.md +34 -0
- package/skills/build-decisioning-platform/advanced/IDEMPOTENCY.md +52 -0
- package/skills/build-decisioning-platform/advanced/MULTI-TENANT.md +47 -0
- package/skills/build-decisioning-platform/advanced/OAUTH.md +22 -0
- package/skills/build-decisioning-platform/advanced/REFERENCE.md +991 -0
- package/skills/build-decisioning-platform/advanced/SANDBOX.md +24 -0
- package/skills/build-decisioning-platform/advanced/STATE-MACHINE.md +52 -0
- package/skills/build-decisioning-signal-marketplace/SKILL.md +269 -0
- package/skills/build-generative-seller-agent/SKILL.md +89 -53
- package/skills/build-governance-agent/SKILL.md +76 -45
- package/skills/build-retail-media-agent/SKILL.md +87 -62
- package/skills/build-seller-agent/SKILL.md +384 -255
- package/skills/build-seller-agent/deployment.md +5 -3
- package/skills/build-seller-agent/specialisms/audience-sync.md +0 -2
- package/skills/build-seller-agent/specialisms/sales-broadcast-tv.md +0 -2
- package/skills/build-seller-agent/specialisms/sales-guaranteed.md +0 -2
- package/skills/build-seller-agent/specialisms/sales-non-guaranteed.md +0 -2
- package/skills/build-seller-agent/specialisms/sales-proposal-mode.md +0 -2
- package/skills/build-seller-agent/specialisms/sales-social.md +0 -2
- package/skills/build-seller-agent/specialisms/signed-requests.md +0 -2
- package/skills/build-si-agent/SKILL.md +40 -32
- package/skills/build-signals-agent/SKILL.md +139 -92
- package/skills/call-adcp-agent.previous/SKILL.md +5 -0
package/docs/llms.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Ad Context Protocol (AdCP)
|
|
2
2
|
|
|
3
|
-
> Generated at: 2026-04-
|
|
4
|
-
> Library: @adcp/sdk v5.
|
|
3
|
+
> Generated at: 2026-04-30
|
|
4
|
+
> Library: @adcp/sdk v5.25.1
|
|
5
5
|
> AdCP major version: 3
|
|
6
6
|
> Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
|
|
7
7
|
|
|
@@ -12,25 +12,36 @@ AdCP is an open protocol for AI agents to buy, manage, and optimize advertising
|
|
|
12
12
|
## Are you building a client or a server?
|
|
13
13
|
|
|
14
14
|
- **Client** (calling existing agents): Continue reading — the Quick Start below is for you.
|
|
15
|
-
- **Server** (implementing an agent that others call): Read `docs/guides/BUILD-AN-AGENT.md`
|
|
15
|
+
- **Server** (implementing an agent that others call): Read `docs/guides/BUILD-AN-AGENT.md` and `docs/migration-5.x-to-6.x.md`. v6 recommended path:
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
import { serve } from '@adcp/sdk';
|
|
19
|
+
import { createAdcpServerFromPlatform } from '@adcp/sdk/server';
|
|
20
|
+
|
|
21
|
+
const platform = {
|
|
22
|
+
capabilities: {
|
|
23
|
+
specialisms: ['signal-marketplace'] as const,
|
|
24
|
+
creative_agents: [], channels: [], pricingModels: ['cpm'] as const, config: {},
|
|
25
|
+
},
|
|
26
|
+
statusMappers: {},
|
|
27
|
+
accounts: {
|
|
28
|
+
resolve: async () => ({ id: 'acc_1', ctx_metadata: {}, authInfo: { kind: 'api_key' } }),
|
|
29
|
+
},
|
|
30
|
+
signals: {
|
|
31
|
+
getSignals: async (req, ctx) => ({ signals: [/* ... */], sandbox: true }),
|
|
32
|
+
activateSignal: async (req, ctx) => ({ /* ... */ }),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
serve(() => createAdcpServerFromPlatform(platform, {
|
|
37
|
+
name: 'My Signals Agent',
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
})); // http://localhost:3001/mcp
|
|
31
40
|
```
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
Compile-time enforcement: `RequiredPlatformsFor<S>` catches missing specialism methods. Capability projection auto-derives `get_adcp_capabilities` blocks (`audience_targeting`, `conversion_tracking`, `compliance_testing.scenarios`, etc.). Idempotency, RFC 9421 signing, async tasks, status normalization, and sync-completion webhook auto-emit are framework-owned.
|
|
43
|
+
|
|
44
|
+
Lower-level option: `createAdcpServer({ signals: { getSignals: ... } })` from `@adcp/sdk/server/legacy/v5` — handler-bag API. Still fully supported, the substrate the platform path calls into. Use when you need fine control over individual handlers, mid-migration from a v5 codebase, or custom-shaped tools the platform interface doesn't yet model. `wrapEnvelope(inner, { replayed, context, operationId })` from `@adcp/sdk/server` attaches protocol envelope fields with the per-error-code allowlist (IDEMPOTENCY_CONFLICT drops `replayed`).
|
|
34
45
|
|
|
35
46
|
## Quick Start (Client)
|
|
36
47
|
|
package/examples/README.md
CHANGED
|
@@ -54,7 +54,9 @@ ADCP_AGENTS_CONFIG='[{"id":"test-agent","name":"Test Agent","agent_uri":"https:/
|
|
|
54
54
|
```typescript
|
|
55
55
|
import { ADCPMultiAgentClient, type AgentConfig } from '@adcp/sdk';
|
|
56
56
|
|
|
57
|
-
const agents: AgentConfig[] = [
|
|
57
|
+
const agents: AgentConfig[] = [
|
|
58
|
+
/* your agents */
|
|
59
|
+
];
|
|
58
60
|
const client = new ADCPMultiAgentClient(agents);
|
|
59
61
|
|
|
60
62
|
// Single agent operation
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BroadcastTvSeller — worked example for `sales-broadcast-tv`.
|
|
3
|
+
*
|
|
4
|
+
* Broadcast linear TV is the canonical HITL case: a media buy isn't real
|
|
5
|
+
* until the trafficker confirms inventory holds and the plan clears
|
|
6
|
+
* standards & practices. Buyers don't get a `media_buy_id` until the
|
|
7
|
+
* trafficker accepts; the unified hybrid shape projects this directly:
|
|
8
|
+
*
|
|
9
|
+
* - `getProducts` — sync catalog read of the affiliate's standing
|
|
10
|
+
* inventory packages (no trafficker review for catalog reads). Brief-
|
|
11
|
+
* based proposal generation is a separate verb (`request_proposal`,
|
|
12
|
+
* adcp#3407) and rides on a status-change channel, not on
|
|
13
|
+
* `get_products`.
|
|
14
|
+
* - `createMediaBuy(req, ctx)` — returns `ctx.handoffToTask(fn)` for
|
|
15
|
+
* trafficker review + IO sign-off (hours to days). The handoff fn
|
|
16
|
+
* does the actual work and returns the wire `Success` arm when the
|
|
17
|
+
* trafficker accepts; `throw AdcpError` becomes the terminal error.
|
|
18
|
+
* - `syncCreatives(creatives, ctx)` — returns `ctx.handoffToTask(fn)`
|
|
19
|
+
* for the standards-and-practices review (24-48 hour SLA in
|
|
20
|
+
* production; demo uses `standardsReviewMs`).
|
|
21
|
+
*
|
|
22
|
+
* Lifecycle changes after acceptance (plan goes from `pending_start` →
|
|
23
|
+
* `active` → `completed` over the campaign window) flow via
|
|
24
|
+
* `publishStatusChange`.
|
|
25
|
+
*
|
|
26
|
+
* @see `skills/build-decisioning-platform/SKILL.md`
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
AdcpError,
|
|
31
|
+
publishStatusChange,
|
|
32
|
+
type DecisioningPlatform,
|
|
33
|
+
type SalesPlatform,
|
|
34
|
+
type AccountStore,
|
|
35
|
+
type SyncCreativesRow,
|
|
36
|
+
} from '@adcp/sdk/server';
|
|
37
|
+
import type {
|
|
38
|
+
GetProductsRequest,
|
|
39
|
+
GetProductsResponse,
|
|
40
|
+
CreateMediaBuyRequest,
|
|
41
|
+
CreateMediaBuySuccess,
|
|
42
|
+
UpdateMediaBuyRequest,
|
|
43
|
+
UpdateMediaBuySuccess,
|
|
44
|
+
GetMediaBuyDeliveryRequest,
|
|
45
|
+
GetMediaBuyDeliveryResponse,
|
|
46
|
+
CreativeAsset,
|
|
47
|
+
AccountReference,
|
|
48
|
+
} from '@adcp/sdk/types';
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// BroadcastTvSeller config + state
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
export interface BroadcastTvConfig {
|
|
55
|
+
/** Affiliate the trafficker IO desk maps to (e.g., 'WCBS'). */
|
|
56
|
+
affiliateId: string;
|
|
57
|
+
/** Simulated trafficker review duration (ms). */
|
|
58
|
+
trafficReviewMs: number;
|
|
59
|
+
/** Simulated S&P review duration (ms). */
|
|
60
|
+
standardsReviewMs: number;
|
|
61
|
+
/** Day-of-week and hour the schedule "activates" relative to start_time. */
|
|
62
|
+
activationOffsetMs: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface BroadcastTvMeta {
|
|
66
|
+
agency_buyer_id: string;
|
|
67
|
+
affiliate_advertiser_id: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type BroadcastBuy = CreateMediaBuySuccess & { daypart?: string };
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Implementation
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
export class BroadcastTvSeller implements DecisioningPlatform<BroadcastTvConfig, BroadcastTvMeta> {
|
|
78
|
+
private mediaBuys = new Map<string, BroadcastBuy>();
|
|
79
|
+
|
|
80
|
+
capabilities = {
|
|
81
|
+
specialisms: ['sales-broadcast-tv'] as const,
|
|
82
|
+
creative_agents: [{ agent_url: 'https://example.com/broadcast-creative-agent/mcp' }],
|
|
83
|
+
channels: ['linear_tv'] as const,
|
|
84
|
+
pricingModels: ['cpm'] as const,
|
|
85
|
+
config: {
|
|
86
|
+
affiliateId: 'WCBS',
|
|
87
|
+
trafficReviewMs: 100,
|
|
88
|
+
standardsReviewMs: 80,
|
|
89
|
+
activationOffsetMs: 50,
|
|
90
|
+
} satisfies BroadcastTvConfig,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
statusMappers = {};
|
|
94
|
+
|
|
95
|
+
accounts: AccountStore<BroadcastTvMeta> = {
|
|
96
|
+
resolve: async (ref: AccountReference) => {
|
|
97
|
+
const id = 'account_id' in ref ? ref.account_id : 'broadcast_acc_1';
|
|
98
|
+
return {
|
|
99
|
+
id,
|
|
100
|
+
name: `Broadcast TV — ${id}`,
|
|
101
|
+
status: 'active',
|
|
102
|
+
operator: 'broadcast.example.com',
|
|
103
|
+
ctx_metadata: { agency_buyer_id: 'agc_42', affiliate_advertiser_id: 'aff_99' },
|
|
104
|
+
authInfo: { kind: 'api_key' },
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
sales: SalesPlatform<BroadcastTvMeta> = {
|
|
110
|
+
/**
|
|
111
|
+
* Sync catalog read. Returns the affiliate's standing packages —
|
|
112
|
+
* primetime daypart, sports tentpoles, etc. Brief-based proposal
|
|
113
|
+
* generation is a separate verb the spec is consolidating
|
|
114
|
+
* (adcp#3407 `request_proposal`); proposal-mode adopters surface
|
|
115
|
+
* the eventual products via `publishStatusChange` on
|
|
116
|
+
* `resource_type: 'proposal'`.
|
|
117
|
+
*/
|
|
118
|
+
getProducts: async (req: GetProductsRequest): Promise<GetProductsResponse> => {
|
|
119
|
+
const promotedOffering = (req as { promoted_offering?: string }).promoted_offering ?? '';
|
|
120
|
+
if (/political|cannabis|gambling/i.test(promotedOffering)) {
|
|
121
|
+
throw new AdcpError('POLICY_VIOLATION', {
|
|
122
|
+
recovery: 'terminal',
|
|
123
|
+
message: 'Affiliate does not carry this category under FCC + station policy',
|
|
124
|
+
field: 'promoted_offering',
|
|
125
|
+
details: { affiliate: this.capabilities.config.affiliateId },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
products: [
|
|
131
|
+
{
|
|
132
|
+
product_id: 'prod_primetime_30s',
|
|
133
|
+
name: 'Primetime 30s — M-F 8-11pm',
|
|
134
|
+
description: 'Local broadcast primetime, :30 spots',
|
|
135
|
+
format_ids: [{ id: 'video_30s', agent_url: 'https://example.com/broadcast-creative-agent/mcp' }],
|
|
136
|
+
delivery_type: 'guaranteed',
|
|
137
|
+
publisher_properties: [{ publisher_domain: 'broadcast.example.com', selection_type: 'all' }],
|
|
138
|
+
reporting_capabilities: {
|
|
139
|
+
available_reporting_frequencies: ['daily'],
|
|
140
|
+
expected_delay_minutes: 240,
|
|
141
|
+
timezone: 'UTC',
|
|
142
|
+
supports_webhooks: false,
|
|
143
|
+
available_metrics: [],
|
|
144
|
+
date_range_support: 'date_range',
|
|
145
|
+
},
|
|
146
|
+
pricing_options: [
|
|
147
|
+
{
|
|
148
|
+
pricing_option_id: 'cpm_42_00',
|
|
149
|
+
pricing_model: 'cpm',
|
|
150
|
+
fixed_price: 42.0,
|
|
151
|
+
currency: 'USD',
|
|
152
|
+
min_spend_per_package: 5_000,
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Hybrid HITL: trafficker review + IO sign-off. Buyer sees `submitted`
|
|
162
|
+
* envelope with `task_id` immediately; the framework runs the handoff
|
|
163
|
+
* fn in background. Trafficker accepts → handoff returns the wire
|
|
164
|
+
* `Success` arm with `media_buy_id`; trafficker rejects → handoff
|
|
165
|
+
* throws `AdcpError`, framework surfaces terminal error.
|
|
166
|
+
*
|
|
167
|
+
* Pre-flight runs sync (rejects bad budgets before allocating a task
|
|
168
|
+
* id). Lifecycle after acceptance flows via `publishStatusChange`.
|
|
169
|
+
*/
|
|
170
|
+
createMediaBuy: (req, ctx) => {
|
|
171
|
+
// Pre-flight runs sync regardless of path
|
|
172
|
+
const errors = this.preflight(req);
|
|
173
|
+
if (errors.length > 0) {
|
|
174
|
+
throw new AdcpError('INVALID_REQUEST', {
|
|
175
|
+
recovery: 'correctable',
|
|
176
|
+
message: errors[0]!.message,
|
|
177
|
+
field: errors[0]!.field,
|
|
178
|
+
details: { errors },
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return Promise.resolve(
|
|
183
|
+
ctx.handoffToTask(async taskCtx => {
|
|
184
|
+
void taskCtx; // taskCtx.id available if you need to log it
|
|
185
|
+
// Trafficker review window
|
|
186
|
+
await new Promise(r => setTimeout(r, this.capabilities.config.trafficReviewMs));
|
|
187
|
+
|
|
188
|
+
const buyId = `mb_${this.capabilities.config.affiliateId}_${Date.now()}`;
|
|
189
|
+
const buy: BroadcastBuy = {
|
|
190
|
+
media_buy_id: buyId,
|
|
191
|
+
status: 'pending_start',
|
|
192
|
+
confirmed_at: new Date().toISOString(),
|
|
193
|
+
revision: 1,
|
|
194
|
+
daypart: 'primetime',
|
|
195
|
+
packages: [],
|
|
196
|
+
};
|
|
197
|
+
this.mediaBuys.set(buyId, buy);
|
|
198
|
+
|
|
199
|
+
// After acceptance, the broadcast traffic system controls the
|
|
200
|
+
// campaign window. Schedule the post-acceptance status-change.
|
|
201
|
+
const account = (req as { account?: { account_id?: string } }).account;
|
|
202
|
+
const accountId = account?.account_id ?? 'broadcast_acc_1';
|
|
203
|
+
setTimeout(() => {
|
|
204
|
+
buy.status = 'active';
|
|
205
|
+
publishStatusChange({
|
|
206
|
+
account_id: accountId,
|
|
207
|
+
resource_type: 'media_buy',
|
|
208
|
+
resource_id: buyId,
|
|
209
|
+
payload: { status: 'active', activated_at: new Date().toISOString() },
|
|
210
|
+
});
|
|
211
|
+
}, this.capabilities.config.activationOffsetMs).unref?.();
|
|
212
|
+
|
|
213
|
+
return buy;
|
|
214
|
+
})
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
updateMediaBuy: async (buyId: string, patch: UpdateMediaBuyRequest): Promise<UpdateMediaBuySuccess> => {
|
|
219
|
+
const existing = this.mediaBuys.get(buyId);
|
|
220
|
+
if (!existing) {
|
|
221
|
+
throw new AdcpError('MEDIA_BUY_NOT_FOUND', {
|
|
222
|
+
recovery: 'terminal',
|
|
223
|
+
message: `media buy ${buyId} not found`,
|
|
224
|
+
field: 'media_buy_id',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
// Broadcast: pause = preempt the schedule; canceled is irreversible
|
|
228
|
+
// (cannot reactivate without a fresh IO).
|
|
229
|
+
if (patch.paused === true) existing.status = 'paused';
|
|
230
|
+
if (patch.paused === false && existing.status === 'paused') existing.status = 'active';
|
|
231
|
+
return { media_buy_id: existing.media_buy_id, status: existing.status, revision: existing.revision };
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Hybrid HITL S&P review: every spot goes through standards-and-
|
|
236
|
+
* practices before it can air. 24-48 hour SLA in production. Returns
|
|
237
|
+
* `ctx.handoffToTask(fn)` so the buyer sees the submitted envelope
|
|
238
|
+
* immediately and the review runs in background.
|
|
239
|
+
*/
|
|
240
|
+
syncCreatives: (creatives, ctx) =>
|
|
241
|
+
Promise.resolve(
|
|
242
|
+
ctx.handoffToTask(async taskCtx => {
|
|
243
|
+
void taskCtx;
|
|
244
|
+
await new Promise(r => setTimeout(r, this.capabilities.config.standardsReviewMs));
|
|
245
|
+
// Mock policy: anything tagged "political" rejects; rest approve.
|
|
246
|
+
return creatives.map(c => {
|
|
247
|
+
const id = (c as { creative_id?: string }).creative_id ?? `cr_${Math.random()}`;
|
|
248
|
+
const tags = ((c as { tags?: string[] }).tags ?? []).map(t => t.toLowerCase());
|
|
249
|
+
if (tags.includes('political')) {
|
|
250
|
+
return {
|
|
251
|
+
creative_id: id,
|
|
252
|
+
action: 'failed',
|
|
253
|
+
status: 'rejected',
|
|
254
|
+
errors: [
|
|
255
|
+
{
|
|
256
|
+
code: 'CREATIVE_REJECTED',
|
|
257
|
+
message: 'Political ads require FCC disclosure file + station GM sign-off',
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
} satisfies SyncCreativesRow;
|
|
261
|
+
}
|
|
262
|
+
return { creative_id: id, action: 'created', status: 'approved' } satisfies SyncCreativesRow;
|
|
263
|
+
});
|
|
264
|
+
})
|
|
265
|
+
),
|
|
266
|
+
|
|
267
|
+
getMediaBuyDelivery: async (filter: GetMediaBuyDeliveryRequest): Promise<GetMediaBuyDeliveryResponse> => {
|
|
268
|
+
return {
|
|
269
|
+
currency: 'USD',
|
|
270
|
+
reporting_period: {
|
|
271
|
+
start: filter.start_date ?? '2026-04-01',
|
|
272
|
+
end: filter.end_date ?? '2026-04-30',
|
|
273
|
+
},
|
|
274
|
+
media_buy_deliveries: [],
|
|
275
|
+
};
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
// Required on SalesPlatform — write-only adopters return an empty array.
|
|
279
|
+
// This affiliate doesn't enumerate buys via this surface (push-channel
|
|
280
|
+
// delivery via webhooks); the empty array is truthful.
|
|
281
|
+
getMediaBuys: async () => ({ media_buys: [] }),
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
private preflight(req: CreateMediaBuyRequest): { code: string; recovery: string; message: string; field: string }[] {
|
|
285
|
+
const errors = [];
|
|
286
|
+
const totalBudget =
|
|
287
|
+
typeof req.total_budget === 'number'
|
|
288
|
+
? req.total_budget
|
|
289
|
+
: ((req.total_budget as { amount?: number })?.amount ?? 0);
|
|
290
|
+
if (totalBudget < 5_000) {
|
|
291
|
+
errors.push({
|
|
292
|
+
code: 'BUDGET_TOO_LOW',
|
|
293
|
+
recovery: 'correctable',
|
|
294
|
+
message: 'Broadcast minimum is $5,000 per IO',
|
|
295
|
+
field: 'total_budget',
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return errors;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IdentityGraphProvider — worked example for `audience-sync`.
|
|
3
|
+
*
|
|
4
|
+
* Identity-graph providers (the category covers vendors like LiveRamp,
|
|
5
|
+
* Oracle Data Cloud, Salesforce CDP, Neustar) have a long-tail
|
|
6
|
+
* activation pipeline: ingest → match → activate to destinations. Match
|
|
7
|
+
* takes 5-30 minutes; activation per destination takes hours. Buyers
|
|
8
|
+
* can't usefully wait synchronously, but they DO want immediate
|
|
9
|
+
* confirmation that the audience was accepted and to know when it's
|
|
10
|
+
* ready.
|
|
11
|
+
*
|
|
12
|
+
* This sample is generic — no real provider's API or branding is
|
|
13
|
+
* implied; the latencies and stages are illustrative. The shape adapters
|
|
14
|
+
* use is:
|
|
15
|
+
*
|
|
16
|
+
* - Sync `syncAudiences` returns per-audience rows with the *current*
|
|
17
|
+
* wire status (`processing` is fine — the buyer's audience_id is
|
|
18
|
+
* now known and they can subscribe for updates).
|
|
19
|
+
* - `publishStatusChange({ resource_type: 'audience', ... })` fires from
|
|
20
|
+
* the match-pipeline + activation-pipeline as each audience reaches
|
|
21
|
+
* internal stages `matched` → `activating` → `active`.
|
|
22
|
+
*
|
|
23
|
+
* `AdcpError` for buyer-fixable rejection (`REFERENCE_NOT_FOUND`,
|
|
24
|
+
* insufficient identifiers, etc.).
|
|
25
|
+
*
|
|
26
|
+
* @see `skills/build-decisioning-platform/SKILL.md`
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { publishStatusChange, type DecisioningPlatform, type AccountStore } from '@adcp/sdk/server';
|
|
30
|
+
import type { AudiencePlatform, Audience, AudienceStatus, SyncAudiencesRow } from '@adcp/sdk/server';
|
|
31
|
+
import type { AccountReference } from '@adcp/sdk/types';
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Config + state
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
export interface IdentityGraphConfig {
|
|
38
|
+
/** Minimum identifier count before activation; audiences below this reject. */
|
|
39
|
+
minIdentifiers: number;
|
|
40
|
+
/** Identity-graph match latency (ms). */
|
|
41
|
+
matchLatencyMs: number;
|
|
42
|
+
/** Per-destination activation latency (ms). */
|
|
43
|
+
activationLatencyMs: number;
|
|
44
|
+
/** Default match rate the demo simulates. */
|
|
45
|
+
defaultMatchRate: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface IdentityGraphMeta {
|
|
49
|
+
graph_id: string;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Internal lifecycle stages — richer than the wire `AudienceStatus` enum
|
|
55
|
+
* (`'processing' | 'ready' | 'too_small'`). The internal stages flow
|
|
56
|
+
* through `publishStatusChange.payload` (freeform JSON) so buyers
|
|
57
|
+
* subscribed to the bus see `matched_count`, `match_rate`, and the
|
|
58
|
+
* stage transitions. The wire-shaped `pollAudienceStatuses` collapses
|
|
59
|
+
* back to the spec enum.
|
|
60
|
+
*/
|
|
61
|
+
type IdentityGraphStage = 'matching' | 'matched' | 'activating' | 'active' | 'failed';
|
|
62
|
+
|
|
63
|
+
function toWireStatus(stage: IdentityGraphStage): AudienceStatus {
|
|
64
|
+
switch (stage) {
|
|
65
|
+
case 'active':
|
|
66
|
+
return 'ready';
|
|
67
|
+
case 'failed':
|
|
68
|
+
return 'too_small';
|
|
69
|
+
default:
|
|
70
|
+
return 'processing';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type AudienceState = {
|
|
75
|
+
audience_id: string;
|
|
76
|
+
stage: IdentityGraphStage;
|
|
77
|
+
matched_count?: number;
|
|
78
|
+
match_rate?: number;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Implementation
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
export class IdentityGraphProvider implements DecisioningPlatform<IdentityGraphConfig, IdentityGraphMeta> {
|
|
86
|
+
private audienceState = new Map<string, AudienceState>();
|
|
87
|
+
|
|
88
|
+
capabilities = {
|
|
89
|
+
specialisms: ['audience-sync'] as const,
|
|
90
|
+
creative_agents: [],
|
|
91
|
+
channels: [] as const,
|
|
92
|
+
pricingModels: ['cpm'] as const,
|
|
93
|
+
config: {
|
|
94
|
+
minIdentifiers: 100,
|
|
95
|
+
matchLatencyMs: 60,
|
|
96
|
+
activationLatencyMs: 80,
|
|
97
|
+
defaultMatchRate: 0.42,
|
|
98
|
+
} satisfies IdentityGraphConfig,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
statusMappers = {};
|
|
102
|
+
|
|
103
|
+
accounts: AccountStore<IdentityGraphMeta> = {
|
|
104
|
+
resolve: async (ref: AccountReference) => {
|
|
105
|
+
const id = 'account_id' in ref ? ref.account_id : 'idg_acc_1';
|
|
106
|
+
return {
|
|
107
|
+
id,
|
|
108
|
+
name: `IdentityGraph — ${id}`,
|
|
109
|
+
status: 'active',
|
|
110
|
+
operator: 'identity-graph.example.com',
|
|
111
|
+
ctx_metadata: { graph_id: 'IG-12345' },
|
|
112
|
+
authInfo: { kind: 'api_key' },
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
audiences: AudiencePlatform<IdentityGraphMeta> = {
|
|
118
|
+
/**
|
|
119
|
+
* Sync acknowledgment: return current state for each audience. Match
|
|
120
|
+
* pipeline + activation pipeline run in background and emit
|
|
121
|
+
* publishStatusChange events as each audience progresses through the
|
|
122
|
+
* richer internal stages (`matching` → `matched` → `activating` →
|
|
123
|
+
* `active`). Buyers subscribed to the status-change bus see the full
|
|
124
|
+
* lifecycle; buyers polling `pollAudienceStatuses` see the wire-flat
|
|
125
|
+
* `processing | ready | too_small`.
|
|
126
|
+
*/
|
|
127
|
+
syncAudiences: async (audiences: Audience[]): Promise<SyncAudiencesRow[]> => {
|
|
128
|
+
const results: SyncAudiencesRow[] = [];
|
|
129
|
+
const accountId = 'idg_acc_1';
|
|
130
|
+
|
|
131
|
+
for (const aud of audiences) {
|
|
132
|
+
const audienceId = (aud as { audience_id?: string }).audience_id ?? `aud_${Math.random()}`;
|
|
133
|
+
const identifiers = ((aud as { identifiers?: unknown[] }).identifiers ?? []) as unknown[];
|
|
134
|
+
|
|
135
|
+
if (identifiers.length < this.capabilities.config.minIdentifiers) {
|
|
136
|
+
this.audienceState.set(audienceId, { audience_id: audienceId, stage: 'failed' });
|
|
137
|
+
results.push({
|
|
138
|
+
audience_id: audienceId,
|
|
139
|
+
action: 'failed',
|
|
140
|
+
status: 'too_small',
|
|
141
|
+
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const isUpdate = this.audienceState.has(audienceId);
|
|
146
|
+
const initial: AudienceState = { audience_id: audienceId, stage: 'matching' };
|
|
147
|
+
this.audienceState.set(audienceId, initial);
|
|
148
|
+
|
|
149
|
+
// Schedule match → matched
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
const matched = Math.floor(identifiers.length * this.capabilities.config.defaultMatchRate);
|
|
152
|
+
const next: AudienceState = {
|
|
153
|
+
audience_id: audienceId,
|
|
154
|
+
stage: 'matched',
|
|
155
|
+
matched_count: matched,
|
|
156
|
+
match_rate: this.capabilities.config.defaultMatchRate,
|
|
157
|
+
};
|
|
158
|
+
this.audienceState.set(audienceId, next);
|
|
159
|
+
publishStatusChange({
|
|
160
|
+
account_id: accountId,
|
|
161
|
+
resource_type: 'audience',
|
|
162
|
+
resource_id: audienceId,
|
|
163
|
+
payload: {
|
|
164
|
+
stage: 'matched',
|
|
165
|
+
status: 'processing',
|
|
166
|
+
matched_count: matched,
|
|
167
|
+
match_rate: this.capabilities.config.defaultMatchRate,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Schedule matched → activating → active
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
this.audienceState.set(audienceId, { ...next, stage: 'activating' });
|
|
174
|
+
publishStatusChange({
|
|
175
|
+
account_id: accountId,
|
|
176
|
+
resource_type: 'audience',
|
|
177
|
+
resource_id: audienceId,
|
|
178
|
+
payload: { stage: 'activating', status: 'processing' },
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
this.audienceState.set(audienceId, { ...next, stage: 'active' });
|
|
183
|
+
publishStatusChange({
|
|
184
|
+
account_id: accountId,
|
|
185
|
+
resource_type: 'audience',
|
|
186
|
+
resource_id: audienceId,
|
|
187
|
+
payload: { stage: 'active', status: 'ready' },
|
|
188
|
+
});
|
|
189
|
+
}, this.capabilities.config.activationLatencyMs).unref?.();
|
|
190
|
+
}, 10).unref?.();
|
|
191
|
+
}, this.capabilities.config.matchLatencyMs).unref?.();
|
|
192
|
+
|
|
193
|
+
results.push({
|
|
194
|
+
audience_id: audienceId,
|
|
195
|
+
action: isUpdate ? 'updated' : 'created',
|
|
196
|
+
status: 'processing',
|
|
197
|
+
matched_count: 0,
|
|
198
|
+
effective_match_rate: 0,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return results;
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
pollAudienceStatuses: async (audienceIds): Promise<Map<string, AudienceStatus>> => {
|
|
206
|
+
const out = new Map<string, AudienceStatus>();
|
|
207
|
+
for (const audienceId of audienceIds) {
|
|
208
|
+
const state = this.audienceState.get(audienceId);
|
|
209
|
+
if (state) out.set(audienceId, toWireStatus(state.stage));
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|