@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
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { isAlwaysBlocked, isPrivateIp } from "../../../net/address-guards.mjs";
|
|
2
2
|
import { ssrfSafeFetch, SsrfRefusedError } from "../../../net/ssrf-fetch.mjs";
|
|
3
|
+
import {
|
|
4
|
+
buildProtectedResourceMetadataUrl,
|
|
5
|
+
normalizeOAuthResourceForComparison
|
|
6
|
+
} from "../../../auth/oauth/resource-url.mjs";
|
|
7
|
+
import {
|
|
8
|
+
buildProtectedResourceMetadataUrl as buildProtectedResourceMetadataUrl2,
|
|
9
|
+
normalizeOAuthResourceForComparison as normalizeOAuthResourceForComparison2
|
|
10
|
+
} from "../../../auth/oauth/resource-url.mjs";
|
|
3
11
|
const LIMITS = Object.freeze({
|
|
4
12
|
authorizationServers: 16,
|
|
5
13
|
uniqueUrls: 64,
|
|
@@ -24,40 +32,6 @@ const DIAGNOSTIC_ORDER = Object.freeze([
|
|
|
24
32
|
"oauth_endpoint_unreachable",
|
|
25
33
|
"oauth_jwks_unavailable"
|
|
26
34
|
]);
|
|
27
|
-
function normalizeOAuthResourceForComparison(value) {
|
|
28
|
-
const match = /^([A-Za-z][A-Za-z\d+.-]*):\/\/([^/?#]*)([\s\S]*)$/.exec(value);
|
|
29
|
-
if (!match) return value;
|
|
30
|
-
const scheme = match[1].toLowerCase();
|
|
31
|
-
const authority = match[2];
|
|
32
|
-
const remainder = match[3];
|
|
33
|
-
const at = authority.lastIndexOf("@");
|
|
34
|
-
const userinfo = at >= 0 ? authority.slice(0, at + 1) : "";
|
|
35
|
-
const hostAndPort = at >= 0 ? authority.slice(at + 1) : authority;
|
|
36
|
-
let host;
|
|
37
|
-
let port = "";
|
|
38
|
-
if (hostAndPort.startsWith("[")) {
|
|
39
|
-
const bracket = hostAndPort.indexOf("]");
|
|
40
|
-
if (bracket < 0) return value;
|
|
41
|
-
host = hostAndPort.slice(0, bracket + 1).toLowerCase();
|
|
42
|
-
const suffix = hostAndPort.slice(bracket + 1);
|
|
43
|
-
if (suffix && !/^:\d+$/.test(suffix)) return value;
|
|
44
|
-
port = suffix.slice(1);
|
|
45
|
-
} else {
|
|
46
|
-
const colon = hostAndPort.lastIndexOf(":");
|
|
47
|
-
if (colon >= 0) {
|
|
48
|
-
const suffix = hostAndPort.slice(colon + 1);
|
|
49
|
-
if (!/^\d+$/.test(suffix)) return value;
|
|
50
|
-
host = hostAndPort.slice(0, colon).toLowerCase();
|
|
51
|
-
port = suffix;
|
|
52
|
-
} else {
|
|
53
|
-
host = hostAndPort.toLowerCase();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (!host) return value;
|
|
57
|
-
const defaultPort = scheme === "https" ? "443" : scheme === "http" ? "80" : void 0;
|
|
58
|
-
const renderedPort = port && port !== defaultPort ? `:${port}` : "";
|
|
59
|
-
return `${scheme}://${userinfo}${host}${renderedPort}${remainder}`;
|
|
60
|
-
}
|
|
61
35
|
function redactOAuthUrlForOutput(value) {
|
|
62
36
|
try {
|
|
63
37
|
const u = new URL(value);
|
|
@@ -75,10 +49,6 @@ function redactOAuthUrlForOutput(value) {
|
|
|
75
49
|
function redactOAuthUrlsInText(value) {
|
|
76
50
|
return value.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => redactOAuthUrlForOutput(url));
|
|
77
51
|
}
|
|
78
|
-
function buildProtectedResourceMetadataUrl(agentUrl) {
|
|
79
|
-
const u = new URL(agentUrl);
|
|
80
|
-
return `${u.origin}/.well-known/oauth-protected-resource${u.pathname}`;
|
|
81
|
-
}
|
|
82
52
|
function buildAuthorizationServerMetadataUrl(issuer) {
|
|
83
53
|
const u = new URL(issuer);
|
|
84
54
|
const issuerPath = u.pathname === "/" ? "" : u.pathname;
|
|
@@ -103,7 +73,7 @@ async function gradeOAuthMetadataGraphWithTransport(agentUrl, options = {}) {
|
|
|
103
73
|
const findings = [];
|
|
104
74
|
let protectedResourceUrl;
|
|
105
75
|
try {
|
|
106
|
-
protectedResourceUrl =
|
|
76
|
+
protectedResourceUrl = buildProtectedResourceMetadataUrl2(agentUrl);
|
|
107
77
|
} catch {
|
|
108
78
|
protectedResourceUrl = redactOAuthUrlForOutput(agentUrl);
|
|
109
79
|
findings.push(finding("oauth_protected_resource_metadata_invalid", "Agent URL is not an absolute URL."));
|
|
@@ -148,7 +118,7 @@ async function gradeOAuthMetadataGraphWithTransport(agentUrl, options = {}) {
|
|
|
148
118
|
"resource"
|
|
149
119
|
)
|
|
150
120
|
);
|
|
151
|
-
} else if (
|
|
121
|
+
} else if (normalizeOAuthResourceForComparison2(resource) !== normalizeOAuthResourceForComparison2(agentUrl)) {
|
|
152
122
|
findings.push(
|
|
153
123
|
finding(
|
|
154
124
|
"oauth_resource_mismatch",
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.15";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
|
|
|
197
197
|
*/
|
|
198
198
|
export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
|
|
199
199
|
/** Capability semver emitted in run summaries and used for advisory expiry. */
|
|
200
|
-
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.
|
|
200
|
+
export declare const RUNNER_CAPABILITY_VERSION = "14.0.0-beta.15";
|
|
201
201
|
/** True when a failed validation contributes to the owning step's grade. */
|
|
202
202
|
export declare function validationFailsStep(result: ValidationResult): boolean;
|
|
203
203
|
/**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Compare full-semver and release-precision AdCP identifiers safely. */
|
|
2
2
|
export declare function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean;
|
|
3
|
+
/** Whether an AdCP identifier is a parseable full or release-precision semver. */
|
|
4
|
+
export declare function isValidAdcpVersion(version: string | undefined): version is string;
|
|
3
5
|
/**
|
|
4
6
|
* Resolve and validate a configured `adcpVersion`. Returns the value to store
|
|
5
7
|
* on the instance — either the caller's pin or the SDK default.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Compare full-semver and release-precision AdCP identifiers safely. */
|
|
2
2
|
export declare function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean;
|
|
3
|
+
/** Whether an AdCP identifier is a parseable full or release-precision semver. */
|
|
4
|
+
export declare function isValidAdcpVersion(version: string | undefined): version is string;
|
|
3
5
|
/**
|
|
4
6
|
* Resolve and validate a configured `adcpVersion`. Returns the value to store
|
|
5
7
|
* on the instance — either the caller's pin or the SDK default.
|
|
@@ -24,6 +24,7 @@ __export(adcp_version_config_exports, {
|
|
|
24
24
|
isMovingAdcpPrereleaseFamilyAlias: () => isMovingAdcpPrereleaseFamilyAlias,
|
|
25
25
|
isPre31AdcpVersion: () => isPre31AdcpVersion,
|
|
26
26
|
isPre32AdcpVersion: () => isPre32AdcpVersion,
|
|
27
|
+
isValidAdcpVersion: () => isValidAdcpVersion,
|
|
27
28
|
listBundledAdcpVersions: () => listBundledAdcpVersions,
|
|
28
29
|
omit31BrandFields: () => omit31BrandFields,
|
|
29
30
|
resolveAdcpVersion: () => resolveAdcpVersion,
|
|
@@ -47,6 +48,9 @@ function isAdcpVersionAtLeast(version, minimum) {
|
|
|
47
48
|
const comparableMinimum = comparableAdcpSemver(minimum);
|
|
48
49
|
return comparable !== void 0 && comparableMinimum !== void 0 && (0, import_semver.gte)(comparable, comparableMinimum);
|
|
49
50
|
}
|
|
51
|
+
function isValidAdcpVersion(version) {
|
|
52
|
+
return version !== void 0 && comparableAdcpSemver(version) !== void 0;
|
|
53
|
+
}
|
|
50
54
|
function resolveAdcpVersion(adcpVersion) {
|
|
51
55
|
if (adcpVersion === void 0) return import_version.ADCP_VERSION;
|
|
52
56
|
const currentReleasePrecision = (0, import_schema_loader.toReleasePrecisionWire)(import_version.ADCP_VERSION);
|
|
@@ -174,6 +178,7 @@ function listBundledAdcpVersions() {
|
|
|
174
178
|
isMovingAdcpPrereleaseFamilyAlias,
|
|
175
179
|
isPre31AdcpVersion,
|
|
176
180
|
isPre32AdcpVersion,
|
|
181
|
+
isValidAdcpVersion,
|
|
177
182
|
listBundledAdcpVersions,
|
|
178
183
|
omit31BrandFields,
|
|
179
184
|
resolveAdcpVersion,
|
|
@@ -14,6 +14,9 @@ function isAdcpVersionAtLeast(version, minimum) {
|
|
|
14
14
|
const comparableMinimum = comparableAdcpSemver(minimum);
|
|
15
15
|
return comparable !== void 0 && comparableMinimum !== void 0 && semverGte(comparable, comparableMinimum);
|
|
16
16
|
}
|
|
17
|
+
function isValidAdcpVersion(version) {
|
|
18
|
+
return version !== void 0 && comparableAdcpSemver(version) !== void 0;
|
|
19
|
+
}
|
|
17
20
|
function resolveAdcpVersion(adcpVersion) {
|
|
18
21
|
if (adcpVersion === void 0) return ADCP_VERSION;
|
|
19
22
|
const currentReleasePrecision = toReleasePrecisionWire(ADCP_VERSION);
|
|
@@ -140,6 +143,7 @@ export {
|
|
|
140
143
|
isMovingAdcpPrereleaseFamilyAlias,
|
|
141
144
|
isPre31AdcpVersion,
|
|
142
145
|
isPre32AdcpVersion,
|
|
146
|
+
isValidAdcpVersion,
|
|
143
147
|
listBundledAdcpVersions,
|
|
144
148
|
omit31BrandFields,
|
|
145
149
|
resolveAdcpVersion,
|
package/dist/lib/version.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AdCP SDK library version
|
|
3
3
|
*/
|
|
4
|
-
export declare const LIBRARY_VERSION = "14.0.0-beta.
|
|
4
|
+
export declare const LIBRARY_VERSION = "14.0.0-beta.15";
|
|
5
5
|
/**
|
|
6
6
|
* AdCP specification version this library is built for
|
|
7
7
|
*/
|
|
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
|
|
|
33
33
|
* Full version information
|
|
34
34
|
*/
|
|
35
35
|
export declare const VERSION_INFO: {
|
|
36
|
-
readonly library: "14.0.0-beta.
|
|
36
|
+
readonly library: "14.0.0-beta.15";
|
|
37
37
|
readonly adcp: "3.2.0-beta.8";
|
|
38
38
|
readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0-beta.1", "3.0-beta.1", "3.0-beta", "3.0.0-beta.3", "3.0-beta.3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.2.0-beta.8", "3.2-beta.8"];
|
|
39
|
-
readonly generatedAt: "2026-08-
|
|
39
|
+
readonly generatedAt: "2026-08-28T20:29:38.378Z";
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Get the AdCP specification version this library is built for
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AdCP SDK library version
|
|
3
3
|
*/
|
|
4
|
-
export declare const LIBRARY_VERSION = "14.0.0-beta.
|
|
4
|
+
export declare const LIBRARY_VERSION = "14.0.0-beta.15";
|
|
5
5
|
/**
|
|
6
6
|
* AdCP specification version this library is built for
|
|
7
7
|
*/
|
|
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
|
|
|
33
33
|
* Full version information
|
|
34
34
|
*/
|
|
35
35
|
export declare const VERSION_INFO: {
|
|
36
|
-
readonly library: "14.0.0-beta.
|
|
36
|
+
readonly library: "14.0.0-beta.15";
|
|
37
37
|
readonly adcp: "3.2.0-beta.8";
|
|
38
38
|
readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0-beta.1", "3.0-beta.1", "3.0-beta", "3.0.0-beta.3", "3.0-beta.3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.2.0-beta.8", "3.2-beta.8"];
|
|
39
|
-
readonly generatedAt: "2026-08-
|
|
39
|
+
readonly generatedAt: "2026-08-28T20:29:38.378Z";
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Get the AdCP specification version this library is built for
|
package/dist/lib/version.js
CHANGED
|
@@ -31,7 +31,7 @@ __export(version_exports, {
|
|
|
31
31
|
toReleasePrecisionVersion: () => toReleasePrecisionVersion
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(version_exports);
|
|
34
|
-
const LIBRARY_VERSION = "14.0.0-beta.
|
|
34
|
+
const LIBRARY_VERSION = "14.0.0-beta.15";
|
|
35
35
|
const ADCP_VERSION = "3.2.0-beta.8";
|
|
36
36
|
const ADCP_MAJOR_VERSION = 3;
|
|
37
37
|
const COMPATIBLE_ADCP_VERSIONS = [
|
|
@@ -94,10 +94,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
|
|
|
94
94
|
"3.2-beta.8"
|
|
95
95
|
];
|
|
96
96
|
const VERSION_INFO = {
|
|
97
|
-
library: "14.0.0-beta.
|
|
97
|
+
library: "14.0.0-beta.15",
|
|
98
98
|
adcp: "3.2.0-beta.8",
|
|
99
99
|
compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
|
|
100
|
-
generatedAt: "2026-08-
|
|
100
|
+
generatedAt: "2026-08-28T20:29:38.378Z"
|
|
101
101
|
};
|
|
102
102
|
function getAdcpVersion() {
|
|
103
103
|
return ADCP_VERSION;
|
package/dist/lib/version.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const LIBRARY_VERSION = "14.0.0-beta.
|
|
1
|
+
const LIBRARY_VERSION = "14.0.0-beta.15";
|
|
2
2
|
const ADCP_VERSION = "3.2.0-beta.8";
|
|
3
3
|
const ADCP_MAJOR_VERSION = 3;
|
|
4
4
|
const COMPATIBLE_ADCP_VERSIONS = [
|
|
@@ -61,10 +61,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
|
|
|
61
61
|
"3.2-beta.8"
|
|
62
62
|
];
|
|
63
63
|
const VERSION_INFO = {
|
|
64
|
-
library: "14.0.0-beta.
|
|
64
|
+
library: "14.0.0-beta.15",
|
|
65
65
|
adcp: "3.2.0-beta.8",
|
|
66
66
|
compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
|
|
67
|
-
generatedAt: "2026-08-
|
|
67
|
+
generatedAt: "2026-08-28T20:29:38.378Z"
|
|
68
68
|
};
|
|
69
69
|
function getAdcpVersion() {
|
|
70
70
|
return ADCP_VERSION;
|
package/docs/llms.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Ad Context Protocol (AdCP)
|
|
2
2
|
|
|
3
3
|
> Generated at: 2026-08-28
|
|
4
|
-
> Library: @adcp/sdk v14.0.0-beta.
|
|
4
|
+
> Library: @adcp/sdk v14.0.0-beta.15
|
|
5
5
|
> AdCP major version: 3
|
|
6
6
|
> Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
|
|
7
7
|
> Note: the `Library` stamp reflects the package.json version at doc-generation time. The narrative below describes the surface that lands on the next-published minor — including any 6.7 helpers documented here ahead of the release tag.
|
|
@@ -1848,8 +1848,10 @@ See docs/TYPE-SUMMARY.md for field-level detail. Key types at a glance:
|
|
|
1848
1848
|
| `GovernanceConfig` | Buyer-side governance middleware config |
|
|
1849
1849
|
| `EstablishedProposalStore` | Durable 3.0/3.1 proposal snapshots, atomic mutation fences, seven-day completion proofs, pruning, and submitted-task reconciliation |
|
|
1850
1850
|
| `WebhooksConfig.tenantScope` | Explicit trusted webhook namespace for a genuinely single-tenant server; multi-tenant servers derive scope per request |
|
|
1851
|
+
| `PostgresTaskSettlementCoordinator` | Atomically commits a push task terminal state and PostgreSQL recovery-outbox checkpoint for different-process workers |
|
|
1851
1852
|
|
|
1852
1853
|
Production webhook publishers may construct an unbound emitter and call `forTenantScope(trustedTenant)` before every delivery. Direct unbound `emit()` fails before checkpointing or network access. `createAdcpServer` derives scope from trusted request context; configure `webhooks.tenantScope` only for a genuinely single-tenant factory.
|
|
1854
|
+
Push-enabled decisioning tasks settled by another process must return `ctx.handoffToTask(producer, { settlement: 'external' })`; the framework withholds `submitted` until the producer durably queues the complete scoped handle and encrypted route. Workers use `createPostgresTaskSettlementCoordinator()` with `completeScopedPushTask()` / `failScopedPushTask()`; the task mutation and encrypted recovery outbox checkpoint commit together. Acknowledge work only for `applied` or compatible `already_terminal`; retry or dead-letter scope misses and conflicts.
|
|
1853
1855
|
|
|
1854
1856
|
## Task Statuses
|
|
1855
1857
|
|
|
@@ -90,10 +90,11 @@ OAuth flow handlers must preserve `state`, verify callback binding, and pass an
|
|
|
90
90
|
|
|
91
91
|
Cross-origin signing-key discovery now requires a schema-shaped, active
|
|
92
92
|
`authorized_operators[]` grant. Broad grants use `brands: ['*']`, omitted
|
|
93
|
-
scopes (or `['all']`), and omitted countries. For narrower grants,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
scopes (or `['all']`), and omitted countries. For narrower grants, pass
|
|
94
|
+
`TaskOptions.delegatedOperatorAuthorization` per dispatch, or configure the
|
|
95
|
+
matching trusted client-wide `requiredOperatorBrand`, `requiredOperatorScope`,
|
|
96
|
+
and/or `requiredOperatorCountry` fallback under
|
|
97
|
+
`webhookVerification.resolverOptions`. Constrained dimensions fail closed
|
|
97
98
|
without context. Cached delegated keys expire no later than `valid_until`. See
|
|
98
99
|
[the 13→14 migration detail](migration-13-to-14.md#cross-origin-signing-key-delegation).
|
|
99
100
|
|
|
@@ -103,7 +104,7 @@ without context. Cached delegated keys expire no later than `valid_until`. See
|
|
|
103
104
|
- Add `zip`, `published_post`, `card`, `pixel_tracker`, `vast_tracker`, and `daast_tracker` to exhaustive `AssetInstance` handling.
|
|
104
105
|
- Read canonical compliance scenarios from `ComplianceResult.tracks`; `tested_tracks` contains compact reference entries.
|
|
105
106
|
- `createAdcpServerFromPlatform()` never emits a task webhook for an inline terminal result. The deprecated `autoEmitCompletionWebhooks` option is ignored under AdCP 3.2.
|
|
106
|
-
- Rename raw platform hooks to explicit forms such as `buildCreativeLegacy`, `previewCreativeLegacy`, `listCreativeFormatsLegacy`, and the corresponding content-standard and brand-rights names. Canonical AdCP 3.2 previews now use `previewCreative` with `target_capability_id`, `creative_id`, or `creative_manifest`; retain `previewCreativeLegacy` only for `format_id` callers. Custom `WebhookRegistrationStore` implementations must round-trip
|
|
107
|
+
- Rename raw platform hooks to explicit forms such as `buildCreativeLegacy`, `previewCreativeLegacy`, `listCreativeFormatsLegacy`, and the corresponding content-standard and brand-rights names. Canonical AdCP 3.2 previews now use `previewCreative` with `target_capability_id`, `creative_id`, or `creative_manifest`; retain `previewCreativeLegacy` only for `format_id` callers. Custom `WebhookRegistrationStore` implementations must round-trip `previewMode`, `authorizationContextVersion`, and `delegatedOperatorAuthorization` so callback routing and delegated authority survive restarts; dispatch now fails closed if an immediate read-back loses the versioned authorization fields, and automatic key discovery rejects pre-upgrade RFC 9421 rows that lack the version marker.
|
|
107
108
|
- Put incrementally migrated raw handler groups under `legacyHandlers`.
|
|
108
109
|
- Replace removed registry hierarchy calls with `lookupBrand()`/`lookupBrands()` and inspect relationship evidence; use `{ fresh: true }` when a live origin check is required.
|
|
109
110
|
- Use `PayloadDigestOptions` for `computePayloadDigestSha256()` rather than the removed bare `RegExp` or `false` overloads.
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
SDK 14 adopts AdCP `3.2.0-beta.8` while preserving the canonical creative boundary introduced in SDK 13. Most SDK 13 applications can install the beta and continue using the established 3.x tools unchanged; adopt the compact 3.2 lifecycle only after the remote agent advertises it.
|
|
4
4
|
|
|
5
|
+
Legacy signal-discovery adapters may keep supplying `opts.signals.getSignals`
|
|
6
|
+
(or `legacyHandlers.signals.getSignals`) while declaring the truthful
|
|
7
|
+
`signal-marketplace` or `signal-owned` specialism. That compatibility handler
|
|
8
|
+
now satisfies platform validation without requiring adopters to invent an
|
|
9
|
+
`activate_signal` implementation during an incremental migration.
|
|
10
|
+
|
|
5
11
|
AdCP 3.2 prereleases are exact protocol pins: beta.6 replaces beta.5 in the
|
|
6
12
|
SDK's compatible-version list rather than extending a rolling 3.2-beta range.
|
|
7
13
|
Beta.1 restored `adcp_major_version` on `buy_products`,
|
|
@@ -57,11 +63,35 @@ const client = new SingleAgentClient(agent, {
|
|
|
57
63
|
});
|
|
58
64
|
```
|
|
59
65
|
|
|
60
|
-
These resolver options
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
These resolver options remain a trusted client-wide fallback for a client that
|
|
67
|
+
uses one tuple. Shared clients can now select and durably persist the trusted
|
|
68
|
+
tuple per dispatch:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
await client.createMediaBuy(request, undefined, {
|
|
72
|
+
delegatedOperatorAuthorization: {
|
|
73
|
+
brand: 'brand_b',
|
|
74
|
+
scope: 'media_buying',
|
|
75
|
+
country: 'US',
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The per-call object takes whole-object precedence and is local receiver policy;
|
|
81
|
+
the SDK neither infers it from request fields nor sends it on the wire. Custom
|
|
82
|
+
`WebhookRegistrationStore` implementations must round-trip the versioned
|
|
83
|
+
authorization fields so restart-time verification can revalidate the tuple
|
|
84
|
+
against live `brand.json`, with immediate read-your-writes consistency after
|
|
85
|
+
`putIfAbsent()`. The SDK reads the row back before seller dispatch and fails
|
|
86
|
+
closed if a legacy projection drops either field. Do not persist a prior allow
|
|
87
|
+
decision as authority.
|
|
88
|
+
|
|
89
|
+
Pre-upgrade RFC 9421 rows without `authorizationContextVersion` cannot be
|
|
90
|
+
safely backfilled from the receiver's current configuration. Automatic key
|
|
91
|
+
discovery rejects them after upgrade; drain them first or re-dispatch the
|
|
92
|
+
operation to create a versioned registration. A caller-supplied
|
|
93
|
+
`webhookVerification.jwks` may support legacy rows only when it independently
|
|
94
|
+
preserves their original trust boundary.
|
|
65
95
|
|
|
66
96
|
The same options are accepted by `resolveAgent()`, `getAgentJwks()`,
|
|
67
97
|
`createAgentJwksSet()`, and `ResolvedAgentJwksResolver`. A constrained list with
|
|
@@ -69,6 +99,8 @@ no corresponding trusted option fails closed. Built-in JWKS caches now expire
|
|
|
69
99
|
at the earlier of their configured TTL and the accepted delegation's
|
|
70
100
|
`valid_until` boundary. Low-level `getAgentJwks()` callers receive that boundary
|
|
71
101
|
as `operatorAuthorizationValidUntil` and must apply it to any custom cache.
|
|
102
|
+
Webhook verification also rechecks that boundary immediately before accepting a
|
|
103
|
+
delivery and committing its replay nonce.
|
|
72
104
|
|
|
73
105
|
### Modern MCP validation errors
|
|
74
106
|
|
|
@@ -152,8 +184,9 @@ loading; keep using `requires_capability` for a singular predicate.
|
|
|
152
184
|
12. Replace webhook emitter `operation_id` arguments with SDK-local `delivery_id` values and upgrade custom stores to `WebhookDeliveryStore`. One delivery ID binds one canonical payload and key; use a fresh delivery ID for each changed status observation while retaining the AdCP `operation_id` inside the payload.
|
|
153
185
|
13. Ensure custom 3.2 buyers include `push_notification_config.operation_id`, and update A2A integrations to keep the AdCP registration in skill parameters even when native A2A push configuration is also present.
|
|
154
186
|
14. Treat failed/rejected task results as canonical terminal artifacts when `include_result` is requested; do not discard them while preserving only the summary error.
|
|
155
|
-
15. Persist the complete `ScopedTaskRef` for out-of-process task settlement and acknowledge durable queue items only after `applied` or `already_terminal
|
|
156
|
-
16.
|
|
187
|
+
15. Persist the complete `ScopedTaskRef` for out-of-process task settlement and acknowledge durable queue items only after `applied` or a compatible `already_terminal` outcome with the intended status. Retry or dead-letter scoped misses and conflicting terminal outcomes. Upgrade populated PostgreSQL task registries with the phased [`getDecisioningTaskRegistryScopeV1Upgrade()` runbook](./migration-task-registry-scoping.md#populated-postgresql-upgrade), not application-boot bootstrap DDL.
|
|
188
|
+
16. For out-of-process settlement, return `ctx.handoffToTask(producer, { settlement: 'external' })`; the producer must durably queue the complete handle before returning, and the framework withholds `submitted` until that commit succeeds. For a push-enabled task, configure `createPostgresTaskSettlementCoordinator()` on the same PostgreSQL pool as the task registry and use `completeScopedPushTask()` / `failScopedPushTask()`. Run the webhook recovery outbox migration and recovery worker; the polling-only scoped helpers still reject push tasks. See [task registry scope migration](./migration-task-registry-scoping.md#out-of-process-settlement).
|
|
189
|
+
17. Upgrade to Node `^20.19.0 || >=22.12.0`, whose two boundaries enable the `require(esm)` support needed by the SDK's CommonJS dependency graph. Node 21 and Node 22.0–22.11 are not supported. Keep Undici 6 for the fully supported configuration, or use the tested best-effort Undici 7 override on Node 20.19+. See the [Node/Undici compatibility policy](./guides/NODE-UNDICI-COMPATIBILITY.md).
|
|
157
190
|
|
|
158
191
|
### Webhook delivery identity and retry horizons
|
|
159
192
|
|
|
@@ -227,6 +260,14 @@ plus a stable non-secret equality fingerprint. The adapter must authenticate
|
|
|
227
260
|
the supplied tenant/destination/snapshot context. Settled records redact payload
|
|
228
261
|
and protected secret references. The application still owns KMS
|
|
229
262
|
keys, secret management, tenant authorization/RBAC, and management APIs or UI.
|
|
263
|
+
For crash-safe task settlement, `createPostgresTaskSettlementCoordinator()`
|
|
264
|
+
explicitly removes the top-level validation `token` from the persisted payload
|
|
265
|
+
and protects it with the same adapter under the distinct `payload_token`
|
|
266
|
+
purpose before writing the outbox. Generic recovery checkpoints preserve
|
|
267
|
+
payload fields named `token`; use `recovery.prepare(...,
|
|
268
|
+
{ protectPayloadToken: true })` only for a protocol field known to be secret.
|
|
269
|
+
The legacy transport-authentication adapter context keeps `purpose` undefined
|
|
270
|
+
for upgrade-compatible KMS AAD.
|
|
230
271
|
|
|
231
272
|
`deliveryRetryHorizonSeconds` defaults to 86,400 seconds and accepts 86,400
|
|
232
273
|
through 604,800. `createAdcpServer()` advertises the configured value under
|
|
@@ -48,10 +48,9 @@ import {
|
|
|
48
48
|
|
|
49
49
|
return ctx.handoffToTask(async taskCtx => {
|
|
50
50
|
// The queue transaction must durably store the complete taskRef before the
|
|
51
|
-
//
|
|
51
|
+
// submitted response is sent. Persisting only taskCtx.id is unsafe.
|
|
52
52
|
await approvals.enqueue({ taskRef: taskCtx.taskRef, request: approvalInput });
|
|
53
|
-
|
|
54
|
-
});
|
|
53
|
+
}, { settlement: 'external' });
|
|
55
54
|
|
|
56
55
|
// A different process after restart:
|
|
57
56
|
const item = await approvals.claim();
|
|
@@ -78,14 +77,168 @@ if (outcome.outcome === 'not_found_in_scope') {
|
|
|
78
77
|
}
|
|
79
78
|
```
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
push
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
The direct `completeScopedTask()` / `failScopedTask()` path is polling-only and
|
|
81
|
+
continues to reject push-enabled tasks. A registry write by itself cannot
|
|
82
|
+
durably promise the terminal webhook.
|
|
83
|
+
|
|
84
|
+
For PostgreSQL deployments, use the transactional push coordinator. It writes
|
|
85
|
+
the terminal task row and the webhook recovery outbox entry in one transaction,
|
|
86
|
+
then lets the ordinary webhook recovery worker publish it. Both tables must use
|
|
87
|
+
the same `pg.Pool` and database/schema:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import {
|
|
91
|
+
completeScopedPushTask,
|
|
92
|
+
createPostgresTaskRegistry,
|
|
93
|
+
createPostgresTaskSettlementCoordinator,
|
|
94
|
+
createWebhookEmitter,
|
|
95
|
+
getWebhookDeliveryMigration,
|
|
96
|
+
getWebhookDeliveryRecoveryMigration,
|
|
97
|
+
pgWebhookDeliveryStore,
|
|
98
|
+
pollWebhookDeliveryRecovery,
|
|
99
|
+
TaskPushSettlementConfigurationError,
|
|
100
|
+
} from '@adcp/sdk/server';
|
|
101
|
+
|
|
102
|
+
// Integration sketch: pool, approvals, taskCtx, request, approvalInput,
|
|
103
|
+
// seal/openPushRoute, the KMS adapter, and signerKey are application-owned.
|
|
104
|
+
// The queue must persist encrypted push state before the request process exits.
|
|
105
|
+
|
|
106
|
+
await pool.query(getWebhookDeliveryRecoveryMigration({
|
|
107
|
+
tableName: 'my_agent_task_webhook_outbox',
|
|
108
|
+
}));
|
|
109
|
+
await pool.query(getWebhookDeliveryMigration({
|
|
110
|
+
tableName: 'my_agent_webhook_bindings',
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
const registry = createPostgresTaskRegistry({
|
|
114
|
+
pool,
|
|
115
|
+
namespace: 'tenant:my-agent',
|
|
116
|
+
storageId: 'prod-eu1:primary-db',
|
|
117
|
+
});
|
|
118
|
+
const settlements = createPostgresTaskSettlementCoordinator({
|
|
119
|
+
registry,
|
|
120
|
+
publisherScope: 'my-agent',
|
|
121
|
+
outbox: { tableName: 'my_agent_task_webhook_outbox' },
|
|
122
|
+
authenticationAdapter: kmsWebhookAuthenticationAdapter,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// In the specialism handler, the submitted response waits until the queue
|
|
126
|
+
// transaction durably stores the complete taskRef plus encrypted push route.
|
|
127
|
+
// The callback's return leaves the task submitted; only the worker below may
|
|
128
|
+
// make it terminal. A callback rejection fails the initial invocation.
|
|
129
|
+
return ctx.handoffToTask(async taskCtx => {
|
|
130
|
+
await approvals.enqueue({
|
|
131
|
+
taskRef: taskCtx.taskRef,
|
|
132
|
+
push: await sealPushRoute({
|
|
133
|
+
url: request.push_notification_config.url,
|
|
134
|
+
operationId: request.push_notification_config.operation_id,
|
|
135
|
+
// Always persist the negotiated version. A valid pre-3.2 version is
|
|
136
|
+
// required when operationId is absent and the stable fallback is used.
|
|
137
|
+
servedAdcpVersion,
|
|
138
|
+
token: request.push_notification_config.token,
|
|
139
|
+
authentication: request.push_notification_config.authentication,
|
|
140
|
+
}),
|
|
141
|
+
request: approvalInput,
|
|
142
|
+
});
|
|
143
|
+
}, { settlement: 'external' });
|
|
144
|
+
|
|
145
|
+
// A different process, including after the request process restarted:
|
|
146
|
+
const item = await approvals.claim();
|
|
147
|
+
const openedPush = await openPushRoute(item.push);
|
|
148
|
+
const legacyScheme = openedPush.authentication?.schemes[0];
|
|
149
|
+
let outcome;
|
|
150
|
+
try {
|
|
151
|
+
outcome = await completeScopedPushTask(
|
|
152
|
+
settlements,
|
|
153
|
+
item.taskRef,
|
|
154
|
+
{
|
|
155
|
+
url: openedPush.url,
|
|
156
|
+
operationId: openedPush.operationId,
|
|
157
|
+
servedAdcpVersion: openedPush.servedAdcpVersion,
|
|
158
|
+
token: openedPush.token,
|
|
159
|
+
authentication:
|
|
160
|
+
legacyScheme === 'Bearer'
|
|
161
|
+
? { type: 'bearer', token: openedPush.authentication.credentials }
|
|
162
|
+
: legacyScheme === 'HMAC-SHA256'
|
|
163
|
+
? { type: 'hmac_sha256', secret: openedPush.authentication.credentials }
|
|
164
|
+
: null,
|
|
165
|
+
},
|
|
166
|
+
item.result,
|
|
167
|
+
);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (error instanceof TaskPushSettlementConfigurationError || error instanceof TypeError) {
|
|
170
|
+
await approvals.deadLetterAndAlert(item, error); // immutable bad route/config
|
|
171
|
+
} else {
|
|
172
|
+
await approvals.retry(item, error); // transaction/infrastructure failure
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (
|
|
178
|
+
outcome.outcome === 'applied' ||
|
|
179
|
+
(outcome.outcome === 'already_terminal' && outcome.compatibility === 'compatible')
|
|
180
|
+
) {
|
|
181
|
+
await approvals.ack(item);
|
|
182
|
+
} else {
|
|
183
|
+
// A scope miss or conflicting terminal result must not be acknowledged as
|
|
184
|
+
// success. Apply the queue's bounded retry/dead-letter policy and alert.
|
|
185
|
+
await approvals.retryOrDeadLetter(item, outcome);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Publish/recover outside the database transaction. The outbox lease is
|
|
189
|
+
// fenced; a crash before publish or before acknowledgement is retryable.
|
|
190
|
+
await pollWebhookDeliveryRecovery({
|
|
191
|
+
recovery: settlements.recovery,
|
|
192
|
+
deliver: async lease => {
|
|
193
|
+
const emitter = createWebhookEmitter({
|
|
194
|
+
signerKey,
|
|
195
|
+
publisherScope: lease.key.publisherScope,
|
|
196
|
+
tenantScope: lease.key.tenantScope,
|
|
197
|
+
deliveryStore: pgWebhookDeliveryStore(pool, {
|
|
198
|
+
tableName: 'my_agent_webhook_bindings',
|
|
199
|
+
}),
|
|
200
|
+
deliveryRecovery: settlements.recovery,
|
|
201
|
+
});
|
|
202
|
+
const result = await emitter.emitRecovered(lease);
|
|
203
|
+
return result.delivered
|
|
204
|
+
? { disposition: 'delivered' }
|
|
205
|
+
: result.terminal
|
|
206
|
+
? { disposition: 'terminal' }
|
|
207
|
+
: { disposition: 'retry', retryAfterMs: 1_000 };
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`TaskPushSettlementOutcome` reports the two independent state machines. Task
|
|
213
|
+
mutation is `applied`, compatible/conflicting `already_terminal`, or the
|
|
214
|
+
non-enumerating `not_found_in_scope`. Delivery is `durably_bound`,
|
|
215
|
+
`recoverable`, `delivered`, or `terminal`; scope misses and conflicting
|
|
216
|
+
settlements report `not_applicable` and never create an outbox entry. Retries
|
|
217
|
+
reuse one deterministic delivery identity and the first committed payload.
|
|
218
|
+
|
|
219
|
+
The settlement coordinator explicitly removes the top-level task-webhook
|
|
220
|
+
`token` from the JSON payload before persistence and protects it through
|
|
221
|
+
`authenticationAdapter`; generic recovery snapshots do not reinterpret a
|
|
222
|
+
field merely because it is named `token`. The adapter context has
|
|
223
|
+
`purpose: 'payload_token'` for that validation token. The context for legacy
|
|
224
|
+
transport authentication intentionally leaves `purpose` undefined so pending
|
|
225
|
+
snapshots encrypted by older SDK versions keep the same KMS AAD.
|
|
226
|
+
Include a key version in `protectedValue`; retain old decrypt-only key versions
|
|
227
|
+
until every pending delivery using them has settled and the configured retry
|
|
228
|
+
horizon has elapsed. Rotate by writing with the new version while continuing
|
|
229
|
+
to resolve old versions. Never store cleartext push tokens in the approval
|
|
230
|
+
queue, task result, logs, metrics, or dead-letter metadata.
|
|
231
|
+
|
|
232
|
+
`updateScopedTaskProgress()` remains available for push-enabled tasks because
|
|
233
|
+
progress does not create a terminal delivery obligation. Use
|
|
234
|
+
`{ settlement: 'external' }` for every handoff owned by these helpers. Its
|
|
235
|
+
registry must declare `durability: 'durable'` and issue a stable `registryId`;
|
|
236
|
+
the built-in in-memory registry is process-local and is rejected before the
|
|
237
|
+
producer runs or the buyer receives `submitted`. Its
|
|
238
|
+
producer callback may enqueue work but cannot return a terminal artifact; even
|
|
239
|
+
if that callback throws, the framework rejects the initial invocation, leaves
|
|
240
|
+
the task internally submitted, and writes no webhook. The buyer never receives
|
|
241
|
+
an acknowledgment before recoverable work exists.
|
|
89
242
|
|
|
90
243
|
The framework owns normal in-process handoff settlement. The direct registry
|
|
91
244
|
surface is specifically for trusted webhook/queue workers and explicit
|
package/package.json
CHANGED
|
@@ -563,7 +563,7 @@ const server = createAdcpServerFromPlatform(platform, {
|
|
|
563
563
|
});
|
|
564
564
|
```
|
|
565
565
|
|
|
566
|
-
Cross-instance reads work — process A allocates the task, process B reads the lifecycle for `tasks_get`. Terminal-state idempotency is enforced atomically so concurrent settlements cannot overwrite each other. Background-completion tracking (`_registerBackground`) is process-local — promises do not serialize.
|
|
566
|
+
Cross-instance reads work — process A allocates the task, process B reads the lifecycle for `tasks_get`. Terminal-state idempotency is enforced atomically so concurrent settlements cannot overwrite each other. Background-completion tracking (`_registerBackground`) is process-local — promises do not serialize. Return `ctx.handoffToTask(producer, { settlement: 'external' })` and persist the complete `taskCtx.taskRef` before the producer returns; the framework withholds `submitted` until that durable write succeeds. Then use `completeScopedTask()` / `failScopedTask()` for polling-only tasks and acknowledge only `applied` or an `already_terminal` result with the intended status. A scoped miss must retry or dead-letter. For tasks with buyer push notifications, use `createPostgresTaskSettlementCoordinator()` with `completeScopedPushTask()` / `failScopedPushTask()` so the task transition and recovery outbox checkpoint commit atomically; registry-only helpers still reject these tasks.
|
|
567
567
|
|
|
568
568
|
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.
|
|
569
569
|
|