@adcp/sdk 14.0.0-beta.17 → 14.0.0-beta.18
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/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/context.d.mts +4 -0
- package/dist/lib/server/decisioning/context.d.ts +4 -0
- package/dist/lib/server/decisioning/index.d.mts +1 -0
- package/dist/lib/server/decisioning/index.d.ts +1 -0
- package/dist/lib/server/decisioning/index.js +11 -0
- package/dist/lib/server/decisioning/index.mjs +12 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +5 -3
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +5 -3
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement-intents.d.mts +136 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement-intents.d.ts +136 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement-intents.js +730 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement-intents.mjs +702 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.js +108 -36
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.mjs +108 -36
- package/dist/lib/server/decisioning/runtime/to-context.js +38 -9
- package/dist/lib/server/decisioning/runtime/to-context.mjs +38 -9
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/schemas.generated.js +0 -63
- package/dist/lib/types/schemas.generated.mjs +0 -63
- package/dist/lib/utils/well-formed-unicode.d.mts +2 -0
- package/dist/lib/utils/well-formed-unicode.d.ts +2 -0
- package/dist/lib/utils/well-formed-unicode.js +51 -0
- package/dist/lib/utils/well-formed-unicode.mjs +27 -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/guides/BUILD-AN-AGENT.md +7 -0
- package/docs/guides/DURABLE-TASK-SETTLEMENT.md +468 -0
- package/docs/llms.txt +4 -1
- package/docs/migration-13-to-14.md +1 -1
- package/docs/migration-task-registry-scoping.md +45 -14
- package/package.json +2 -1
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
|
|
5
5
|
"source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
|
|
6
6
|
"upstream_adcp_version": "2.5.3",
|
|
7
|
-
"synced_at": "2026-08-
|
|
7
|
+
"synced_at": "2026-08-30T04:04:07.159Z"
|
|
8
8
|
}
|
|
@@ -43,6 +43,10 @@ export interface RequestContext<TAccount = Account> {
|
|
|
43
43
|
* `ctx_metadata`, account objects, task results, logs, or durable HITL
|
|
44
44
|
* state. Background workers must re-resolve credentials; if durable work
|
|
45
45
|
* only needs identity, snapshot a stable non-secret principal identifier.
|
|
46
|
+
* A native `AbortSignal` stored as a data property at
|
|
47
|
+
* `authInfo.extra.signal` retains its identity so later host cancellation
|
|
48
|
+
* remains observable. Other auth values retain the framework's existing
|
|
49
|
+
* clone-and-freeze behavior.
|
|
46
50
|
*/
|
|
47
51
|
authInfo?: Readonly<ResolvedAuthInfo>;
|
|
48
52
|
/** Framework-derived caller namespace for authenticated mutations. */
|
|
@@ -43,6 +43,10 @@ export interface RequestContext<TAccount = Account> {
|
|
|
43
43
|
* `ctx_metadata`, account objects, task results, logs, or durable HITL
|
|
44
44
|
* state. Background workers must re-resolve credentials; if durable work
|
|
45
45
|
* only needs identity, snapshot a stable non-secret principal identifier.
|
|
46
|
+
* A native `AbortSignal` stored as a data property at
|
|
47
|
+
* `authInfo.extra.signal` retains its identity so later host cancellation
|
|
48
|
+
* remains observable. Other auth values retain the framework's existing
|
|
49
|
+
* clone-and-freeze behavior.
|
|
46
50
|
*/
|
|
47
51
|
authInfo?: Readonly<ResolvedAuthInfo>;
|
|
48
52
|
/** Framework-derived caller namespace for authenticated mutations. */
|
|
@@ -49,6 +49,7 @@ export { PlatformConfigError, validatePlatform } from './runtime/validate-platfo
|
|
|
49
49
|
export { completeScopedTask, createInMemoryTaskRegistry, failScopedTask, updateScopedTaskProgress, type ScopedTaskRef, type TaskMutationOutcome, type TaskRegistry, type TaskRegistryMutationResult, type TaskRegistryScope, type TaskRecord, type TaskStatus, } from './runtime/task-registry.mjs';
|
|
50
50
|
export { createPostgresTaskRegistry, getDecisioningTaskRegistryBootstrap, getDecisioningTaskRegistryMigration, getDecisioningTaskRegistryScopeV1Upgrade, type CreatePostgresTaskRegistryOptions, type DecisioningTaskRegistryScopeV1Upgrade, type DecisioningTaskRegistryScopeV1UpgradeOptions, type PgQueryable, type PgTransactionClient, type PgTransactionalPool, } from './runtime/postgres-task-registry.mjs';
|
|
51
51
|
export { completeScopedPushTask, createPostgresTaskSettlementCoordinator, failScopedPushTask, TaskPushSettlementConfigurationError, type PostgresTaskSettlementCoordinator, type PostgresTaskSettlementCoordinatorOptions, type TaskPushDeliveryState, type TaskPushSettlementConfig, type TaskPushSettlementOutcome, } from './runtime/postgres-task-settlement.mjs';
|
|
52
|
+
export { canonicalizeTaskSettlementIntent, createPostgresTaskSettlementIntentQueue, getTaskSettlementIntentMigration, TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS, TaskSettlementIntentConflictError, type CreatePostgresTaskSettlementIntentQueueOptions, type DurableTaskSettlementRef, type PostgresTaskSettlementIntentQueue, type PruneTaskSettlementIntentAcknowledgementsOptions, type RecoverTaskSettlementIntentsOptions, type TaskSettlementIntent, type TaskSettlementIntentCheckpoint, type TaskSettlementIntentRecoveryContext, type TaskSettlementIntentRecoveryErrorContext, type TaskSettlementIntentRecoveryMetrics, type TaskSettlementIntentWriteOptions, } from './runtime/postgres-task-settlement-intents.mjs';
|
|
52
53
|
export { createTenantRegistry, createDefaultJwksValidator, createSelfSignedTenantKey, createNoopJwksValidator, type TenantRegistry, type TenantConfig, type TenantSigningKey, type TenantStatus, type TenantHealth, type TenantRegistryOptions, type JwksValidator, type JwksValidationResult, } from './tenant-registry.mjs';
|
|
53
54
|
export { getAsset, getAssetSlot, requireAsset } from './manifest-helpers.mjs';
|
|
54
55
|
export type { CreativeAssetsContainer } from './manifest-helpers.mjs';
|
|
@@ -49,6 +49,7 @@ export { PlatformConfigError, validatePlatform } from './runtime/validate-platfo
|
|
|
49
49
|
export { completeScopedTask, createInMemoryTaskRegistry, failScopedTask, updateScopedTaskProgress, type ScopedTaskRef, type TaskMutationOutcome, type TaskRegistry, type TaskRegistryMutationResult, type TaskRegistryScope, type TaskRecord, type TaskStatus, } from './runtime/task-registry';
|
|
50
50
|
export { createPostgresTaskRegistry, getDecisioningTaskRegistryBootstrap, getDecisioningTaskRegistryMigration, getDecisioningTaskRegistryScopeV1Upgrade, type CreatePostgresTaskRegistryOptions, type DecisioningTaskRegistryScopeV1Upgrade, type DecisioningTaskRegistryScopeV1UpgradeOptions, type PgQueryable, type PgTransactionClient, type PgTransactionalPool, } from './runtime/postgres-task-registry';
|
|
51
51
|
export { completeScopedPushTask, createPostgresTaskSettlementCoordinator, failScopedPushTask, TaskPushSettlementConfigurationError, type PostgresTaskSettlementCoordinator, type PostgresTaskSettlementCoordinatorOptions, type TaskPushDeliveryState, type TaskPushSettlementConfig, type TaskPushSettlementOutcome, } from './runtime/postgres-task-settlement';
|
|
52
|
+
export { canonicalizeTaskSettlementIntent, createPostgresTaskSettlementIntentQueue, getTaskSettlementIntentMigration, TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS, TaskSettlementIntentConflictError, type CreatePostgresTaskSettlementIntentQueueOptions, type DurableTaskSettlementRef, type PostgresTaskSettlementIntentQueue, type PruneTaskSettlementIntentAcknowledgementsOptions, type RecoverTaskSettlementIntentsOptions, type TaskSettlementIntent, type TaskSettlementIntentCheckpoint, type TaskSettlementIntentRecoveryContext, type TaskSettlementIntentRecoveryErrorContext, type TaskSettlementIntentRecoveryMetrics, type TaskSettlementIntentWriteOptions, } from './runtime/postgres-task-settlement-intents';
|
|
52
53
|
export { createTenantRegistry, createDefaultJwksValidator, createSelfSignedTenantKey, createNoopJwksValidator, type TenantRegistry, type TenantConfig, type TenantSigningKey, type TenantStatus, type TenantHealth, type TenantRegistryOptions, type JwksValidator, type JwksValidationResult, } from './tenant-registry';
|
|
53
54
|
export { getAsset, getAssetSlot, requireAsset } from './manifest-helpers';
|
|
54
55
|
export type { CreativeAssetsContainer } from './manifest-helpers';
|
|
@@ -46,7 +46,9 @@ __export(decisioning_exports, {
|
|
|
46
46
|
ProductUnavailableError: () => import_errors_typed.ProductUnavailableError,
|
|
47
47
|
RateLimitedError: () => import_errors_typed.RateLimitedError,
|
|
48
48
|
ServiceUnavailableError: () => import_errors_typed.ServiceUnavailableError,
|
|
49
|
+
TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS: () => import_postgres_task_settlement_intents.TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS,
|
|
49
50
|
TaskPushSettlementConfigurationError: () => import_postgres_task_settlement.TaskPushSettlementConfigurationError,
|
|
51
|
+
TaskSettlementIntentConflictError: () => import_postgres_task_settlement_intents.TaskSettlementIntentConflictError,
|
|
50
52
|
UnsupportedFeatureError: () => import_errors_typed.UnsupportedFeatureError,
|
|
51
53
|
batchPoll: () => import_helpers.batchPoll,
|
|
52
54
|
buildListCreativesResponse: () => import_list_helpers.buildListCreativesResponse,
|
|
@@ -55,6 +57,7 @@ __export(decisioning_exports, {
|
|
|
55
57
|
buildPricingOption: () => import_assembly_helpers.buildPricingOption,
|
|
56
58
|
buildProduct: () => import_assembly_helpers.buildProduct,
|
|
57
59
|
buildProductLegacy: () => import_assembly_helpers.buildProductLegacy,
|
|
60
|
+
canonicalizeTaskSettlementIntent: () => import_postgres_task_settlement_intents.canonicalizeTaskSettlementIntent,
|
|
58
61
|
completeScopedPushTask: () => import_postgres_task_settlement.completeScopedPushTask,
|
|
59
62
|
completeScopedTask: () => import_task_registry.completeScopedTask,
|
|
60
63
|
composeMethod: () => import_compose.composeMethod,
|
|
@@ -66,6 +69,7 @@ __export(decisioning_exports, {
|
|
|
66
69
|
createPostgresProposalStore: () => import_proposal.createPostgresProposalStore,
|
|
67
70
|
createPostgresTaskRegistry: () => import_postgres_task_registry.createPostgresTaskRegistry,
|
|
68
71
|
createPostgresTaskSettlementCoordinator: () => import_postgres_task_settlement.createPostgresTaskSettlementCoordinator,
|
|
72
|
+
createPostgresTaskSettlementIntentQueue: () => import_postgres_task_settlement_intents.createPostgresTaskSettlementIntentQueue,
|
|
69
73
|
createSelfSignedTenantKey: () => import_tenant_registry.createSelfSignedTenantKey,
|
|
70
74
|
createTenantAdminHandlers: () => import_admin_router.createTenantAdminHandlers,
|
|
71
75
|
createTenantAdminRouter: () => import_admin_router.createTenantAdminRouter,
|
|
@@ -100,6 +104,7 @@ __export(decisioning_exports, {
|
|
|
100
104
|
getHydratedLegacyFormatIds: () => import_from_platform.getHydratedLegacyFormatIds,
|
|
101
105
|
getProposalStoreMigration: () => import_proposal.getProposalStoreMigration,
|
|
102
106
|
getStatusChangeBus: () => import_status_changes.getStatusChangeBus,
|
|
107
|
+
getTaskSettlementIntentMigration: () => import_postgres_task_settlement_intents.getTaskSettlementIntentMigration,
|
|
103
108
|
identityStatusMappers: () => import_status_mappers.identityStatusMappers,
|
|
104
109
|
maybeHydrateRecipesForMediaBuyId: () => import_proposal.maybeHydrateRecipesForMediaBuyId,
|
|
105
110
|
maybeInterceptFinalize: () => import_proposal.maybeInterceptFinalize,
|
|
@@ -145,6 +150,7 @@ var import_validate_platform = require('./runtime/validate-platform.js');
|
|
|
145
150
|
var import_task_registry = require('./runtime/task-registry.js');
|
|
146
151
|
var import_postgres_task_registry = require('./runtime/postgres-task-registry.js');
|
|
147
152
|
var import_postgres_task_settlement = require('./runtime/postgres-task-settlement.js');
|
|
153
|
+
var import_postgres_task_settlement_intents = require('./runtime/postgres-task-settlement-intents.js');
|
|
148
154
|
var import_tenant_registry = require('./tenant-registry.js');
|
|
149
155
|
var import_manifest_helpers = require('./manifest-helpers.js');
|
|
150
156
|
var import_list_helpers = require('./list-helpers.js');
|
|
@@ -184,7 +190,9 @@ var import_assembly_helpers = require('./assembly-helpers.js');
|
|
|
184
190
|
ProductUnavailableError,
|
|
185
191
|
RateLimitedError,
|
|
186
192
|
ServiceUnavailableError,
|
|
193
|
+
TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS,
|
|
187
194
|
TaskPushSettlementConfigurationError,
|
|
195
|
+
TaskSettlementIntentConflictError,
|
|
188
196
|
UnsupportedFeatureError,
|
|
189
197
|
batchPoll,
|
|
190
198
|
buildListCreativesResponse,
|
|
@@ -193,6 +201,7 @@ var import_assembly_helpers = require('./assembly-helpers.js');
|
|
|
193
201
|
buildPricingOption,
|
|
194
202
|
buildProduct,
|
|
195
203
|
buildProductLegacy,
|
|
204
|
+
canonicalizeTaskSettlementIntent,
|
|
196
205
|
completeScopedPushTask,
|
|
197
206
|
completeScopedTask,
|
|
198
207
|
composeMethod,
|
|
@@ -204,6 +213,7 @@ var import_assembly_helpers = require('./assembly-helpers.js');
|
|
|
204
213
|
createPostgresProposalStore,
|
|
205
214
|
createPostgresTaskRegistry,
|
|
206
215
|
createPostgresTaskSettlementCoordinator,
|
|
216
|
+
createPostgresTaskSettlementIntentQueue,
|
|
207
217
|
createSelfSignedTenantKey,
|
|
208
218
|
createTenantAdminHandlers,
|
|
209
219
|
createTenantAdminRouter,
|
|
@@ -238,6 +248,7 @@ var import_assembly_helpers = require('./assembly-helpers.js');
|
|
|
238
248
|
getHydratedLegacyFormatIds,
|
|
239
249
|
getProposalStoreMigration,
|
|
240
250
|
getStatusChangeBus,
|
|
251
|
+
getTaskSettlementIntentMigration,
|
|
241
252
|
identityStatusMappers,
|
|
242
253
|
maybeHydrateRecipesForMediaBuyId,
|
|
243
254
|
maybeInterceptFinalize,
|
|
@@ -61,6 +61,13 @@ import {
|
|
|
61
61
|
failScopedPushTask,
|
|
62
62
|
TaskPushSettlementConfigurationError
|
|
63
63
|
} from "./runtime/postgres-task-settlement.mjs";
|
|
64
|
+
import {
|
|
65
|
+
canonicalizeTaskSettlementIntent,
|
|
66
|
+
createPostgresTaskSettlementIntentQueue,
|
|
67
|
+
getTaskSettlementIntentMigration,
|
|
68
|
+
TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS,
|
|
69
|
+
TaskSettlementIntentConflictError
|
|
70
|
+
} from "./runtime/postgres-task-settlement-intents.mjs";
|
|
64
71
|
import {
|
|
65
72
|
createTenantRegistry,
|
|
66
73
|
createDefaultJwksValidator,
|
|
@@ -145,7 +152,9 @@ export {
|
|
|
145
152
|
ProductUnavailableError,
|
|
146
153
|
RateLimitedError,
|
|
147
154
|
ServiceUnavailableError,
|
|
155
|
+
TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS,
|
|
148
156
|
TaskPushSettlementConfigurationError,
|
|
157
|
+
TaskSettlementIntentConflictError,
|
|
149
158
|
UnsupportedFeatureError,
|
|
150
159
|
batchPoll,
|
|
151
160
|
buildListCreativesResponse,
|
|
@@ -154,6 +163,7 @@ export {
|
|
|
154
163
|
buildPricingOption,
|
|
155
164
|
buildProduct,
|
|
156
165
|
buildProductLegacy,
|
|
166
|
+
canonicalizeTaskSettlementIntent,
|
|
157
167
|
completeScopedPushTask,
|
|
158
168
|
completeScopedTask,
|
|
159
169
|
composeMethod,
|
|
@@ -165,6 +175,7 @@ export {
|
|
|
165
175
|
createPostgresProposalStore,
|
|
166
176
|
createPostgresTaskRegistry,
|
|
167
177
|
createPostgresTaskSettlementCoordinator,
|
|
178
|
+
createPostgresTaskSettlementIntentQueue,
|
|
168
179
|
createSelfSignedTenantKey,
|
|
169
180
|
createTenantAdminHandlers,
|
|
170
181
|
createTenantAdminRouter,
|
|
@@ -199,6 +210,7 @@ export {
|
|
|
199
210
|
getHydratedLegacyFormatIds,
|
|
200
211
|
getProposalStoreMigration,
|
|
201
212
|
getStatusChangeBus,
|
|
213
|
+
getTaskSettlementIntentMigration,
|
|
202
214
|
identityStatusMappers,
|
|
203
215
|
maybeHydrateRecipesForMediaBuyId,
|
|
204
216
|
maybeInterceptFinalize,
|
|
@@ -382,7 +382,7 @@ function rowToRecord(row) {
|
|
|
382
382
|
...row.owner_scope ? { ownerScope: row.owner_scope } : {},
|
|
383
383
|
status: row.status,
|
|
384
384
|
...row.status_message !== null && { statusMessage: row.status_message },
|
|
385
|
-
...row.result !== null && row.result !== void 0 && { result: row.result },
|
|
385
|
+
...(row.has_result ?? (row.result !== null && row.result !== void 0)) && { result: row.result },
|
|
386
386
|
...row.error !== null && row.error !== void 0 && { error: row.error },
|
|
387
387
|
...row.progress !== null && row.progress !== void 0 && { progress: row.progress },
|
|
388
388
|
...row.has_webhook && { hasWebhook: true },
|
|
@@ -447,7 +447,8 @@ function createPostgresTaskRegistry(opts) {
|
|
|
447
447
|
if (scope.registryId !== void 0 && scope.registryId !== registryId) return null;
|
|
448
448
|
const { rows } = await query(
|
|
449
449
|
"getTask",
|
|
450
|
-
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
450
|
+
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
451
|
+
result IS NOT NULL AS has_result, error, progress, has_webhook, created_at, updated_at
|
|
451
452
|
FROM ${table} WHERE task_id = $1 AND registry_namespace = $2 AND account_id = $3 AND owner_scope = $4`,
|
|
452
453
|
[taskId, namespace, scope.accountId, scope.ownerScope]
|
|
453
454
|
);
|
|
@@ -457,7 +458,8 @@ function createPostgresTaskRegistry(opts) {
|
|
|
457
458
|
async list(listOpts) {
|
|
458
459
|
const { rows } = await query(
|
|
459
460
|
"list",
|
|
460
|
-
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
461
|
+
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
462
|
+
result IS NOT NULL AS has_result, error, progress, has_webhook, created_at, updated_at
|
|
461
463
|
FROM ${table}
|
|
462
464
|
WHERE registry_namespace = $1 AND account_id = $2 AND owner_scope = $3
|
|
463
465
|
ORDER BY created_at DESC, task_id DESC`,
|
|
@@ -355,7 +355,7 @@ function rowToRecord(row) {
|
|
|
355
355
|
...row.owner_scope ? { ownerScope: row.owner_scope } : {},
|
|
356
356
|
status: row.status,
|
|
357
357
|
...row.status_message !== null && { statusMessage: row.status_message },
|
|
358
|
-
...row.result !== null && row.result !== void 0 && { result: row.result },
|
|
358
|
+
...(row.has_result ?? (row.result !== null && row.result !== void 0)) && { result: row.result },
|
|
359
359
|
...row.error !== null && row.error !== void 0 && { error: row.error },
|
|
360
360
|
...row.progress !== null && row.progress !== void 0 && { progress: row.progress },
|
|
361
361
|
...row.has_webhook && { hasWebhook: true },
|
|
@@ -420,7 +420,8 @@ function createPostgresTaskRegistry(opts) {
|
|
|
420
420
|
if (scope.registryId !== void 0 && scope.registryId !== registryId) return null;
|
|
421
421
|
const { rows } = await query(
|
|
422
422
|
"getTask",
|
|
423
|
-
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
423
|
+
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
424
|
+
result IS NOT NULL AS has_result, error, progress, has_webhook, created_at, updated_at
|
|
424
425
|
FROM ${table} WHERE task_id = $1 AND registry_namespace = $2 AND account_id = $3 AND owner_scope = $4`,
|
|
425
426
|
[taskId, namespace, scope.accountId, scope.ownerScope]
|
|
426
427
|
);
|
|
@@ -430,7 +431,8 @@ function createPostgresTaskRegistry(opts) {
|
|
|
430
431
|
async list(listOpts) {
|
|
431
432
|
const { rows } = await query(
|
|
432
433
|
"list",
|
|
433
|
-
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
434
|
+
`SELECT task_id, tool, account_id, owner_scope, status, status_message, result,
|
|
435
|
+
result IS NOT NULL AS has_result, error, progress, has_webhook, created_at, updated_at
|
|
434
436
|
FROM ${table}
|
|
435
437
|
WHERE registry_namespace = $1 AND account_id = $2 AND owner_scope = $3
|
|
436
438
|
ORDER BY created_at DESC, task_id DESC`,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable PostgreSQL queue for application-owned task settlement intents.
|
|
3
|
+
*
|
|
4
|
+
* `createPostgresTaskSettlementCoordinator()` makes the task transition and
|
|
5
|
+
* terminal webhook checkpoint atomic. This queue protects the boundary before
|
|
6
|
+
* that call: an application may commit a human approval or provider outcome
|
|
7
|
+
* and then die before it asks the SDK to settle the AdCP task.
|
|
8
|
+
*/
|
|
9
|
+
import type { AdcpStructuredError } from '../async-outcome.mjs';
|
|
10
|
+
import type { PgQueryable } from './postgres-task-registry.mjs';
|
|
11
|
+
import { type ScopedTaskRef } from './task-registry.mjs';
|
|
12
|
+
/** Default conflict-retention window after an intent is acknowledged. */
|
|
13
|
+
export declare const TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS: number;
|
|
14
|
+
/** Complete, serializable task handle required by the durable intent queue. */
|
|
15
|
+
export interface DurableTaskSettlementRef extends ScopedTaskRef {
|
|
16
|
+
registryId: string;
|
|
17
|
+
ownerScope: string;
|
|
18
|
+
}
|
|
19
|
+
export type TaskSettlementIntent = {
|
|
20
|
+
taskRef: DurableTaskSettlementRef;
|
|
21
|
+
action: 'complete';
|
|
22
|
+
result: unknown;
|
|
23
|
+
} | {
|
|
24
|
+
taskRef: DurableTaskSettlementRef;
|
|
25
|
+
action: 'fail';
|
|
26
|
+
error: AdcpStructuredError;
|
|
27
|
+
result?: unknown;
|
|
28
|
+
};
|
|
29
|
+
export interface TaskSettlementIntentCheckpoint extends DurableTaskSettlementRef {
|
|
30
|
+
queueNamespace: string;
|
|
31
|
+
intentFingerprint: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TaskSettlementIntentRecoveryContext {
|
|
34
|
+
attemptCount: number;
|
|
35
|
+
/** Extend this claim by the configured lease duration. Returns false if fencing ownership was lost. */
|
|
36
|
+
extendLease(): Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
export interface TaskSettlementIntentRecoveryMetrics {
|
|
39
|
+
claimed: number;
|
|
40
|
+
settled: number;
|
|
41
|
+
retried: number;
|
|
42
|
+
deadLettered: number;
|
|
43
|
+
leaseLost: number;
|
|
44
|
+
}
|
|
45
|
+
export interface TaskSettlementIntentRecoveryErrorContext {
|
|
46
|
+
attemptCount: number;
|
|
47
|
+
taskRef: DurableTaskSettlementRef;
|
|
48
|
+
action: TaskSettlementIntent['action'];
|
|
49
|
+
disposition: 'retry' | 'dead_letter' | 'lease_lost';
|
|
50
|
+
}
|
|
51
|
+
export interface RecoverTaskSettlementIntentsOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Apply the exact terminal intent and return the literal `settled` only
|
|
54
|
+
* after the intended state is proven. The implementation MUST be
|
|
55
|
+
* idempotent because a worker can die after settlement and before ack.
|
|
56
|
+
*/
|
|
57
|
+
settle(intent: TaskSettlementIntent, context: TaskSettlementIntentRecoveryContext): Promise<'settled'>;
|
|
58
|
+
batchSize?: number;
|
|
59
|
+
leaseMs?: number;
|
|
60
|
+
retryAfterMs?: number;
|
|
61
|
+
maxRetryAfterMs?: number;
|
|
62
|
+
maxAttempts?: number;
|
|
63
|
+
workerId?: string;
|
|
64
|
+
/** Observability hook. Error messages are never persisted by the queue. */
|
|
65
|
+
onError?(error: unknown, context: TaskSettlementIntentRecoveryErrorContext): void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
export interface TaskSettlementIntentWriteOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Optional active transaction client. Use this to commit the domain outcome
|
|
70
|
+
* and settlement intent atomically in the same application transaction.
|
|
71
|
+
*/
|
|
72
|
+
db?: PgQueryable;
|
|
73
|
+
}
|
|
74
|
+
export interface PruneTaskSettlementIntentAcknowledgementsOptions extends TaskSettlementIntentWriteOptions {
|
|
75
|
+
/** Maximum tombstones removed by this call. Defaults to 1000; maximum 10000. */
|
|
76
|
+
limit?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface PostgresTaskSettlementIntentQueue {
|
|
79
|
+
readonly durability: 'durable';
|
|
80
|
+
enqueue(intent: TaskSettlementIntent, options?: TaskSettlementIntentWriteOptions): Promise<TaskSettlementIntentCheckpoint>;
|
|
81
|
+
/** Returns false when the exact checkpoint was already absent. */
|
|
82
|
+
acknowledge(checkpoint: TaskSettlementIntentCheckpoint, options?: TaskSettlementIntentWriteOptions): Promise<boolean>;
|
|
83
|
+
/** Remove a bounded batch of acknowledgement tombstones whose idempotency horizon elapsed. */
|
|
84
|
+
pruneAcknowledged(options?: PruneTaskSettlementIntentAcknowledgementsOptions): Promise<number>;
|
|
85
|
+
recover(options: RecoverTaskSettlementIntentsOptions): Promise<TaskSettlementIntentRecoveryMetrics>;
|
|
86
|
+
probe(): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export interface CreatePostgresTaskSettlementIntentQueueOptions {
|
|
89
|
+
/** Pool used by recovery and by writes that do not supply a transaction. */
|
|
90
|
+
db: PgQueryable;
|
|
91
|
+
/** Trusted deployment or tenant namespace. */
|
|
92
|
+
namespace: string;
|
|
93
|
+
/** Defaults to `adcp_task_settlement_intents`. */
|
|
94
|
+
tableName?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Retain acknowledged fingerprints for this long so a conflicting terminal
|
|
97
|
+
* artifact cannot rebind the same scoped task. Defaults to seven days.
|
|
98
|
+
*/
|
|
99
|
+
idempotencyHorizonMs?: number;
|
|
100
|
+
}
|
|
101
|
+
/** An existing scoped task is already bound to a different terminal intent. */
|
|
102
|
+
export declare class TaskSettlementIntentConflictError extends Error {
|
|
103
|
+
readonly name = "TaskSettlementIntentConflictError";
|
|
104
|
+
}
|
|
105
|
+
/** Bootstrap DDL for a new durable settlement-intent queue. */
|
|
106
|
+
export declare function getTaskSettlementIntentMigration(options?: {
|
|
107
|
+
tableName?: string;
|
|
108
|
+
}): string;
|
|
109
|
+
/**
|
|
110
|
+
* Create a durable task-settlement intent queue.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const queue = createPostgresTaskSettlementIntentQueue({
|
|
115
|
+
* db: pool,
|
|
116
|
+
* namespace: 'seller-prod',
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* await withTransaction(async tx => {
|
|
120
|
+
* await saveApproval(tx, approval);
|
|
121
|
+
* await queue.enqueue({ taskRef, action: 'complete', result }, { db: tx });
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* await queue.recover({
|
|
125
|
+
* settle: async intent => {
|
|
126
|
+
* await settleThroughRegistryOrPushCoordinator(intent);
|
|
127
|
+
* return 'settled';
|
|
128
|
+
* },
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function createPostgresTaskSettlementIntentQueue(options: CreatePostgresTaskSettlementIntentQueueOptions): PostgresTaskSettlementIntentQueue;
|
|
133
|
+
/** Clone, validate, and reduce an intent to the exact artifact persisted by the task registry. */
|
|
134
|
+
export declare function canonicalizeTaskSettlementIntent(intent: TaskSettlementIntent): TaskSettlementIntent & {
|
|
135
|
+
taskRef: DurableTaskSettlementRef;
|
|
136
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable PostgreSQL queue for application-owned task settlement intents.
|
|
3
|
+
*
|
|
4
|
+
* `createPostgresTaskSettlementCoordinator()` makes the task transition and
|
|
5
|
+
* terminal webhook checkpoint atomic. This queue protects the boundary before
|
|
6
|
+
* that call: an application may commit a human approval or provider outcome
|
|
7
|
+
* and then die before it asks the SDK to settle the AdCP task.
|
|
8
|
+
*/
|
|
9
|
+
import type { AdcpStructuredError } from '../async-outcome';
|
|
10
|
+
import type { PgQueryable } from './postgres-task-registry';
|
|
11
|
+
import { type ScopedTaskRef } from './task-registry';
|
|
12
|
+
/** Default conflict-retention window after an intent is acknowledged. */
|
|
13
|
+
export declare const TASK_SETTLEMENT_INTENT_IDEMPOTENCY_HORIZON_MS: number;
|
|
14
|
+
/** Complete, serializable task handle required by the durable intent queue. */
|
|
15
|
+
export interface DurableTaskSettlementRef extends ScopedTaskRef {
|
|
16
|
+
registryId: string;
|
|
17
|
+
ownerScope: string;
|
|
18
|
+
}
|
|
19
|
+
export type TaskSettlementIntent = {
|
|
20
|
+
taskRef: DurableTaskSettlementRef;
|
|
21
|
+
action: 'complete';
|
|
22
|
+
result: unknown;
|
|
23
|
+
} | {
|
|
24
|
+
taskRef: DurableTaskSettlementRef;
|
|
25
|
+
action: 'fail';
|
|
26
|
+
error: AdcpStructuredError;
|
|
27
|
+
result?: unknown;
|
|
28
|
+
};
|
|
29
|
+
export interface TaskSettlementIntentCheckpoint extends DurableTaskSettlementRef {
|
|
30
|
+
queueNamespace: string;
|
|
31
|
+
intentFingerprint: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TaskSettlementIntentRecoveryContext {
|
|
34
|
+
attemptCount: number;
|
|
35
|
+
/** Extend this claim by the configured lease duration. Returns false if fencing ownership was lost. */
|
|
36
|
+
extendLease(): Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
export interface TaskSettlementIntentRecoveryMetrics {
|
|
39
|
+
claimed: number;
|
|
40
|
+
settled: number;
|
|
41
|
+
retried: number;
|
|
42
|
+
deadLettered: number;
|
|
43
|
+
leaseLost: number;
|
|
44
|
+
}
|
|
45
|
+
export interface TaskSettlementIntentRecoveryErrorContext {
|
|
46
|
+
attemptCount: number;
|
|
47
|
+
taskRef: DurableTaskSettlementRef;
|
|
48
|
+
action: TaskSettlementIntent['action'];
|
|
49
|
+
disposition: 'retry' | 'dead_letter' | 'lease_lost';
|
|
50
|
+
}
|
|
51
|
+
export interface RecoverTaskSettlementIntentsOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Apply the exact terminal intent and return the literal `settled` only
|
|
54
|
+
* after the intended state is proven. The implementation MUST be
|
|
55
|
+
* idempotent because a worker can die after settlement and before ack.
|
|
56
|
+
*/
|
|
57
|
+
settle(intent: TaskSettlementIntent, context: TaskSettlementIntentRecoveryContext): Promise<'settled'>;
|
|
58
|
+
batchSize?: number;
|
|
59
|
+
leaseMs?: number;
|
|
60
|
+
retryAfterMs?: number;
|
|
61
|
+
maxRetryAfterMs?: number;
|
|
62
|
+
maxAttempts?: number;
|
|
63
|
+
workerId?: string;
|
|
64
|
+
/** Observability hook. Error messages are never persisted by the queue. */
|
|
65
|
+
onError?(error: unknown, context: TaskSettlementIntentRecoveryErrorContext): void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
export interface TaskSettlementIntentWriteOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Optional active transaction client. Use this to commit the domain outcome
|
|
70
|
+
* and settlement intent atomically in the same application transaction.
|
|
71
|
+
*/
|
|
72
|
+
db?: PgQueryable;
|
|
73
|
+
}
|
|
74
|
+
export interface PruneTaskSettlementIntentAcknowledgementsOptions extends TaskSettlementIntentWriteOptions {
|
|
75
|
+
/** Maximum tombstones removed by this call. Defaults to 1000; maximum 10000. */
|
|
76
|
+
limit?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface PostgresTaskSettlementIntentQueue {
|
|
79
|
+
readonly durability: 'durable';
|
|
80
|
+
enqueue(intent: TaskSettlementIntent, options?: TaskSettlementIntentWriteOptions): Promise<TaskSettlementIntentCheckpoint>;
|
|
81
|
+
/** Returns false when the exact checkpoint was already absent. */
|
|
82
|
+
acknowledge(checkpoint: TaskSettlementIntentCheckpoint, options?: TaskSettlementIntentWriteOptions): Promise<boolean>;
|
|
83
|
+
/** Remove a bounded batch of acknowledgement tombstones whose idempotency horizon elapsed. */
|
|
84
|
+
pruneAcknowledged(options?: PruneTaskSettlementIntentAcknowledgementsOptions): Promise<number>;
|
|
85
|
+
recover(options: RecoverTaskSettlementIntentsOptions): Promise<TaskSettlementIntentRecoveryMetrics>;
|
|
86
|
+
probe(): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export interface CreatePostgresTaskSettlementIntentQueueOptions {
|
|
89
|
+
/** Pool used by recovery and by writes that do not supply a transaction. */
|
|
90
|
+
db: PgQueryable;
|
|
91
|
+
/** Trusted deployment or tenant namespace. */
|
|
92
|
+
namespace: string;
|
|
93
|
+
/** Defaults to `adcp_task_settlement_intents`. */
|
|
94
|
+
tableName?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Retain acknowledged fingerprints for this long so a conflicting terminal
|
|
97
|
+
* artifact cannot rebind the same scoped task. Defaults to seven days.
|
|
98
|
+
*/
|
|
99
|
+
idempotencyHorizonMs?: number;
|
|
100
|
+
}
|
|
101
|
+
/** An existing scoped task is already bound to a different terminal intent. */
|
|
102
|
+
export declare class TaskSettlementIntentConflictError extends Error {
|
|
103
|
+
readonly name = "TaskSettlementIntentConflictError";
|
|
104
|
+
}
|
|
105
|
+
/** Bootstrap DDL for a new durable settlement-intent queue. */
|
|
106
|
+
export declare function getTaskSettlementIntentMigration(options?: {
|
|
107
|
+
tableName?: string;
|
|
108
|
+
}): string;
|
|
109
|
+
/**
|
|
110
|
+
* Create a durable task-settlement intent queue.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const queue = createPostgresTaskSettlementIntentQueue({
|
|
115
|
+
* db: pool,
|
|
116
|
+
* namespace: 'seller-prod',
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* await withTransaction(async tx => {
|
|
120
|
+
* await saveApproval(tx, approval);
|
|
121
|
+
* await queue.enqueue({ taskRef, action: 'complete', result }, { db: tx });
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* await queue.recover({
|
|
125
|
+
* settle: async intent => {
|
|
126
|
+
* await settleThroughRegistryOrPushCoordinator(intent);
|
|
127
|
+
* return 'settled';
|
|
128
|
+
* },
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function createPostgresTaskSettlementIntentQueue(options: CreatePostgresTaskSettlementIntentQueueOptions): PostgresTaskSettlementIntentQueue;
|
|
133
|
+
/** Clone, validate, and reduce an intent to the exact artifact persisted by the task registry. */
|
|
134
|
+
export declare function canonicalizeTaskSettlementIntent(intent: TaskSettlementIntent): TaskSettlementIntent & {
|
|
135
|
+
taskRef: DurableTaskSettlementRef;
|
|
136
|
+
};
|