@adcp/sdk 14.0.0-beta.14 → 14.0.0-beta.15
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/auth/oauth/authorization-required.d.mts +25 -11
- package/dist/lib/auth/oauth/authorization-required.d.ts +25 -11
- package/dist/lib/auth/oauth/authorization-required.js +18 -4
- package/dist/lib/auth/oauth/authorization-required.mjs +17 -4
- package/dist/lib/auth/oauth/index.d.mts +1 -1
- package/dist/lib/auth/oauth/index.d.ts +1 -1
- package/dist/lib/auth/oauth/index.js +2 -0
- package/dist/lib/auth/oauth/index.mjs +2 -0
- package/dist/lib/auth/oauth/resource-url.d.mts +8 -0
- package/dist/lib/auth/oauth/resource-url.d.ts +8 -0
- package/dist/lib/auth/oauth/resource-url.js +42 -0
- package/dist/lib/auth/oauth/resource-url.mjs +40 -0
- package/dist/lib/core/ConversationTypes.d.mts +10 -0
- package/dist/lib/core/ConversationTypes.d.ts +10 -0
- package/dist/lib/core/SingleAgentClient.d.mts +5 -2
- package/dist/lib/core/SingleAgentClient.d.ts +5 -2
- package/dist/lib/core/SingleAgentClient.js +133 -28
- package/dist/lib/core/SingleAgentClient.mjs +138 -29
- package/dist/lib/core/TaskExecutor.d.mts +1 -0
- package/dist/lib/core/TaskExecutor.d.ts +1 -0
- package/dist/lib/core/TaskExecutor.js +7 -1
- package/dist/lib/core/TaskExecutor.mjs +7 -1
- package/dist/lib/core/webhook-registration.d.mts +8 -1
- package/dist/lib/core/webhook-registration.d.ts +8 -1
- package/dist/lib/core/webhook-registration.js +65 -5
- package/dist/lib/core/webhook-registration.mjs +61 -4
- package/dist/lib/errors/index.d.mts +9 -0
- package/dist/lib/errors/index.d.ts +9 -0
- package/dist/lib/errors/index.js +33 -0
- package/dist/lib/errors/index.mjs +32 -0
- package/dist/lib/index.d.mts +3 -2
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/media-buy/compatibility.js +14 -2
- package/dist/lib/media-buy/compatibility.mjs +14 -2
- package/dist/lib/protocols/index.js +23 -7
- package/dist/lib/protocols/index.mjs +24 -8
- package/dist/lib/protocols/mcp.js +8 -6
- package/dist/lib/protocols/mcp.mjs +9 -7
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/async-outcome.d.mts +11 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts +11 -0
- package/dist/lib/server/decisioning/context.d.mts +11 -1
- package/dist/lib/server/decisioning/context.d.ts +11 -1
- package/dist/lib/server/decisioning/index.d.mts +3 -2
- package/dist/lib/server/decisioning/index.d.ts +3 -2
- package/dist/lib/server/decisioning/index.js +9 -0
- package/dist/lib/server/decisioning/index.mjs +10 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -2
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -2
- package/dist/lib/server/decisioning/runtime/from-platform.js +40 -8
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +40 -8
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +8 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +8 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +10 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +9 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.mts +79 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.ts +79 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.js +391 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.mjs +369 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.mts +2 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +2 -0
- package/dist/lib/server/decisioning/runtime/task-registry.js +2 -1
- package/dist/lib/server/decisioning/runtime/task-registry.mjs +2 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +15 -11
- package/dist/lib/server/decisioning/runtime/to-context.mjs +15 -11
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +4 -0
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/webhook-delivery/index.d.mts +2 -2
- package/dist/lib/server/webhook-delivery/index.d.ts +2 -2
- package/dist/lib/server/webhook-delivery/index.js +4 -0
- package/dist/lib/server/webhook-delivery/index.mjs +5 -1
- package/dist/lib/server/webhook-delivery/pg.d.mts +3 -1
- package/dist/lib/server/webhook-delivery/pg.d.ts +3 -1
- package/dist/lib/server/webhook-delivery/pg.js +25 -2
- package/dist/lib/server/webhook-delivery/pg.mjs +25 -2
- package/dist/lib/server/webhook-delivery/recovery.d.mts +44 -0
- package/dist/lib/server/webhook-delivery/recovery.d.ts +44 -0
- package/dist/lib/server/webhook-delivery/recovery.js +146 -43
- package/dist/lib/server/webhook-delivery/recovery.mjs +144 -43
- package/dist/lib/signing/agent-resolver/index.d.mts +1 -1
- package/dist/lib/signing/agent-resolver/index.d.ts +1 -1
- package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +9 -0
- package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +9 -0
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +4 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +4 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +17 -4
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +17 -4
- package/dist/lib/signing/jwks.d.mts +7 -0
- package/dist/lib/signing/jwks.d.ts +7 -0
- package/dist/lib/signing/server.d.mts +2 -2
- package/dist/lib/signing/server.d.ts +2 -2
- package/dist/lib/signing/webhook-verifier.d.mts +6 -0
- package/dist/lib/signing/webhook-verifier.d.ts +6 -0
- package/dist/lib/signing/webhook-verifier.js +38 -4
- package/dist/lib/signing/webhook-verifier.mjs +38 -4
- package/dist/lib/testing/client.d.mts +1 -0
- package/dist/lib/testing/client.d.ts +1 -0
- package/dist/lib/testing/client.js +6 -2
- package/dist/lib/testing/client.mjs +6 -2
- package/dist/lib/testing/compliance/comply.d.mts +2 -2
- package/dist/lib/testing/compliance/comply.d.ts +2 -2
- package/dist/lib/testing/compliance/comply.js +41 -31
- package/dist/lib/testing/compliance/comply.mjs +44 -21
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +1 -7
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +1 -7
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +6 -42
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +10 -40
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/utils/adcp-version-config.d.mts +2 -0
- package/dist/lib/utils/adcp-version-config.d.ts +2 -0
- package/dist/lib/utils/adcp-version-config.js +5 -0
- package/dist/lib/utils/adcp-version-config.mjs +4 -0
- 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.mjs +3 -3
- package/docs/llms.txt +3 -1
- package/docs/migration-12-to-14.md +6 -5
- package/docs/migration-13-to-14.md +48 -7
- package/docs/migration-task-registry-scoping.md +164 -11
- package/package.json +1 -1
- package/skills/build-decisioning-platform/advanced/REFERENCE.md +1 -1
|
@@ -1267,12 +1267,14 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1267
1267
|
mediaBuy: opts.legacyHandlers?.mediaBuy ?? runtimeLegacyOptions.mediaBuy,
|
|
1268
1268
|
creative: opts.legacyHandlers?.creative ?? runtimeLegacyOptions.creative,
|
|
1269
1269
|
governance: opts.legacyHandlers?.governance ?? runtimeLegacyOptions.governance,
|
|
1270
|
-
brandRights: opts.legacyHandlers?.brandRights ?? runtimeLegacyOptions.brandRights
|
|
1270
|
+
brandRights: opts.legacyHandlers?.brandRights ?? runtimeLegacyOptions.brandRights,
|
|
1271
|
+
signals: opts.legacyHandlers?.signals ?? runtimeLegacyOptions.signals
|
|
1271
1272
|
};
|
|
1272
1273
|
(0, import_validate_platform.validatePlatform)(platform, {
|
|
1273
1274
|
creative: legacyHandlers.creative,
|
|
1274
1275
|
campaignGovernance: legacyHandlers.governance,
|
|
1275
|
-
brandRights: legacyHandlers.brandRights
|
|
1276
|
+
brandRights: legacyHandlers.brandRights,
|
|
1277
|
+
signals: legacyHandlers.signals
|
|
1276
1278
|
});
|
|
1277
1279
|
{
|
|
1278
1280
|
const specialisms = platform.capabilities.specialisms;
|
|
@@ -1281,7 +1283,8 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1281
1283
|
mediaBuy: legacyHandlers.mediaBuy,
|
|
1282
1284
|
creative: platform.creative ?? legacyHandlers.creative,
|
|
1283
1285
|
governance: legacyHandlers.governance,
|
|
1284
|
-
brandRights: platform.brandRights ?? legacyHandlers.brandRights
|
|
1286
|
+
brandRights: platform.brandRights ?? legacyHandlers.brandRights,
|
|
1287
|
+
signals: platform.signals ?? legacyHandlers.signals
|
|
1285
1288
|
};
|
|
1286
1289
|
const issues = (0, import_validate_specialisms.validateSpecialismRequiredTools)(effectiveSpecialismSurface, specialisms);
|
|
1287
1290
|
if (issues.length > 0) {
|
|
@@ -1698,7 +1701,7 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1698
1701
|
mergeOpts
|
|
1699
1702
|
),
|
|
1700
1703
|
signals: mergeHandlers(
|
|
1701
|
-
|
|
1704
|
+
legacyHandlers.signals,
|
|
1702
1705
|
buildSignalsHandlers(
|
|
1703
1706
|
platform,
|
|
1704
1707
|
taskRegistry,
|
|
@@ -2535,6 +2538,17 @@ async function routeIfHandoff(taskRegistry, opts, result, project) {
|
|
|
2535
2538
|
return await project(result);
|
|
2536
2539
|
}
|
|
2537
2540
|
const { fn: taskFn, options } = entry;
|
|
2541
|
+
if (options && "settlement" in options && options.settlement === "external") {
|
|
2542
|
+
return dispatchHitl(
|
|
2543
|
+
taskRegistry,
|
|
2544
|
+
opts,
|
|
2545
|
+
async (taskRef) => {
|
|
2546
|
+
await taskFn((0, import_to_context.buildHandoffContext)(taskRegistry, taskRef));
|
|
2547
|
+
},
|
|
2548
|
+
options.task_id,
|
|
2549
|
+
"external"
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2538
2552
|
return dispatchHitl(
|
|
2539
2553
|
taskRegistry,
|
|
2540
2554
|
opts,
|
|
@@ -2550,7 +2564,10 @@ async function routeIfHandoff(taskRegistry, opts, result, project) {
|
|
|
2550
2564
|
rejectResponseSummary(result);
|
|
2551
2565
|
return await project(result);
|
|
2552
2566
|
}
|
|
2553
|
-
async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId) {
|
|
2567
|
+
async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId, settlement = "framework") {
|
|
2568
|
+
if (settlement === "external" && taskRegistry.durability !== "durable") {
|
|
2569
|
+
throw new Error("External task settlement requires a durable task registry with a stable identity");
|
|
2570
|
+
}
|
|
2554
2571
|
const createStart = Date.now();
|
|
2555
2572
|
const createdRef = await taskRegistry.create({
|
|
2556
2573
|
tool: opts.tool,
|
|
@@ -2599,6 +2616,20 @@ async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId) {
|
|
|
2599
2616
|
opts.logger
|
|
2600
2617
|
);
|
|
2601
2618
|
};
|
|
2619
|
+
if (settlement === "external") {
|
|
2620
|
+
if (typeof taskRef.registryId !== "string" || taskRef.registryId.length === 0) {
|
|
2621
|
+
throw new Error("External task settlement requires a durable task registry with a stable identity");
|
|
2622
|
+
}
|
|
2623
|
+
try {
|
|
2624
|
+
await taskFn(taskRef);
|
|
2625
|
+
} catch (taskFnError) {
|
|
2626
|
+
opts.logger.error(
|
|
2627
|
+
`[adcp/decisioning] external task producer for ${taskId} (${opts.tool}) failed before durable handoff. Task remains submitted internally; no terminal state, webhook, or buyer acknowledgment was written. Error type: ${taskFnError instanceof Error ? "Error" : typeof taskFnError}`
|
|
2628
|
+
);
|
|
2629
|
+
throw new Error("External task producer failed before durable handoff");
|
|
2630
|
+
}
|
|
2631
|
+
return { status: "submitted", task_id: taskId };
|
|
2632
|
+
}
|
|
2602
2633
|
const completion = (async () => {
|
|
2603
2634
|
const registryScope = taskRef;
|
|
2604
2635
|
let result;
|
|
@@ -3137,12 +3168,13 @@ function validatePushNotificationUrl(rawUrl, opts = {}) {
|
|
|
3137
3168
|
}
|
|
3138
3169
|
return { ok: true };
|
|
3139
3170
|
}
|
|
3140
|
-
const
|
|
3171
|
+
const TOKEN_MIN_LENGTH = 16;
|
|
3172
|
+
const TOKEN_MAX_LENGTH = 4096;
|
|
3141
3173
|
const TOKEN_CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/;
|
|
3142
3174
|
const PUSH_OPERATION_ID_RE = /^[A-Za-z0-9_.:-]{1,255}$/;
|
|
3143
3175
|
function validatePushNotificationToken(token) {
|
|
3144
|
-
if (token.length
|
|
3145
|
-
return { ok: false, reason:
|
|
3176
|
+
if (token.length < TOKEN_MIN_LENGTH) {
|
|
3177
|
+
return { ok: false, reason: `token shorter than ${TOKEN_MIN_LENGTH} chars` };
|
|
3146
3178
|
}
|
|
3147
3179
|
if (token.length > TOKEN_MAX_LENGTH) {
|
|
3148
3180
|
return { ok: false, reason: `token longer than ${TOKEN_MAX_LENGTH} chars` };
|
|
@@ -1287,12 +1287,14 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1287
1287
|
mediaBuy: opts.legacyHandlers?.mediaBuy ?? runtimeLegacyOptions.mediaBuy,
|
|
1288
1288
|
creative: opts.legacyHandlers?.creative ?? runtimeLegacyOptions.creative,
|
|
1289
1289
|
governance: opts.legacyHandlers?.governance ?? runtimeLegacyOptions.governance,
|
|
1290
|
-
brandRights: opts.legacyHandlers?.brandRights ?? runtimeLegacyOptions.brandRights
|
|
1290
|
+
brandRights: opts.legacyHandlers?.brandRights ?? runtimeLegacyOptions.brandRights,
|
|
1291
|
+
signals: opts.legacyHandlers?.signals ?? runtimeLegacyOptions.signals
|
|
1291
1292
|
};
|
|
1292
1293
|
validatePlatform(platform, {
|
|
1293
1294
|
creative: legacyHandlers.creative,
|
|
1294
1295
|
campaignGovernance: legacyHandlers.governance,
|
|
1295
|
-
brandRights: legacyHandlers.brandRights
|
|
1296
|
+
brandRights: legacyHandlers.brandRights,
|
|
1297
|
+
signals: legacyHandlers.signals
|
|
1296
1298
|
});
|
|
1297
1299
|
{
|
|
1298
1300
|
const specialisms = platform.capabilities.specialisms;
|
|
@@ -1301,7 +1303,8 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1301
1303
|
mediaBuy: legacyHandlers.mediaBuy,
|
|
1302
1304
|
creative: platform.creative ?? legacyHandlers.creative,
|
|
1303
1305
|
governance: legacyHandlers.governance,
|
|
1304
|
-
brandRights: platform.brandRights ?? legacyHandlers.brandRights
|
|
1306
|
+
brandRights: platform.brandRights ?? legacyHandlers.brandRights,
|
|
1307
|
+
signals: platform.signals ?? legacyHandlers.signals
|
|
1305
1308
|
};
|
|
1306
1309
|
const issues = validateSpecialismRequiredTools(effectiveSpecialismSurface, specialisms);
|
|
1307
1310
|
if (issues.length > 0) {
|
|
@@ -1718,7 +1721,7 @@ function createAdcpServerFromPlatform(platform, opts) {
|
|
|
1718
1721
|
mergeOpts
|
|
1719
1722
|
),
|
|
1720
1723
|
signals: mergeHandlers(
|
|
1721
|
-
|
|
1724
|
+
legacyHandlers.signals,
|
|
1722
1725
|
buildSignalsHandlers(
|
|
1723
1726
|
platform,
|
|
1724
1727
|
taskRegistry,
|
|
@@ -2555,6 +2558,17 @@ async function routeIfHandoff(taskRegistry, opts, result, project) {
|
|
|
2555
2558
|
return await project(result);
|
|
2556
2559
|
}
|
|
2557
2560
|
const { fn: taskFn, options } = entry;
|
|
2561
|
+
if (options && "settlement" in options && options.settlement === "external") {
|
|
2562
|
+
return dispatchHitl(
|
|
2563
|
+
taskRegistry,
|
|
2564
|
+
opts,
|
|
2565
|
+
async (taskRef) => {
|
|
2566
|
+
await taskFn(buildHandoffContext(taskRegistry, taskRef));
|
|
2567
|
+
},
|
|
2568
|
+
options.task_id,
|
|
2569
|
+
"external"
|
|
2570
|
+
);
|
|
2571
|
+
}
|
|
2558
2572
|
return dispatchHitl(
|
|
2559
2573
|
taskRegistry,
|
|
2560
2574
|
opts,
|
|
@@ -2570,7 +2584,10 @@ async function routeIfHandoff(taskRegistry, opts, result, project) {
|
|
|
2570
2584
|
rejectResponseSummary(result);
|
|
2571
2585
|
return await project(result);
|
|
2572
2586
|
}
|
|
2573
|
-
async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId) {
|
|
2587
|
+
async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId, settlement = "framework") {
|
|
2588
|
+
if (settlement === "external" && taskRegistry.durability !== "durable") {
|
|
2589
|
+
throw new Error("External task settlement requires a durable task registry with a stable identity");
|
|
2590
|
+
}
|
|
2574
2591
|
const createStart = Date.now();
|
|
2575
2592
|
const createdRef = await taskRegistry.create({
|
|
2576
2593
|
tool: opts.tool,
|
|
@@ -2619,6 +2636,20 @@ async function dispatchHitl(taskRegistry, opts, taskFn, overrideTaskId) {
|
|
|
2619
2636
|
opts.logger
|
|
2620
2637
|
);
|
|
2621
2638
|
};
|
|
2639
|
+
if (settlement === "external") {
|
|
2640
|
+
if (typeof taskRef.registryId !== "string" || taskRef.registryId.length === 0) {
|
|
2641
|
+
throw new Error("External task settlement requires a durable task registry with a stable identity");
|
|
2642
|
+
}
|
|
2643
|
+
try {
|
|
2644
|
+
await taskFn(taskRef);
|
|
2645
|
+
} catch (taskFnError) {
|
|
2646
|
+
opts.logger.error(
|
|
2647
|
+
`[adcp/decisioning] external task producer for ${taskId} (${opts.tool}) failed before durable handoff. Task remains submitted internally; no terminal state, webhook, or buyer acknowledgment was written. Error type: ${taskFnError instanceof Error ? "Error" : typeof taskFnError}`
|
|
2648
|
+
);
|
|
2649
|
+
throw new Error("External task producer failed before durable handoff");
|
|
2650
|
+
}
|
|
2651
|
+
return { status: "submitted", task_id: taskId };
|
|
2652
|
+
}
|
|
2622
2653
|
const completion = (async () => {
|
|
2623
2654
|
const registryScope = taskRef;
|
|
2624
2655
|
let result;
|
|
@@ -3157,12 +3188,13 @@ function validatePushNotificationUrl(rawUrl, opts = {}) {
|
|
|
3157
3188
|
}
|
|
3158
3189
|
return { ok: true };
|
|
3159
3190
|
}
|
|
3160
|
-
const
|
|
3191
|
+
const TOKEN_MIN_LENGTH = 16;
|
|
3192
|
+
const TOKEN_MAX_LENGTH = 4096;
|
|
3161
3193
|
const TOKEN_CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/;
|
|
3162
3194
|
const PUSH_OPERATION_ID_RE = /^[A-Za-z0-9_.:-]{1,255}$/;
|
|
3163
3195
|
function validatePushNotificationToken(token) {
|
|
3164
|
-
if (token.length
|
|
3165
|
-
return { ok: false, reason:
|
|
3196
|
+
if (token.length < TOKEN_MIN_LENGTH) {
|
|
3197
|
+
return { ok: false, reason: `token shorter than ${TOKEN_MIN_LENGTH} chars` };
|
|
3166
3198
|
}
|
|
3167
3199
|
if (token.length > TOKEN_MAX_LENGTH) {
|
|
3168
3200
|
return { ok: false, reason: `token longer than ${TOKEN_MAX_LENGTH} chars` };
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
* process boundaries may use `completeScopedTask()` / `failScopedTask()` for
|
|
45
45
|
* polling-only tasks after persisting the full issued reference. Registry-only
|
|
46
46
|
* settlement rejects buyer push-notification tasks because it cannot durably
|
|
47
|
-
* deliver their terminal webhook; those
|
|
47
|
+
* deliver their terminal webhook; settle those with
|
|
48
|
+
* `createPostgresTaskSettlementCoordinator()` in a trusted worker.
|
|
48
49
|
* The MCP `tasks/get` wire path reads via `getTask` and is cross-instance.
|
|
49
50
|
*
|
|
50
51
|
* Status: Preview / 6.0.
|
|
@@ -63,6 +64,12 @@ export interface PgQueryable {
|
|
|
63
64
|
rowCount: number | null;
|
|
64
65
|
}>;
|
|
65
66
|
}
|
|
67
|
+
export interface PgTransactionClient extends PgQueryable {
|
|
68
|
+
release(): void;
|
|
69
|
+
}
|
|
70
|
+
export interface PgTransactionalPool extends PgQueryable {
|
|
71
|
+
connect(): Promise<PgTransactionClient>;
|
|
72
|
+
}
|
|
66
73
|
export interface CreatePostgresTaskRegistryOptions {
|
|
67
74
|
/** A `pg.Pool` instance (or any `PgQueryable`). */
|
|
68
75
|
pool: PgQueryable;
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
* process boundaries may use `completeScopedTask()` / `failScopedTask()` for
|
|
45
45
|
* polling-only tasks after persisting the full issued reference. Registry-only
|
|
46
46
|
* settlement rejects buyer push-notification tasks because it cannot durably
|
|
47
|
-
* deliver their terminal webhook; those
|
|
47
|
+
* deliver their terminal webhook; settle those with
|
|
48
|
+
* `createPostgresTaskSettlementCoordinator()` in a trusted worker.
|
|
48
49
|
* The MCP `tasks/get` wire path reads via `getTask` and is cross-instance.
|
|
49
50
|
*
|
|
50
51
|
* Status: Preview / 6.0.
|
|
@@ -63,6 +64,12 @@ export interface PgQueryable {
|
|
|
63
64
|
rowCount: number | null;
|
|
64
65
|
}>;
|
|
65
66
|
}
|
|
67
|
+
export interface PgTransactionClient extends PgQueryable {
|
|
68
|
+
release(): void;
|
|
69
|
+
}
|
|
70
|
+
export interface PgTransactionalPool extends PgQueryable {
|
|
71
|
+
connect(): Promise<PgTransactionClient>;
|
|
72
|
+
}
|
|
66
73
|
export interface CreatePostgresTaskRegistryOptions {
|
|
67
74
|
/** A `pg.Pool` instance (or any `PgQueryable`). */
|
|
68
75
|
pool: PgQueryable;
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var postgres_task_registry_exports = {};
|
|
20
20
|
__export(postgres_task_registry_exports, {
|
|
21
|
+
_postgresTaskRegistryBinding: () => _postgresTaskRegistryBinding,
|
|
21
22
|
createPostgresTaskRegistry: () => createPostgresTaskRegistry,
|
|
22
23
|
getDecisioningTaskRegistryBootstrap: () => getDecisioningTaskRegistryBootstrap,
|
|
23
24
|
getDecisioningTaskRegistryMigration: () => getDecisioningTaskRegistryMigration,
|
|
@@ -26,6 +27,10 @@ __export(postgres_task_registry_exports, {
|
|
|
26
27
|
module.exports = __toCommonJS(postgres_task_registry_exports);
|
|
27
28
|
var import_node_crypto = require("node:crypto");
|
|
28
29
|
var import_task_registry = require('./task-registry.js');
|
|
30
|
+
const postgresTaskRegistryBindings = /* @__PURE__ */ new WeakMap();
|
|
31
|
+
function _postgresTaskRegistryBinding(registry) {
|
|
32
|
+
return postgresTaskRegistryBindings.get(registry);
|
|
33
|
+
}
|
|
29
34
|
const DEFAULT_TABLE = "adcp_decisioning_tasks";
|
|
30
35
|
const VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
|
|
31
36
|
const VALID_NAMESPACE = /^[A-Za-z0-9_.:-]{1,255}$/;
|
|
@@ -416,8 +421,9 @@ function createPostgresTaskRegistry(opts) {
|
|
|
416
421
|
throw payloadError;
|
|
417
422
|
};
|
|
418
423
|
const backgrounds = /* @__PURE__ */ new Map();
|
|
419
|
-
|
|
424
|
+
const registry = {
|
|
420
425
|
scopeVersion: 1,
|
|
426
|
+
durability: "durable",
|
|
421
427
|
registryId,
|
|
422
428
|
async create(createOpts) {
|
|
423
429
|
const taskId = createOpts.overrideTaskId ?? `task_${(0, import_node_crypto.randomUUID)()}`;
|
|
@@ -581,9 +587,12 @@ function createPostgresTaskRegistry(opts) {
|
|
|
581
587
|
await Promise.all(pending);
|
|
582
588
|
}
|
|
583
589
|
};
|
|
590
|
+
postgresTaskRegistryBindings.set(registry, { pool, namespace, tableName: table });
|
|
591
|
+
return registry;
|
|
584
592
|
}
|
|
585
593
|
// Annotate the CommonJS export names for ESM import in node:
|
|
586
594
|
0 && (module.exports = {
|
|
595
|
+
_postgresTaskRegistryBinding,
|
|
587
596
|
createPostgresTaskRegistry,
|
|
588
597
|
getDecisioningTaskRegistryBootstrap,
|
|
589
598
|
getDecisioningTaskRegistryMigration,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { sanitizeTaskProgressForStorage } from "./task-registry.mjs";
|
|
3
|
+
const postgresTaskRegistryBindings = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function _postgresTaskRegistryBinding(registry) {
|
|
5
|
+
return postgresTaskRegistryBindings.get(registry);
|
|
6
|
+
}
|
|
3
7
|
const DEFAULT_TABLE = "adcp_decisioning_tasks";
|
|
4
8
|
const VALID_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
|
|
5
9
|
const VALID_NAMESPACE = /^[A-Za-z0-9_.:-]{1,255}$/;
|
|
@@ -390,8 +394,9 @@ function createPostgresTaskRegistry(opts) {
|
|
|
390
394
|
throw payloadError;
|
|
391
395
|
};
|
|
392
396
|
const backgrounds = /* @__PURE__ */ new Map();
|
|
393
|
-
|
|
397
|
+
const registry = {
|
|
394
398
|
scopeVersion: 1,
|
|
399
|
+
durability: "durable",
|
|
395
400
|
registryId,
|
|
396
401
|
async create(createOpts) {
|
|
397
402
|
const taskId = createOpts.overrideTaskId ?? `task_${randomUUID()}`;
|
|
@@ -555,8 +560,11 @@ function createPostgresTaskRegistry(opts) {
|
|
|
555
560
|
await Promise.all(pending);
|
|
556
561
|
}
|
|
557
562
|
};
|
|
563
|
+
postgresTaskRegistryBindings.set(registry, { pool, namespace, tableName: table });
|
|
564
|
+
return registry;
|
|
558
565
|
}
|
|
559
566
|
export {
|
|
567
|
+
_postgresTaskRegistryBinding,
|
|
560
568
|
createPostgresTaskRegistry,
|
|
561
569
|
getDecisioningTaskRegistryBootstrap,
|
|
562
570
|
getDecisioningTaskRegistryMigration,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe PostgreSQL settlement for push-enabled decisioning tasks.
|
|
3
|
+
*
|
|
4
|
+
* The task transition and terminal webhook outbox checkpoint commit in one
|
|
5
|
+
* database transaction. Delivery remains the existing webhook recovery
|
|
6
|
+
* worker's responsibility, so a process can die after commit without losing
|
|
7
|
+
* the buyer's promised terminal notification.
|
|
8
|
+
*/
|
|
9
|
+
import type { AdcpStructuredError } from '../async-outcome.mjs';
|
|
10
|
+
import type { WebhookAuthentication, WebhookRetryOptions } from '../../webhook-emitter.mjs';
|
|
11
|
+
import { type CreateWebhookDeliveryRecoveryOptions, type DurableWebhookDeliveryRecovery, type WebhookAuthenticationAdapter } from '../../webhook-delivery/recovery.mjs';
|
|
12
|
+
import { type PgWebhookDeliveryRecoveryOptions } from '../../webhook-delivery/pg.mjs';
|
|
13
|
+
import { type ScopedTaskRef, type TaskRegistry, type TaskStatus } from './task-registry.mjs';
|
|
14
|
+
export interface TaskPushSettlementConfig {
|
|
15
|
+
/** Validated destination from the original push_notification_config. */
|
|
16
|
+
url: string;
|
|
17
|
+
/** Original buyer correlation identity. */
|
|
18
|
+
operationId?: string;
|
|
19
|
+
/** Negotiated AdCP version; required when operationId is absent to prove a legacy route. */
|
|
20
|
+
servedAdcpVersion?: string;
|
|
21
|
+
/** Optional validation token echoed in the task-webhook payload. */
|
|
22
|
+
token?: string;
|
|
23
|
+
/** Optional legacy transport authentication. RFC 9421 remains the baseline. */
|
|
24
|
+
authentication?: WebhookAuthentication;
|
|
25
|
+
}
|
|
26
|
+
export type TaskPushDeliveryState = 'durably_bound' | 'recoverable' | 'delivered' | 'terminal';
|
|
27
|
+
export type TaskPushSettlementOutcome = {
|
|
28
|
+
outcome: 'applied';
|
|
29
|
+
delivery: 'durably_bound';
|
|
30
|
+
} | {
|
|
31
|
+
outcome: 'already_terminal';
|
|
32
|
+
status: TaskStatus;
|
|
33
|
+
compatibility: 'compatible';
|
|
34
|
+
delivery: TaskPushDeliveryState;
|
|
35
|
+
} | {
|
|
36
|
+
outcome: 'already_terminal';
|
|
37
|
+
status: TaskStatus;
|
|
38
|
+
compatibility: 'conflicting';
|
|
39
|
+
delivery: 'not_applicable';
|
|
40
|
+
} | {
|
|
41
|
+
outcome: 'not_found_in_scope';
|
|
42
|
+
delivery: 'not_applicable';
|
|
43
|
+
};
|
|
44
|
+
type TerminalSettlement = {
|
|
45
|
+
status: 'completed';
|
|
46
|
+
result: unknown;
|
|
47
|
+
} | {
|
|
48
|
+
status: 'failed';
|
|
49
|
+
error: AdcpStructuredError;
|
|
50
|
+
result?: unknown;
|
|
51
|
+
};
|
|
52
|
+
export interface PostgresTaskSettlementCoordinatorOptions {
|
|
53
|
+
/** The exact PostgreSQL registry that issued the ScopedTaskRef. */
|
|
54
|
+
registry: TaskRegistry;
|
|
55
|
+
/** Stable publisher namespace; normally the server's configured name. */
|
|
56
|
+
publisherScope: string;
|
|
57
|
+
/** PostgreSQL outbox options. The outbox is always created on the registry's pool. */
|
|
58
|
+
outbox?: PgWebhookDeliveryRecoveryOptions;
|
|
59
|
+
/** Required when push tokens or legacy transport credentials are present. */
|
|
60
|
+
authenticationAdapter?: WebhookAuthenticationAdapter;
|
|
61
|
+
/** Recovery lease/snapshot limits shared with the returned recovery worker. */
|
|
62
|
+
recovery?: Omit<CreateWebhookDeliveryRecoveryOptions, 'backend' | 'authenticationAdapter'>;
|
|
63
|
+
/** Retry policy persisted with every terminal snapshot. */
|
|
64
|
+
retries?: WebhookRetryOptions;
|
|
65
|
+
}
|
|
66
|
+
export interface PostgresTaskSettlementCoordinator {
|
|
67
|
+
readonly durability: 'durable';
|
|
68
|
+
/** Wire this into the normal webhook recovery poller/emitter. */
|
|
69
|
+
readonly recovery: DurableWebhookDeliveryRecovery;
|
|
70
|
+
settle(ref: ScopedTaskRef, terminal: TerminalSettlement, push: TaskPushSettlementConfig): Promise<TaskPushSettlementOutcome>;
|
|
71
|
+
}
|
|
72
|
+
/** Configuration or immutable-delivery conflict detected before commit. */
|
|
73
|
+
export declare class TaskPushSettlementConfigurationError extends Error {
|
|
74
|
+
readonly name = "TaskPushSettlementConfigurationError";
|
|
75
|
+
}
|
|
76
|
+
export declare function createPostgresTaskSettlementCoordinator(options: PostgresTaskSettlementCoordinatorOptions): PostgresTaskSettlementCoordinator;
|
|
77
|
+
export declare function completeScopedPushTask<TResult>(coordinator: PostgresTaskSettlementCoordinator, ref: ScopedTaskRef, push: TaskPushSettlementConfig, result: TResult): Promise<TaskPushSettlementOutcome>;
|
|
78
|
+
export declare function failScopedPushTask(coordinator: PostgresTaskSettlementCoordinator, ref: ScopedTaskRef, push: TaskPushSettlementConfig, error: AdcpStructuredError, result?: unknown): Promise<TaskPushSettlementOutcome>;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe PostgreSQL settlement for push-enabled decisioning tasks.
|
|
3
|
+
*
|
|
4
|
+
* The task transition and terminal webhook outbox checkpoint commit in one
|
|
5
|
+
* database transaction. Delivery remains the existing webhook recovery
|
|
6
|
+
* worker's responsibility, so a process can die after commit without losing
|
|
7
|
+
* the buyer's promised terminal notification.
|
|
8
|
+
*/
|
|
9
|
+
import type { AdcpStructuredError } from '../async-outcome';
|
|
10
|
+
import type { WebhookAuthentication, WebhookRetryOptions } from '../../webhook-emitter';
|
|
11
|
+
import { type CreateWebhookDeliveryRecoveryOptions, type DurableWebhookDeliveryRecovery, type WebhookAuthenticationAdapter } from '../../webhook-delivery/recovery';
|
|
12
|
+
import { type PgWebhookDeliveryRecoveryOptions } from '../../webhook-delivery/pg';
|
|
13
|
+
import { type ScopedTaskRef, type TaskRegistry, type TaskStatus } from './task-registry';
|
|
14
|
+
export interface TaskPushSettlementConfig {
|
|
15
|
+
/** Validated destination from the original push_notification_config. */
|
|
16
|
+
url: string;
|
|
17
|
+
/** Original buyer correlation identity. */
|
|
18
|
+
operationId?: string;
|
|
19
|
+
/** Negotiated AdCP version; required when operationId is absent to prove a legacy route. */
|
|
20
|
+
servedAdcpVersion?: string;
|
|
21
|
+
/** Optional validation token echoed in the task-webhook payload. */
|
|
22
|
+
token?: string;
|
|
23
|
+
/** Optional legacy transport authentication. RFC 9421 remains the baseline. */
|
|
24
|
+
authentication?: WebhookAuthentication;
|
|
25
|
+
}
|
|
26
|
+
export type TaskPushDeliveryState = 'durably_bound' | 'recoverable' | 'delivered' | 'terminal';
|
|
27
|
+
export type TaskPushSettlementOutcome = {
|
|
28
|
+
outcome: 'applied';
|
|
29
|
+
delivery: 'durably_bound';
|
|
30
|
+
} | {
|
|
31
|
+
outcome: 'already_terminal';
|
|
32
|
+
status: TaskStatus;
|
|
33
|
+
compatibility: 'compatible';
|
|
34
|
+
delivery: TaskPushDeliveryState;
|
|
35
|
+
} | {
|
|
36
|
+
outcome: 'already_terminal';
|
|
37
|
+
status: TaskStatus;
|
|
38
|
+
compatibility: 'conflicting';
|
|
39
|
+
delivery: 'not_applicable';
|
|
40
|
+
} | {
|
|
41
|
+
outcome: 'not_found_in_scope';
|
|
42
|
+
delivery: 'not_applicable';
|
|
43
|
+
};
|
|
44
|
+
type TerminalSettlement = {
|
|
45
|
+
status: 'completed';
|
|
46
|
+
result: unknown;
|
|
47
|
+
} | {
|
|
48
|
+
status: 'failed';
|
|
49
|
+
error: AdcpStructuredError;
|
|
50
|
+
result?: unknown;
|
|
51
|
+
};
|
|
52
|
+
export interface PostgresTaskSettlementCoordinatorOptions {
|
|
53
|
+
/** The exact PostgreSQL registry that issued the ScopedTaskRef. */
|
|
54
|
+
registry: TaskRegistry;
|
|
55
|
+
/** Stable publisher namespace; normally the server's configured name. */
|
|
56
|
+
publisherScope: string;
|
|
57
|
+
/** PostgreSQL outbox options. The outbox is always created on the registry's pool. */
|
|
58
|
+
outbox?: PgWebhookDeliveryRecoveryOptions;
|
|
59
|
+
/** Required when push tokens or legacy transport credentials are present. */
|
|
60
|
+
authenticationAdapter?: WebhookAuthenticationAdapter;
|
|
61
|
+
/** Recovery lease/snapshot limits shared with the returned recovery worker. */
|
|
62
|
+
recovery?: Omit<CreateWebhookDeliveryRecoveryOptions, 'backend' | 'authenticationAdapter'>;
|
|
63
|
+
/** Retry policy persisted with every terminal snapshot. */
|
|
64
|
+
retries?: WebhookRetryOptions;
|
|
65
|
+
}
|
|
66
|
+
export interface PostgresTaskSettlementCoordinator {
|
|
67
|
+
readonly durability: 'durable';
|
|
68
|
+
/** Wire this into the normal webhook recovery poller/emitter. */
|
|
69
|
+
readonly recovery: DurableWebhookDeliveryRecovery;
|
|
70
|
+
settle(ref: ScopedTaskRef, terminal: TerminalSettlement, push: TaskPushSettlementConfig): Promise<TaskPushSettlementOutcome>;
|
|
71
|
+
}
|
|
72
|
+
/** Configuration or immutable-delivery conflict detected before commit. */
|
|
73
|
+
export declare class TaskPushSettlementConfigurationError extends Error {
|
|
74
|
+
readonly name = "TaskPushSettlementConfigurationError";
|
|
75
|
+
}
|
|
76
|
+
export declare function createPostgresTaskSettlementCoordinator(options: PostgresTaskSettlementCoordinatorOptions): PostgresTaskSettlementCoordinator;
|
|
77
|
+
export declare function completeScopedPushTask<TResult>(coordinator: PostgresTaskSettlementCoordinator, ref: ScopedTaskRef, push: TaskPushSettlementConfig, result: TResult): Promise<TaskPushSettlementOutcome>;
|
|
78
|
+
export declare function failScopedPushTask(coordinator: PostgresTaskSettlementCoordinator, ref: ScopedTaskRef, push: TaskPushSettlementConfig, error: AdcpStructuredError, result?: unknown): Promise<TaskPushSettlementOutcome>;
|
|
79
|
+
export {};
|