@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.
Files changed (127) hide show
  1. package/dist/lib/auth/oauth/authorization-required.d.mts +25 -11
  2. package/dist/lib/auth/oauth/authorization-required.d.ts +25 -11
  3. package/dist/lib/auth/oauth/authorization-required.js +18 -4
  4. package/dist/lib/auth/oauth/authorization-required.mjs +17 -4
  5. package/dist/lib/auth/oauth/index.d.mts +1 -1
  6. package/dist/lib/auth/oauth/index.d.ts +1 -1
  7. package/dist/lib/auth/oauth/index.js +2 -0
  8. package/dist/lib/auth/oauth/index.mjs +2 -0
  9. package/dist/lib/auth/oauth/resource-url.d.mts +8 -0
  10. package/dist/lib/auth/oauth/resource-url.d.ts +8 -0
  11. package/dist/lib/auth/oauth/resource-url.js +42 -0
  12. package/dist/lib/auth/oauth/resource-url.mjs +40 -0
  13. package/dist/lib/core/ConversationTypes.d.mts +10 -0
  14. package/dist/lib/core/ConversationTypes.d.ts +10 -0
  15. package/dist/lib/core/SingleAgentClient.d.mts +5 -2
  16. package/dist/lib/core/SingleAgentClient.d.ts +5 -2
  17. package/dist/lib/core/SingleAgentClient.js +133 -28
  18. package/dist/lib/core/SingleAgentClient.mjs +138 -29
  19. package/dist/lib/core/TaskExecutor.d.mts +1 -0
  20. package/dist/lib/core/TaskExecutor.d.ts +1 -0
  21. package/dist/lib/core/TaskExecutor.js +7 -1
  22. package/dist/lib/core/TaskExecutor.mjs +7 -1
  23. package/dist/lib/core/webhook-registration.d.mts +8 -1
  24. package/dist/lib/core/webhook-registration.d.ts +8 -1
  25. package/dist/lib/core/webhook-registration.js +65 -5
  26. package/dist/lib/core/webhook-registration.mjs +61 -4
  27. package/dist/lib/errors/index.d.mts +9 -0
  28. package/dist/lib/errors/index.d.ts +9 -0
  29. package/dist/lib/errors/index.js +33 -0
  30. package/dist/lib/errors/index.mjs +32 -0
  31. package/dist/lib/index.d.mts +3 -2
  32. package/dist/lib/index.d.ts +3 -2
  33. package/dist/lib/index.js +4 -0
  34. package/dist/lib/index.mjs +4 -0
  35. package/dist/lib/media-buy/compatibility.js +14 -2
  36. package/dist/lib/media-buy/compatibility.mjs +14 -2
  37. package/dist/lib/protocols/index.js +23 -7
  38. package/dist/lib/protocols/index.mjs +24 -8
  39. package/dist/lib/protocols/mcp.js +8 -6
  40. package/dist/lib/protocols/mcp.mjs +9 -7
  41. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  42. package/dist/lib/server/decisioning/async-outcome.d.mts +11 -0
  43. package/dist/lib/server/decisioning/async-outcome.d.ts +11 -0
  44. package/dist/lib/server/decisioning/context.d.mts +11 -1
  45. package/dist/lib/server/decisioning/context.d.ts +11 -1
  46. package/dist/lib/server/decisioning/index.d.mts +3 -2
  47. package/dist/lib/server/decisioning/index.d.ts +3 -2
  48. package/dist/lib/server/decisioning/index.js +9 -0
  49. package/dist/lib/server/decisioning/index.mjs +10 -0
  50. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -2
  51. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -2
  52. package/dist/lib/server/decisioning/runtime/from-platform.js +40 -8
  53. package/dist/lib/server/decisioning/runtime/from-platform.mjs +40 -8
  54. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +8 -1
  55. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +8 -1
  56. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +10 -1
  57. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +9 -1
  58. package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.mts +79 -0
  59. package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.ts +79 -0
  60. package/dist/lib/server/decisioning/runtime/postgres-task-settlement.js +391 -0
  61. package/dist/lib/server/decisioning/runtime/postgres-task-settlement.mjs +369 -0
  62. package/dist/lib/server/decisioning/runtime/task-registry.d.mts +2 -0
  63. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +2 -0
  64. package/dist/lib/server/decisioning/runtime/task-registry.js +2 -1
  65. package/dist/lib/server/decisioning/runtime/task-registry.mjs +2 -1
  66. package/dist/lib/server/decisioning/runtime/to-context.js +15 -11
  67. package/dist/lib/server/decisioning/runtime/to-context.mjs +15 -11
  68. package/dist/lib/server/index.d.mts +2 -2
  69. package/dist/lib/server/index.d.ts +2 -2
  70. package/dist/lib/server/index.js +4 -0
  71. package/dist/lib/server/index.mjs +4 -0
  72. package/dist/lib/server/webhook-delivery/index.d.mts +2 -2
  73. package/dist/lib/server/webhook-delivery/index.d.ts +2 -2
  74. package/dist/lib/server/webhook-delivery/index.js +4 -0
  75. package/dist/lib/server/webhook-delivery/index.mjs +5 -1
  76. package/dist/lib/server/webhook-delivery/pg.d.mts +3 -1
  77. package/dist/lib/server/webhook-delivery/pg.d.ts +3 -1
  78. package/dist/lib/server/webhook-delivery/pg.js +25 -2
  79. package/dist/lib/server/webhook-delivery/pg.mjs +25 -2
  80. package/dist/lib/server/webhook-delivery/recovery.d.mts +44 -0
  81. package/dist/lib/server/webhook-delivery/recovery.d.ts +44 -0
  82. package/dist/lib/server/webhook-delivery/recovery.js +146 -43
  83. package/dist/lib/server/webhook-delivery/recovery.mjs +144 -43
  84. package/dist/lib/signing/agent-resolver/index.d.mts +1 -1
  85. package/dist/lib/signing/agent-resolver/index.d.ts +1 -1
  86. package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +9 -0
  87. package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +9 -0
  88. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +4 -1
  89. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +4 -1
  90. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +17 -4
  91. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +17 -4
  92. package/dist/lib/signing/jwks.d.mts +7 -0
  93. package/dist/lib/signing/jwks.d.ts +7 -0
  94. package/dist/lib/signing/server.d.mts +2 -2
  95. package/dist/lib/signing/server.d.ts +2 -2
  96. package/dist/lib/signing/webhook-verifier.d.mts +6 -0
  97. package/dist/lib/signing/webhook-verifier.d.ts +6 -0
  98. package/dist/lib/signing/webhook-verifier.js +38 -4
  99. package/dist/lib/signing/webhook-verifier.mjs +38 -4
  100. package/dist/lib/testing/client.d.mts +1 -0
  101. package/dist/lib/testing/client.d.ts +1 -0
  102. package/dist/lib/testing/client.js +6 -2
  103. package/dist/lib/testing/client.mjs +6 -2
  104. package/dist/lib/testing/compliance/comply.d.mts +2 -2
  105. package/dist/lib/testing/compliance/comply.d.ts +2 -2
  106. package/dist/lib/testing/compliance/comply.js +41 -31
  107. package/dist/lib/testing/compliance/comply.mjs +44 -21
  108. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +1 -7
  109. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +1 -7
  110. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +6 -42
  111. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +10 -40
  112. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  113. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  114. package/dist/lib/utils/adcp-version-config.d.mts +2 -0
  115. package/dist/lib/utils/adcp-version-config.d.ts +2 -0
  116. package/dist/lib/utils/adcp-version-config.js +5 -0
  117. package/dist/lib/utils/adcp-version-config.mjs +4 -0
  118. package/dist/lib/version.d.mts +3 -3
  119. package/dist/lib/version.d.ts +3 -3
  120. package/dist/lib/version.js +3 -3
  121. package/dist/lib/version.mjs +3 -3
  122. package/docs/llms.txt +3 -1
  123. package/docs/migration-12-to-14.md +6 -5
  124. package/docs/migration-13-to-14.md +48 -7
  125. package/docs/migration-task-registry-scoping.md +164 -11
  126. package/package.json +1 -1
  127. package/skills/build-decisioning-platform/advanced/REFERENCE.md +1 -1
