@adcp/sdk 14.0.0-beta.12 → 14.0.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.d.ts +3 -3
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +3 -1
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +2 -2
- package/dist/lib/server/create-adcp-server.d.ts +2 -2
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +6 -1
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +6 -1
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.d.mts +3 -3
- package/dist/lib/server/decisioning/index.d.ts +3 -3
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +24 -17
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +24 -17
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +71 -42
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +75 -43
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +15 -21
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +15 -21
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +100 -30
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +100 -30
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.d.mts +30 -16
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +30 -16
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.js +40 -20
- package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.mjs +38 -19
- package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.d.mts +2 -2
- package/dist/lib/server/decisioning/runtime/to-context.d.ts +2 -2
- package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +2 -2
- package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.mjs +2 -2
- package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +3 -2
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +3 -2
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative.d.mts +10 -10
- package/dist/lib/server/decisioning/specialisms/creative.d.ts +10 -10
- package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
- package/dist/lib/server/index.d.mts +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/default-invariants.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/default-invariants.js +11 -2
- package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
- package/dist/lib/testing/storyboard/default-invariants.mjs +11 -2
- package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
- package/dist/lib/testing/storyboard/index.d.mts +1 -1
- 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.map +1 -1
- package/dist/lib/testing/storyboard/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/loader.js +14 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -1
- package/dist/lib/testing/storyboard/loader.mjs +14 -0
- package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
- package/dist/lib/testing/storyboard/phase-condition.d.mts +41 -0
- package/dist/lib/testing/storyboard/phase-condition.d.ts +42 -0
- package/dist/lib/testing/storyboard/phase-condition.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/phase-condition.js +215 -0
- package/dist/lib/testing/storyboard/phase-condition.js.map +1 -0
- package/dist/lib/testing/storyboard/phase-condition.mjs +189 -0
- package/dist/lib/testing/storyboard/phase-condition.mjs.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.js +15 -2
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.mjs +15 -2
- package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +57 -23
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +57 -23
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +6 -2
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +6 -2
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/storyboard/types.d.mts +5 -4
- package/dist/lib/testing/storyboard/types.d.ts +5 -4
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/storyboard/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/webhook-assertions.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/webhook-assertions.js +60 -4
- package/dist/lib/testing/storyboard/webhook-assertions.js.map +1 -1
- package/dist/lib/testing/storyboard/webhook-assertions.mjs +60 -4
- package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
- package/dist/lib/testing/storyboard/webhook-receiver.d.mts +15 -0
- package/dist/lib/testing/storyboard/webhook-receiver.d.ts +15 -0
- package/dist/lib/testing/storyboard/webhook-receiver.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/webhook-receiver.js +57 -6
- package/dist/lib/testing/storyboard/webhook-receiver.js.map +1 -1
- package/dist/lib/testing/storyboard/webhook-receiver.mjs +57 -6
- package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
- package/dist/lib/testing/types.d.mts +2 -0
- package/dist/lib/testing/types.d.ts +2 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/testing/types.js.map +1 -1
- package/dist/lib/types/core.generated.d.mts +5 -2
- package/dist/lib/types/core.generated.d.ts +5 -2
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js.map +1 -1
- package/dist/lib/types/index.d.mts +1 -1
- package/dist/lib/types/index.d.ts +1 -1
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/types/list-transformers.d.ts +9 -5
- package/dist/lib/types/schemas.generated.d.ts +21 -298
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +5 -2
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +4 -2
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/server-payload-aliases.d.mts +2 -1
- package/dist/lib/types/server-payload-aliases.d.ts +2 -1
- package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
- package/dist/lib/types/server-payload-aliases.js.map +1 -1
- package/dist/lib/types/tools.generated.d.mts +5 -2
- package/dist/lib/types/tools.generated.d.ts +5 -2
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/tools.generated.js.map +1 -1
- package/dist/lib/utils/build-creative-return-builders.d.mts +5 -1
- package/dist/lib/utils/build-creative-return-builders.d.ts +5 -1
- package/dist/lib/utils/build-creative-return-builders.d.ts.map +1 -1
- package/dist/lib/utils/build-creative-return-builders.js +9 -3
- package/dist/lib/utils/build-creative-return-builders.js.map +1 -1
- package/dist/lib/utils/build-creative-return-builders.mjs +7 -2
- package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
- package/dist/lib/utils/response-unwrapper.js +1 -1
- package/dist/lib/utils/response-unwrapper.js.map +1 -1
- package/dist/lib/utils/response-unwrapper.mjs +1 -1
- package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +16 -7
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +16 -7
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/llms.txt +2 -2
- package/docs/migration-5.x-to-6.x.md +3 -2
- package/docs/migration-task-registry-scoping.md +61 -0
- package/examples/hello_seller_adapter_guaranteed.ts +1 -1
- package/package.json +4 -4
- package/skills/build-decisioning-creative-template/SKILL.md +2 -2
- package/skills/build-decisioning-platform/SKILL.md +4 -2
- package/skills/build-decisioning-platform/advanced/REFERENCE.md +7 -6
|
@@ -269,11 +269,12 @@ In-memory task registry refuses to construct outside `NODE_ENV=test/development`
|
|
|
269
269
|
```ts
|
|
270
270
|
import { createPostgresTaskRegistry, getDecisioningTaskRegistryMigration } from '@adcp/sdk/server';
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
const taskRegistryNamespace = 'tenant:my-agent';
|
|
273
|
+
await pool.query(getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace }));
|
|
273
274
|
|
|
274
275
|
createAdcpServerFromPlatform(platform, {
|
|
275
276
|
name: '...', version: '...',
|
|
276
|
-
taskRegistry: createPostgresTaskRegistry({ pool }),
|
|
277
|
+
taskRegistry: createPostgresTaskRegistry({ pool, namespace: taskRegistryNamespace }),
|
|
277
278
|
});
|
|
278
279
|
```
|
|
279
280
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Task registry scope migration
|
|
2
|
+
|
|
3
|
+
Task registry reads, writes, and background waits now require the account and
|
|
4
|
+
authenticated owner scope that created the task. This prevents a known task ID
|
|
5
|
+
from crossing account or principal boundaries.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const scope = { accountId: account.id, ownerScope: `api_key:${keyId}` };
|
|
9
|
+
|
|
10
|
+
await registry.getTask(taskId, scope);
|
|
11
|
+
await registry.updateProgress(taskId, scope, progress);
|
|
12
|
+
await registry.complete(taskId, scope, result);
|
|
13
|
+
await registry.fail(taskId, scope, error, failureArtifact);
|
|
14
|
+
await registry.awaitTask(taskId, scope);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Custom `TaskRegistry` implementations must apply every scope component in the
|
|
18
|
+
storage query. Do not derive `ownerScope` from request parameters; use the
|
|
19
|
+
authenticated server context. Set `scopeVersion: 1` only after migrating those
|
|
20
|
+
method signatures; the platform factory rejects unmarked legacy registries so
|
|
21
|
+
an old `(taskId, result)` write cannot mistake the new scope argument for a
|
|
22
|
+
result.
|
|
23
|
+
|
|
24
|
+
`DecisioningAdcpServer.getTaskState()` and `.awaitTask()` accept the same scope.
|
|
25
|
+
Administrative and test code that intentionally has no buyer context can use
|
|
26
|
+
the explicitly named `getTaskStateUnsafe()` and `awaitTaskUnsafe()` helpers.
|
|
27
|
+
Unsafe reads return `null` when the same public task ID exists in more than one
|
|
28
|
+
scope.
|
|
29
|
+
|
|
30
|
+
PostgreSQL registries additionally require a trusted deployment or tenant
|
|
31
|
+
namespace:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const taskRegistryNamespace = 'tenant:my-agent';
|
|
35
|
+
createPostgresTaskRegistry({
|
|
36
|
+
pool,
|
|
37
|
+
namespace: taskRegistryNamespace,
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Run the migration with that same namespace before deploying the new registry:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
await pool.query(
|
|
45
|
+
getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace })
|
|
46
|
+
);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
It backfills legacy rows to the supplied registry namespace and account fallback
|
|
50
|
+
owner scope, then migrates the primary key to
|
|
51
|
+
`(registry_namespace, account_id, owner_scope, task_id)`. The namespace must be
|
|
52
|
+
stable across deploys and unique for every hosted tenant. A single in-memory
|
|
53
|
+
registry instance must likewise not be shared across tenants unless the host
|
|
54
|
+
includes tenant identity in both `accountId` and `ownerScope`.
|
|
55
|
+
|
|
56
|
+
The legacy table did not store a tenant identifier. If multiple hosted tenants
|
|
57
|
+
previously shared one legacy table, the SDK cannot infer which tenant owns each
|
|
58
|
+
row: the first migration would otherwise assign every legacy row to its supplied
|
|
59
|
+
namespace. Before migrating, drain in-flight tasks or explicitly map legacy rows
|
|
60
|
+
to tenant namespaces in an operator-managed migration. Do not run separate
|
|
61
|
+
tenant migrations over an ambiguous shared legacy table.
|
|
@@ -1355,7 +1355,7 @@ const mediaBuyStore = createMediaBuyStore({ store: stateStore });
|
|
|
1355
1355
|
// instance persists across requests — a fresh registry per request would
|
|
1356
1356
|
// lose every submitted task between create_media_buy and the buyer's
|
|
1357
1357
|
// first tasks_get poll. SWAP `createInMemoryTaskRegistry()` for
|
|
1358
|
-
// `createPostgresTaskRegistry({ pool })` in production; in-memory
|
|
1358
|
+
// `createPostgresTaskRegistry({ pool, namespace: tenantId })` in production; in-memory
|
|
1359
1359
|
// in-flight tasks are lost on process restart.
|
|
1360
1360
|
const taskRegistry = createInMemoryTaskRegistry();
|
|
1361
1361
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adcp/sdk",
|
|
3
|
-
"version": "14.0.0-beta.
|
|
3
|
+
"version": "14.0.0-beta.13",
|
|
4
4
|
"description": "AdCP SDK — client, server, and compliance harnesses for the AdContext Protocol (MCP + A2A)",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -485,9 +485,9 @@
|
|
|
485
485
|
"pretest": "npm run schemas:ensure",
|
|
486
486
|
"test": "npm run test:node && npm test --workspace=packages/eslint-plugin --if-present && npm test --workspace=@adcp/reference-renderers",
|
|
487
487
|
"test:node": "npm run test:node:fast && npm run test:node:slow",
|
|
488
|
-
"test:node:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
|
|
489
|
-
"test:node:fast:shard": "test -n \"$TEST_SHARD\" && NODE_ENV=test node --test-timeout=60000 --test-force-exit --test-shard=$TEST_SHARD --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
|
|
490
|
-
"test:node:slow": "NODE_ENV=test node --test-timeout=180000 --test-force-exit --test test/canonical-creatives-a2a-e2e.test.js test/generate-zod-object-intersections.test.js test/lib/cli-auth-scheme.test.js test/lib/cli-soft-fail.test.js test/lib/cli-webhook-receiver-flag.test.js test/lib/conformance-cli.test.js test/lib/conformance-seeder.test.js test/lib/media-buy-lifecycle-release-gate.test.js test/lib/storyboard-notices.test.js test/lib/storyboard-requires-gate.test.js",
|
|
488
|
+
"test:node:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' ! -name 'server-decisioning-from-platform.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
|
|
489
|
+
"test:node:fast:shard": "test -n \"$TEST_SHARD\" && NODE_ENV=test node --test-timeout=60000 --test-force-exit --test-shard=$TEST_SHARD --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' ! -name 'server-decisioning-from-platform.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
|
|
490
|
+
"test:node:slow": "NODE_ENV=test node --test-timeout=180000 --test-force-exit --test test/canonical-creatives-a2a-e2e.test.js test/generate-zod-object-intersections.test.js test/server-decisioning-from-platform.test.js test/lib/cli-auth-scheme.test.js test/lib/cli-soft-fail.test.js test/lib/cli-webhook-receiver-flag.test.js test/lib/conformance-cli.test.js test/lib/conformance-seeder.test.js test/lib/media-buy-lifecycle-release-gate.test.js test/lib/storyboard-notices.test.js test/lib/storyboard-requires-gate.test.js",
|
|
491
491
|
"pretest:lib": "npm run schemas:ensure",
|
|
492
492
|
"test:lib": "npm run test:lib:fast && npm run test:lib:slow",
|
|
493
493
|
"test:lib:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
|
|
@@ -405,7 +405,7 @@ serve(() => server, {
|
|
|
405
405
|
|
|
406
406
|
- Calls `validatePlatform()` — throws if you advertise a specialism but don't implement it, or define both halves of a method-pair
|
|
407
407
|
- Wraps each method with `AdcpError`-catch + `submitted`-envelope projection for HITL
|
|
408
|
-
- Returns a `DecisioningAdcpServer` (extends `AdcpServer`) with `getTaskState(taskId)` + `awaitTask(taskId)` for HITL inspection
|
|
408
|
+
- Returns a `DecisioningAdcpServer` (extends `AdcpServer`) with scoped `getTaskState(taskId, scope)` + `awaitTask(taskId, scope)` for HITL inspection. Trusted admin/tests may use the explicitly unsafe `getTaskStateUnsafe(taskId)` + `awaitTaskUnsafe(taskId)` helpers.
|
|
409
409
|
|
|
410
410
|
`serve()` accepts the server and binds HTTP transport for both MCP and A2A.
|
|
411
411
|
|
|
@@ -483,7 +483,7 @@ console.log(result.structuredContent);
|
|
|
483
483
|
|
|
484
484
|
`dispatchTestRequest` is the canonical loop for unit-testing platform behavior without HTTP. It's available on `DecisioningAdcpServer` (the type returned by `createAdcpServerFromPlatform`). Set `validation: { requests: 'off' }` while iterating; turn it back to `strict` for end-to-end tests.
|
|
485
485
|
|
|
486
|
-
For HITL platforms, `server.awaitTask(taskId)` settles the background promise; `server.getTaskState(taskId)` reads terminal status.
|
|
486
|
+
For HITL platforms, `server.awaitTask(taskId, scope)` settles the background promise; `server.getTaskState(taskId, scope)` reads terminal status. Use the `*Unsafe(taskId)` variants only in trusted admin or test code.
|
|
487
487
|
|
|
488
488
|
## What NOT to do
|
|
489
489
|
|
|
@@ -289,13 +289,15 @@ import { Pool } from 'pg';
|
|
|
289
289
|
import { createAdcpServerFromPlatform, getAllAdcpMigrations, serve } from '@adcp/sdk/server';
|
|
290
290
|
|
|
291
291
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
292
|
-
|
|
292
|
+
const taskRegistryNamespace = 'tenant:my-agent';
|
|
293
|
+
await pool.query(getAllAdcpMigrations({ taskRegistryNamespace })); // one DDL call, all 3 tables
|
|
293
294
|
|
|
294
295
|
const platform = new MyPlatform(myAdServer);
|
|
295
296
|
const server = createAdcpServerFromPlatform(platform, {
|
|
296
297
|
name: 'My Sales Agent',
|
|
297
298
|
version: '1.0.0',
|
|
298
299
|
pool, // wires idempotency + ctxMetadata + taskRegistry
|
|
300
|
+
taskRegistryNamespace,
|
|
299
301
|
});
|
|
300
302
|
|
|
301
303
|
serve(() => server, { port: process.env.PORT });
|
|
@@ -310,7 +312,7 @@ For dev / single-process: omit `pool` entirely. Framework defaults to in-memory
|
|
|
310
312
|
Things you set up once at deploy time:
|
|
311
313
|
|
|
312
314
|
- [ ] `DATABASE_URL` env var pointing at your Postgres instance
|
|
313
|
-
- [ ] Run `getAllAdcpMigrations()` once per database (idempotent — safe to re-run)
|
|
315
|
+
- [ ] Run `getAllAdcpMigrations({ taskRegistryNamespace })` once per database with a stable, trusted namespace (idempotent — safe to re-run)
|
|
314
316
|
- [ ] OAuth provider config — see `advanced/OAUTH.md` if buyers authenticate via OIDC
|
|
315
317
|
- [ ] `ADCP_VERSION` env (default `3.0.0`) if pinning a specific spec version
|
|
316
318
|
|
|
@@ -267,7 +267,7 @@ sales: SalesPlatform<MyMeta> = {
|
|
|
267
267
|
**The buyer gets terminal state two ways:**
|
|
268
268
|
|
|
269
269
|
1. **Webhook push** — buyer included `push_notification_config: { url, token }` in the original request. Framework signs (RFC 9421) + delivers to that URL with the spec's `mcp-webhook-payload.json` envelope on terminal state. URL is validated server-side: rejects RFC 1918, loopback, link-local, CGNAT, IPv6 unique-local, alternate IPv4 forms, and IPv4-mapped IPv6 before delivery (SSRF guard). Bad URLs FAIL FAST with `INVALID_REQUEST` at the request boundary — buyers see their config error immediately, not as silent webhook drops.
|
|
270
|
-
2. **Polling** — framework auto-registers a `tasks_get` custom tool. Buyers call it with `{ task_id, account }` and receive the spec-flat lifecycle shape (`task_id`, `task_type`, `status`, `created_at`, `updated_at`, `completed_at` on terminal, `result` on completed, top-level `error: { code, message, details? }` on failed). Tenant-scoped — passes `account` through `accounts.resolve(ref, ctx)` and refuses cross-tenant probes with `REFERENCE_NOT_FOUND`. You don't write this tool; it's wired in by the framework.
|
|
270
|
+
2. **Polling** — framework auto-registers a `tasks_get` custom tool. Buyers call it with `{ task_id, account }` and receive the spec-flat lifecycle shape (`task_id`, `task_type`, `status`, `created_at`, `updated_at`, `completed_at` on terminal, `result` on completed, top-level `error: { code, message, details? }` on failed). Tenant-scoped — passes `account` through `accounts.resolve(ref, ctx)` and refuses cross-tenant probes with `REFERENCE_NOT_FOUND`. You don't write this tool; it's wired in by the framework. Scoped application code uses `server.getTaskState(taskId, { accountId, ownerScope })`; explicitly trusted ops and test code can use `server.getTaskStateUnsafe(taskId)`.
|
|
271
271
|
|
|
272
272
|
**Sync-only tools that need long-running completion** use `publishStatusChange(...)` for lifecycle updates instead of HITL. The per-tool wire response schemas don't include `Submitted` arms for `update_media_buy`, `build_creative`, `sync_catalogs`, or `get_products` (a spec inconsistency tracked as [adcp#3392](https://github.com/adcontextprotocol/adcp/issues/3392) — the Submitted schemas exist but aren't rolled into each tool's response `oneOf`). Until the spec consolidates, long-running work on those tools publishes status changes (`media_buy` → `active` → `completed`) on the event bus and buyers subscribe. When adcp#3392 lands, the SDK will widen the unified shape to `update_media_buy`, `build_creative`, and `sync_catalogs` — but NOT to `get_products` (see "Proposal generation" below).
|
|
273
273
|
|
|
@@ -528,7 +528,7 @@ Same pattern for stdio + http transports — `authenticate` runs at the transpor
|
|
|
528
528
|
|
|
529
529
|
The framework's default in-memory `TaskRegistry` is gated by `NODE_ENV` — refuses to construct outside `{test, development}` unless `ADCP_DECISIONING_ALLOW_INMEMORY_TASKS=1` is explicitly set. Every HITL-eligible production deployment needs a durable task registry so task state survives process restarts and load-balancer failover.
|
|
530
530
|
|
|
531
|
-
Ship `createPostgresTaskRegistry({ pool, tableName? })`:
|
|
531
|
+
Ship `createPostgresTaskRegistry({ pool, namespace, tableName? })`:
|
|
532
532
|
|
|
533
533
|
```ts
|
|
534
534
|
import { Pool } from 'pg';
|
|
@@ -540,19 +540,20 @@ import {
|
|
|
540
540
|
|
|
541
541
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
542
542
|
|
|
543
|
-
|
|
544
|
-
|
|
543
|
+
const taskRegistryNamespace = 'tenant:my-agent';
|
|
544
|
+
// Once at boot — idempotent and safe to re-run with the same namespace
|
|
545
|
+
await pool.query(getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace }));
|
|
545
546
|
|
|
546
547
|
const server = createAdcpServerFromPlatform(platform, {
|
|
547
548
|
name: 'My Ad Network',
|
|
548
549
|
version: '1.0.0',
|
|
549
|
-
taskRegistry: createPostgresTaskRegistry({ pool }),
|
|
550
|
+
taskRegistry: createPostgresTaskRegistry({ pool, namespace: taskRegistryNamespace }),
|
|
550
551
|
});
|
|
551
552
|
```
|
|
552
553
|
|
|
553
554
|
Cross-instance reads work — process A allocates the task, process B reads the lifecycle for `tasks_get`. Terminal-state idempotency is enforced via SQL `WHERE status = 'submitted'` so concurrent webhook deliveries can't race to overwrite each other. Background-completion tracking (`_registerBackground`) is process-local — promises don't serialize, so production HITL flows that span process boundaries drive completion via webhook → an explicit `complete()` / `fail()` from the receiving process.
|
|
554
555
|
|
|
555
|
-
Custom backend? Implement the `TaskRegistry` interface
|
|
556
|
+
Custom backend? Implement the scoped `TaskRegistry` interface for Redis / DynamoDB / Spanner / etc. The framework awaits every storage method; apply both `accountId` and `ownerScope` on every read and write, then set `scopeVersion: 1`. Keep the explicitly named unsafe methods limited to trusted administrative and test paths.
|
|
556
557
|
|
|
557
558
|
**Adopter `*Task` return size cap.** Postgres-backed registries cap `result` / `error` JSONB rows at 4MB. Returns over the cap surface via `onTaskTransition` with `errorCode: 'REGISTRY_WRITE_FAILED'` and skip webhook delivery (registry state is inconsistent, so the framework refuses to push). Offload large payloads to blob storage and return references in the result body instead. The cap protects the DB write path only — adopter code that serializes `result` for logs/metrics MUST impose its own bound.
|
|
558
559
|
|