@@ -0,0 +1,391 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var postgres_task_settlement_exports = {};
20
+ __export(postgres_task_settlement_exports, {
21
+ TaskPushSettlementConfigurationError: () => TaskPushSettlementConfigurationError,
22
+ completeScopedPushTask: () => completeScopedPushTask,
23
+ createPostgresTaskSettlementCoordinator: () => createPostgresTaskSettlementCoordinator,
24
+ failScopedPushTask: () => failScopedPushTask
25
+ });
26
+ module.exports = __toCommonJS(postgres_task_settlement_exports);
27
+ var import_node_crypto = require("node:crypto");
28
+ var import_jcs = require('../../../utils/jcs.js');
29
+ var import_adcp_version_config = require('../../../utils/adcp-version-config.js');
30
+ var import_errors = require('../../errors.js');
31
+ var import_common = require('../../webhook-delivery/common.js');
32
+ var import_recovery = require('../../webhook-delivery/recovery.js');
33
+ var import_pg = require('../../webhook-delivery/pg.js');
34
+ var import_protocol_for_tool = require('./protocol-for-tool.js');
35
+ var import_postgres_task_registry = require('./postgres-task-registry.js');
36
+ var import_task_registry = require('./task-registry.js');
37
+ class TaskPushSettlementConfigurationError extends Error {
38
+ name = "TaskPushSettlementConfigurationError";
39
+ }
40
+ const TERMINAL = /* @__PURE__ */ new Set(["completed", "failed", "rejected", "canceled"]);
41
+ const MAX_RESULT_BYTES = 4 * 1024 * 1024;
42
+ const TOKEN_CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/;
43
+ function createPostgresTaskSettlementCoordinator(options) {
44
+ const binding = (0, import_postgres_task_registry._postgresTaskRegistryBinding)(options.registry);
45
+ if (!binding) {
46
+ throw new TypeError("createPostgresTaskSettlementCoordinator requires a registry from createPostgresTaskRegistry");
47
+ }
48
+ const pool = binding.pool;
49
+ if (typeof pool.connect !== "function") {
50
+ throw new TypeError(
51
+ "Crash-safe task settlement requires a pg Pool with connect(); a query-only adapter cannot own a transaction"
52
+ );
53
+ }
54
+ if (typeof options.registry.registryId !== "string" || options.registry.registryId.length === 0) {
55
+ throw new TypeError("Crash-safe task settlement requires task registry storageId/registryId binding");
56
+ }
57
+ if (typeof options.publisherScope !== "string" || options.publisherScope.length === 0) {
58
+ throw new TypeError("publisherScope must be a non-empty string");
59
+ }
60
+ const outboxOptions = options.outbox ?? {};
61
+ const outboxTable = (0, import_common.quoteWebhookTable)(outboxOptions.tableName ?? "adcp_webhook_outbox");
62
+ const claimScope = {
63
+ publisherScope: options.publisherScope,
64
+ tenantScope: stableRegistryScope(options.registry.registryId, binding.namespace)
65
+ };
66
+ const backend = (0, import_pg.pgWebhookDeliveryRecoveryBackend)(binding.pool, { ...outboxOptions, claimScope });
67
+ const recovery = (0, import_recovery.createWebhookDeliveryRecovery)({
68
+ ...options.recovery,
69
+ backend,
70
+ ...options.authenticationAdapter && { authenticationAdapter: options.authenticationAdapter }
71
+ });
72
+ const retries = resolveRetries(options.retries);
73
+ return {
74
+ durability: "durable",
75
+ recovery,
76
+ async settle(ref, terminal, push) {
77
+ if (ref.registryId !== options.registry.registryId) {
78
+ return { outcome: "not_found_in_scope", delivery: "not_applicable" };
79
+ }
80
+ let client;
81
+ try {
82
+ client = await pool.connect();
83
+ await client.query("BEGIN");
84
+ const locked = await client.query(
85
+ `SELECT tool, status, result, error, has_webhook
86
+ FROM ${binding.tableName}
87
+ WHERE task_id = $1 AND registry_namespace = $2 AND account_id = $3 AND owner_scope = $4
88
+ FOR UPDATE`,
89
+ [ref.taskId, binding.namespace, ref.accountId, ref.ownerScope]
90
+ );
91
+ if (locked.rows.length === 0) {
92
+ await client.query("ROLLBACK");
93
+ return { outcome: "not_found_in_scope", delivery: "not_applicable" };
94
+ }
95
+ const row = locked.rows[0];
96
+ validatePush(push);
97
+ if (row.has_webhook !== true) {
98
+ throw new TaskPushSettlementConfigurationError(
99
+ "Crash-safe push settlement requires a task created with hasWebhook: true"
100
+ );
101
+ }
102
+ let result;
103
+ let error;
104
+ try {
105
+ result = terminal.status === "completed" ? (0, import_task_registry.sanitizeTaskResultForWire)(structuredClone(terminal.result), ref) : terminal.result === void 0 ? { errors: [(0, import_errors.sanitizeStructuredAdcpError)(terminal.error)] } : (0, import_task_registry.sanitizeTaskResultForWire)(structuredClone(terminal.result), ref);
106
+ error = terminal.status === "failed" ? (0, import_errors.sanitizeStructuredAdcpError)(terminal.error) : void 0;
107
+ (0, import_jcs.canonicalJsonSha256)({ result, error });
108
+ assertPayloadSize(result, error);
109
+ } catch (cause) {
110
+ if (cause instanceof TaskPushSettlementConfigurationError) throw cause;
111
+ throw new TaskPushSettlementConfigurationError("Task terminal result/error must be serializable JSON", {
112
+ cause
113
+ });
114
+ }
115
+ const compatible = terminalMatches(row, terminal.status, result, error);
116
+ if (TERMINAL.has(row.status) && !compatible) {
117
+ await client.query("COMMIT");
118
+ return {
119
+ outcome: "already_terminal",
120
+ status: row.status,
121
+ compatibility: "conflicting",
122
+ delivery: "not_applicable"
123
+ };
124
+ }
125
+ const deliveryKey = {
126
+ ...claimScope,
127
+ deliveryId: stableScope("task-webhook", ref)
128
+ };
129
+ const existing = await readOutbox(client, outboxTable, deliveryKey);
130
+ if (TERMINAL.has(row.status) && !existing) {
131
+ throw new TaskPushSettlementConfigurationError(
132
+ "Terminal task has no atomic webhook delivery checkpoint; refusing to create a duplicate notification"
133
+ );
134
+ }
135
+ let inserted = false;
136
+ let delivery = existing ? deliveryState(existing) : void 0;
137
+ if (!import_protocol_for_tool.SPEC_WEBHOOK_TASK_TYPES.has(row.tool)) {
138
+ throw new TaskPushSettlementConfigurationError(
139
+ `Task type ${row.tool} cannot be emitted by the closed AdCP task-webhook schema`
140
+ );
141
+ }
142
+ const existingTimestamp = existing?.state === "pending" ? existing.snapshot.payload.timestamp : void 0;
143
+ const payload = {
144
+ idempotency_key: `pending.${deliveryKey.deliveryId.slice(-48)}`,
145
+ operation_id: resolveOperationId(push, row.tool, ref.taskId),
146
+ task_id: ref.taskId,
147
+ task_type: row.tool,
148
+ status: terminal.status,
149
+ timestamp: typeof existingTimestamp === "string" ? existingTimestamp : (/* @__PURE__ */ new Date()).toISOString(),
150
+ protocol: (0, import_protocol_for_tool.protocolForTool)(row.tool),
151
+ result,
152
+ ...push.token !== void 0 && { token: push.token },
153
+ ...terminal.status === "failed" && { message: error.message }
154
+ };
155
+ let prepared;
156
+ try {
157
+ prepared = await recovery.prepare(
158
+ deliveryKey,
159
+ {
160
+ url: push.url,
161
+ payload,
162
+ authentication: push.authentication ?? null,
163
+ retries
164
+ },
165
+ { protectPayloadToken: push.token !== void 0 }
166
+ );
167
+ } catch (cause) {
168
+ if (cause instanceof import_recovery.WebhookAuthenticationProtectionError) throw cause;
169
+ throw new TaskPushSettlementConfigurationError("Terminal webhook delivery configuration is invalid", {
170
+ cause
171
+ });
172
+ }
173
+ const intentFingerprint = taskPushIntentFingerprint(prepared.snapshot);
174
+ if (existing?.state === "settled") {
175
+ if (!TERMINAL.has(row.status)) {
176
+ throw new Error("Settled webhook outbox row exists for a non-terminal task");
177
+ }
178
+ if (existing.intent_fingerprint && existing.intent_fingerprint !== intentFingerprint) {
179
+ throw new TaskPushSettlementConfigurationError(
180
+ "Terminal webhook delivery identity is already bound to a conflicting route or payload"
181
+ );
182
+ }
183
+ await client.query("COMMIT");
184
+ return {
185
+ outcome: "already_terminal",
186
+ status: row.status,
187
+ compatibility: "compatible",
188
+ delivery: deliveryState(existing)
189
+ };
190
+ }
191
+ if (existing && existing.snapshot_fingerprint !== prepared.snapshotFingerprint) {
192
+ throw new TaskPushSettlementConfigurationError(
193
+ "Terminal webhook delivery identity is already bound to a conflicting route or payload"
194
+ );
195
+ }
196
+ if (!existing) {
197
+ const write = await client.query(
198
+ `INSERT INTO ${outboxTable} (
199
+ publisher_scope, tenant_scope, delivery_id, snapshot, snapshot_fingerprint,
200
+ storage_fingerprint, intent_fingerprint, state, attempt_count, next_attempt_at
201
+ ) VALUES ($1, $2, $3, $4::jsonb, $5, $6, $7, 'pending', 0, clock_timestamp())
202
+ ON CONFLICT (publisher_scope, tenant_scope, delivery_id) DO NOTHING`,
203
+ [
204
+ deliveryKey.publisherScope,
205
+ deliveryKey.tenantScope,
206
+ deliveryKey.deliveryId,
207
+ JSON.stringify(prepared.snapshot),
208
+ prepared.snapshotFingerprint,
209
+ prepared.storageFingerprint,
210
+ intentFingerprint
211
+ ]
212
+ );
213
+ if ((write.rowCount ?? 0) !== 1) {
214
+ const raced = await readOutbox(client, outboxTable, deliveryKey);
215
+ if (!raced || raced.snapshot_fingerprint !== prepared.snapshotFingerprint) {
216
+ throw new TaskPushSettlementConfigurationError(
217
+ "Terminal webhook delivery identity is already bound to a conflicting route or payload"
218
+ );
219
+ }
220
+ delivery = deliveryState(raced);
221
+ } else {
222
+ inserted = true;
223
+ delivery = "durably_bound";
224
+ }
225
+ }
226
+ if (!TERMINAL.has(row.status)) {
227
+ const update = terminal.status === "completed" ? await client.query(
228
+ `UPDATE ${binding.tableName}
229
+ SET status = 'completed', result = $5::jsonb, error = NULL,
230
+ status_message = NULL, updated_at = clock_timestamp()
231
+ WHERE task_id = $1 AND registry_namespace = $2 AND account_id = $3 AND owner_scope = $4`,
232
+ [ref.taskId, binding.namespace, ref.accountId, ref.ownerScope, JSON.stringify(result)]
233
+ ) : await client.query(
234
+ `UPDATE ${binding.tableName}
235
+ SET status = 'failed', result = $5::jsonb, error = $6::jsonb,
236
+ status_message = $7, updated_at = clock_timestamp()
237
+ WHERE task_id = $1 AND registry_namespace = $2 AND account_id = $3 AND owner_scope = $4`,
238
+ [
239
+ ref.taskId,
240
+ binding.namespace,
241
+ ref.accountId,
242
+ ref.ownerScope,
243
+ JSON.stringify(result),
244
+ JSON.stringify(error),
245
+ error.message
246
+ ]
247
+ );
248
+ if ((update.rowCount ?? 0) !== 1) throw new Error("Task disappeared while holding its settlement lock");
249
+ await client.query("COMMIT");
250
+ return { outcome: "applied", delivery: "durably_bound" };
251
+ }
252
+ await client.query("COMMIT");
253
+ return {
254
+ outcome: "already_terminal",
255
+ status: row.status,
256
+ compatibility: "compatible",
257
+ delivery: inserted ? "durably_bound" : delivery ?? "recoverable"
258
+ };
259
+ } catch (cause) {
260
+ if (client) await rollbackQuietly(client);
261
+ if (cause instanceof TaskPushSettlementConfigurationError) throw cause;
262
+ throw new Error("PostgresTaskSettlementCoordinator.settle: transaction failed", { cause });
263
+ } finally {
264
+ client?.release();
265
+ }
266
+ }
267
+ };
268
+ }
269
+ async function completeScopedPushTask(coordinator, ref, push, result) {
270
+ return coordinator.settle(ref, { status: "completed", result }, push);
271
+ }
272
+ async function failScopedPushTask(coordinator, ref, push, error, result) {
273
+ return coordinator.settle(ref, { status: "failed", error, ...result !== void 0 && { result } }, push);
274
+ }
275
+ function terminalMatches(row, status, result, error) {
276
+ if (row.status !== status) return false;
277
+ return (0, import_jcs.canonicalJsonSha256)(row.result) === (0, import_jcs.canonicalJsonSha256)(result) && (status === "completed" || (0, import_jcs.canonicalJsonSha256)(row.error) === (0, import_jcs.canonicalJsonSha256)(error));
278
+ }
279
+ function stableScope(prefix, ref) {
280
+ const digest = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify([ref.registryId, ref.accountId, ref.ownerScope, ref.taskId])).digest("hex");
281
+ return `${prefix}:${digest}`;
282
+ }
283
+ function stableRegistryScope(registryId, namespace) {
284
+ const digest = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify([registryId, namespace])).digest("hex");
285
+ return `task-registry:${digest}`;
286
+ }
287
+ function taskPushIntentFingerprint(snapshot) {
288
+ const { timestamp: _generatedTimestamp, ...payload } = snapshot.payload;
289
+ return (0, import_jcs.canonicalJsonSha256)({
290
+ url: snapshot.url,
291
+ payload,
292
+ retries: snapshot.retries,
293
+ authentication: snapshot.authentication.kind === "none" ? { kind: "none" } : { kind: "protected", fingerprint: snapshot.authentication.fingerprint },
294
+ ...snapshot.payloadToken && { payloadToken: { fingerprint: snapshot.payloadToken.fingerprint } }
295
+ });
296
+ }
297
+ function validatePush(push) {
298
+ if (!push || typeof push !== "object") {
299
+ throw new TaskPushSettlementConfigurationError("push settlement config is required");
300
+ }
301
+ const allowHttp = process.env.NODE_ENV === "test" || process.env.NODE_ENV === "development" || process.env.ADCP_DECISIONING_ALLOW_HTTP_WEBHOOKS === "1";
302
+ let parsedUrl;
303
+ try {
304
+ parsedUrl = typeof push.url === "string" ? new URL(push.url) : void 0;
305
+ } catch {
306
+ }
307
+ if (parsedUrl === void 0 || parsedUrl.hostname.length === 0 || parsedUrl.username.length > 0 || parsedUrl.password.length > 0 || parsedUrl.protocol !== "https:" && !(allowHttp && parsedUrl.protocol === "http:")) {
308
+ throw new TaskPushSettlementConfigurationError(
309
+ "push settlement url must be a request-validated HTTPS destination (HTTP requires the development allowlist)"
310
+ );
311
+ }
312
+ if (push.operationId !== void 0 && (typeof push.operationId !== "string" || !/^[A-Za-z0-9_.:-]{1,255}$/.test(push.operationId))) {
313
+ throw new TaskPushSettlementConfigurationError("push settlement operationId must match /^[A-Za-z0-9_.:-]{1,255}$/");
314
+ }
315
+ if (push.operationId === void 0 && (!(0, import_adcp_version_config.isValidAdcpVersion)(push.servedAdcpVersion) || (0, import_adcp_version_config.isAdcpVersionAtLeast)(push.servedAdcpVersion, "3.2.0-beta.5"))) {
316
+ throw new TaskPushSettlementConfigurationError(
317
+ "push settlement operationId is required unless servedAdcpVersion is an explicit valid pre-3.2.0-beta.5 version"
318
+ );
319
+ }
320
+ if (push.token !== void 0 && (typeof push.token !== "string" || push.token.length < 16 || push.token.length > 4096 || TOKEN_CONTROL_CHAR_RE.test(push.token))) {
321
+ throw new TaskPushSettlementConfigurationError(
322
+ "push settlement token must be a string from 16 through 4096 characters"
323
+ );
324
+ }
325
+ if (push.authentication !== void 0 && push.authentication !== null) {
326
+ const authentication = push.authentication;
327
+ const validBearer = authentication.type === "bearer" && typeof authentication.token === "string" && authentication.token.length >= 32;
328
+ const validHmac = authentication.type === "hmac_sha256" && typeof authentication.secret === "string" && authentication.secret.length >= 32;
329
+ if (!validBearer && !validHmac) {
330
+ throw new TaskPushSettlementConfigurationError(
331
+ "push settlement authentication must be a WebhookAuthentication value"
332
+ );
333
+ }
334
+ }
335
+ }
336
+ function resolveOperationId(push, tool, taskId) {
337
+ return push.operationId ?? `${tool}.${taskId}`;
338
+ }
339
+ function resolveRetries(retries) {
340
+ const resolved = {
341
+ maxAttempts: retries?.maxAttempts ?? 5,
342
+ initialDelayMs: retries?.initialDelayMs ?? 1e3,
343
+ maxDelayMs: retries?.maxDelayMs ?? 6e4,
344
+ jitter: retries?.jitter ?? 0.25
345
+ };
346
+ if (!Number.isSafeInteger(resolved.maxAttempts) || resolved.maxAttempts < 1) {
347
+ throw new TypeError("retries.maxAttempts must be an integer of at least 1");
348
+ }
349
+ for (const key of ["initialDelayMs", "maxDelayMs"]) {
350
+ if (!Number.isFinite(resolved[key]) || resolved[key] < 0) {
351
+ throw new TypeError(`retries.${key} must be a finite non-negative number`);
352
+ }
353
+ }
354
+ if (!Number.isFinite(resolved.jitter) || resolved.jitter < 0 || resolved.jitter > 1) {
355
+ throw new TypeError("retries.jitter must be a finite number from 0 through 1");
356
+ }
357
+ return resolved;
358
+ }
359
+ function assertPayloadSize(result, error) {
360
+ const bytes = Buffer.byteLength(JSON.stringify({ result, error }), "utf8");
361
+ if (bytes > MAX_RESULT_BYTES) {
362
+ throw new TaskPushSettlementConfigurationError(`Task result/error JSON exceeds ${MAX_RESULT_BYTES} bytes`);
363
+ }
364
+ }
365
+ async function readOutbox(client, table, key) {
366
+ const found = await client.query(
367
+ `SELECT snapshot, snapshot_fingerprint, intent_fingerprint, state, disposition
368
+ FROM ${table}
369
+ WHERE publisher_scope = $1 AND tenant_scope = $2 AND delivery_id = $3
370
+ FOR UPDATE`,
371
+ [key.publisherScope, key.tenantScope, key.deliveryId]
372
+ );
373
+ return found.rows[0];
374
+ }
375
+ function deliveryState(row) {
376
+ if (row.state !== "settled") return "recoverable";
377
+ return row.disposition === "delivered" ? "delivered" : "terminal";
378
+ }
379
+ async function rollbackQuietly(client) {
380
+ try {
381
+ await client.query("ROLLBACK");
382
+ } catch {
383
+ }
384
+ }
385
+ // Annotate the CommonJS export names for ESM import in node:
386
+ 0 && (module.exports = {
387
+ TaskPushSettlementConfigurationError,
388
+ completeScopedPushTask,
389
+ createPostgresTaskSettlementCoordinator,
390
+ failScopedPushTask
391
+ });