@adcp/sdk 14.0.0 → 14.1.0

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 (185) hide show
  1. package/dist/lib/adapters/implicit-account-store.d.mts +12 -7
  2. package/dist/lib/adapters/implicit-account-store.d.ts +12 -7
  3. package/dist/lib/adapters/implicit-account-store.js +69 -15
  4. package/dist/lib/adapters/implicit-account-store.mjs +69 -15
  5. package/dist/lib/core/AgentClient.d.mts +1 -0
  6. package/dist/lib/core/AgentClient.d.ts +1 -0
  7. package/dist/lib/core/AgentClient.js +3 -0
  8. package/dist/lib/core/AgentClient.mjs +3 -0
  9. package/dist/lib/core/SingleAgentClient.d.mts +31 -1
  10. package/dist/lib/core/SingleAgentClient.d.ts +31 -1
  11. package/dist/lib/core/SingleAgentClient.js +355 -35
  12. package/dist/lib/core/SingleAgentClient.mjs +365 -37
  13. package/dist/lib/core/TaskExecutor.js +2 -1
  14. package/dist/lib/core/TaskExecutor.mjs +2 -1
  15. package/dist/lib/core/account-key.d.mts +3 -0
  16. package/dist/lib/core/account-key.d.ts +3 -0
  17. package/dist/lib/core/account-key.js +41 -0
  18. package/dist/lib/core/account-key.mjs +17 -0
  19. package/dist/lib/core/account-resolution.d.mts +2 -0
  20. package/dist/lib/core/account-resolution.d.ts +2 -0
  21. package/dist/lib/core/buyer-account-registry.d.mts +65 -0
  22. package/dist/lib/core/buyer-account-registry.d.ts +65 -0
  23. package/dist/lib/core/buyer-account-registry.js +518 -0
  24. package/dist/lib/core/buyer-account-registry.mjs +494 -0
  25. package/dist/lib/core/product-cache.d.mts +18 -0
  26. package/dist/lib/core/product-cache.d.ts +18 -0
  27. package/dist/lib/core/product-cache.js +137 -0
  28. package/dist/lib/core/product-cache.mjs +112 -0
  29. package/dist/lib/errors/index.d.mts +40 -1
  30. package/dist/lib/errors/index.d.ts +40 -1
  31. package/dist/lib/errors/index.js +69 -3
  32. package/dist/lib/errors/index.mjs +64 -3
  33. package/dist/lib/governance/authorization.d.mts +17 -1
  34. package/dist/lib/governance/authorization.d.ts +17 -1
  35. package/dist/lib/governance/authorization.js +55 -7
  36. package/dist/lib/governance/authorization.mjs +59 -7
  37. package/dist/lib/governance/index.d.mts +2 -2
  38. package/dist/lib/governance/index.d.ts +2 -2
  39. package/dist/lib/governance/index.js +2 -0
  40. package/dist/lib/governance/index.mjs +3 -1
  41. package/dist/lib/index.d.mts +5 -3
  42. package/dist/lib/index.d.ts +5 -3
  43. package/dist/lib/index.js +20 -0
  44. package/dist/lib/index.mjs +19 -0
  45. package/dist/lib/protocols/a2a.js +9 -1
  46. package/dist/lib/protocols/a2a.mjs +9 -1
  47. package/dist/lib/protocols/index.js +9 -2
  48. package/dist/lib/protocols/index.mjs +9 -2
  49. package/dist/lib/protocols/mcp-modern.js +2 -1
  50. package/dist/lib/protocols/mcp-modern.mjs +2 -1
  51. package/dist/lib/protocols/mcp.js +5 -2
  52. package/dist/lib/protocols/mcp.mjs +5 -2
  53. package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
  54. package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
  55. package/dist/lib/protocols/rawResponseCapture.js +41 -29
  56. package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
  57. package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
  58. package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
  59. package/dist/lib/protocols/signedRequestRejection.js +209 -0
  60. package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
  61. package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
  62. package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
  63. package/dist/lib/protocols/transportDiagnostics.js +2 -0
  64. package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
  65. package/dist/lib/registry/types.generated.d.mts +112 -45
  66. package/dist/lib/registry/types.generated.d.ts +112 -45
  67. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  68. package/dist/lib/server/account-provisioning.d.mts +2 -0
  69. package/dist/lib/server/account-provisioning.d.ts +2 -0
  70. package/dist/lib/server/account-provisioning.js +30 -0
  71. package/dist/lib/server/account-provisioning.mjs +6 -0
  72. package/dist/lib/server/account-reference-warnings.d.mts +12 -0
  73. package/dist/lib/server/account-reference-warnings.d.ts +12 -0
  74. package/dist/lib/server/account-reference-warnings.js +48 -0
  75. package/dist/lib/server/account-reference-warnings.mjs +23 -0
  76. package/dist/lib/server/auth-signature.js +1 -0
  77. package/dist/lib/server/auth-signature.mjs +1 -0
  78. package/dist/lib/server/create-adcp-server.d.mts +34 -0
  79. package/dist/lib/server/create-adcp-server.d.ts +34 -0
  80. package/dist/lib/server/create-adcp-server.js +225 -14
  81. package/dist/lib/server/create-adcp-server.mjs +225 -14
  82. package/dist/lib/server/decisioning/account.d.mts +2 -0
  83. package/dist/lib/server/decisioning/account.d.ts +2 -0
  84. package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
  85. package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
  86. package/dist/lib/server/index.d.mts +2 -2
  87. package/dist/lib/server/index.d.ts +2 -2
  88. package/dist/lib/server/index.js +2 -0
  89. package/dist/lib/server/index.mjs +3 -1
  90. package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
  91. package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
  92. package/dist/lib/signing/agent-resolver/consistency.js +0 -1
  93. package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
  94. package/dist/lib/signing/agent-resolver/errors.d.mts +1 -1
  95. package/dist/lib/signing/agent-resolver/errors.d.ts +1 -1
  96. package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +2 -0
  97. package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +2 -0
  98. package/dist/lib/signing/agent-resolver/fetch-helpers.js +2 -1
  99. package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +2 -1
  100. package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
  101. package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
  102. package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
  103. package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
  104. package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
  105. package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
  106. package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
  107. package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
  108. package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
  109. package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
  110. package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
  111. package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
  112. package/dist/lib/signing/agent-resolver/resolve-agent.js +101 -132
  113. package/dist/lib/signing/agent-resolver/resolve-agent.mjs +102 -133
  114. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
  115. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
  116. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
  117. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
  118. package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
  119. package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
  120. package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
  121. package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
  122. package/dist/lib/signing/brand-jwks.d.mts +27 -75
  123. package/dist/lib/signing/brand-jwks.d.ts +27 -75
  124. package/dist/lib/signing/brand-jwks.js +112 -182
  125. package/dist/lib/signing/brand-jwks.mjs +112 -182
  126. package/dist/lib/signing/errors.d.mts +3 -1
  127. package/dist/lib/signing/errors.d.ts +3 -1
  128. package/dist/lib/signing/errors.js +4 -1
  129. package/dist/lib/signing/errors.mjs +4 -1
  130. package/dist/lib/signing/jwks-https.d.mts +7 -0
  131. package/dist/lib/signing/jwks-https.d.ts +7 -0
  132. package/dist/lib/signing/jwks-https.js +31 -8
  133. package/dist/lib/signing/jwks-https.mjs +31 -8
  134. package/dist/lib/signing/jwks.d.mts +8 -0
  135. package/dist/lib/signing/jwks.d.ts +8 -0
  136. package/dist/lib/signing/middleware.js +2 -1
  137. package/dist/lib/signing/middleware.mjs +2 -1
  138. package/dist/lib/signing/publisher-pins.d.mts +11 -0
  139. package/dist/lib/signing/publisher-pins.d.ts +11 -0
  140. package/dist/lib/signing/publisher-pins.js +125 -0
  141. package/dist/lib/signing/publisher-pins.mjs +101 -0
  142. package/dist/lib/signing/server.d.mts +1 -0
  143. package/dist/lib/signing/server.d.ts +1 -0
  144. package/dist/lib/signing/types.d.mts +5 -0
  145. package/dist/lib/signing/types.d.ts +5 -0
  146. package/dist/lib/signing/verifier.js +49 -4
  147. package/dist/lib/signing/verifier.mjs +49 -4
  148. package/dist/lib/signing/webhook-verifier.d.mts +7 -2
  149. package/dist/lib/signing/webhook-verifier.d.ts +7 -2
  150. package/dist/lib/signing/webhook-verifier.js +42 -2
  151. package/dist/lib/signing/webhook-verifier.mjs +43 -3
  152. package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
  153. package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
  154. package/dist/lib/testing/storyboard/account-policy.js +35 -0
  155. package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
  156. package/dist/lib/testing/storyboard/context.js +6 -0
  157. package/dist/lib/testing/storyboard/context.mjs +6 -0
  158. package/dist/lib/testing/storyboard/request-builder.js +12 -2
  159. package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
  160. package/dist/lib/testing/storyboard/runner.js +3 -2
  161. package/dist/lib/testing/storyboard/runner.mjs +3 -2
  162. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  163. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  164. package/dist/lib/version.d.mts +3 -3
  165. package/dist/lib/version.d.ts +3 -3
  166. package/dist/lib/version.js +3 -3
  167. package/dist/lib/version.mjs +3 -3
  168. package/dist/lib/wholesale-feed-sync/sync.d.mts +1 -0
  169. package/dist/lib/wholesale-feed-sync/sync.d.ts +1 -0
  170. package/dist/lib/wholesale-feed-sync/sync.js +92 -21
  171. package/dist/lib/wholesale-feed-sync/sync.mjs +92 -21
  172. package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
  173. package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
  174. package/docs/TYPE-SUMMARY.md +2 -2
  175. package/docs/guides/BUILD-AN-AGENT.md +2 -2
  176. package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
  177. package/docs/guides/FIRST-CALL-TO-A-SELLER.md +104 -0
  178. package/docs/guides/SIGNING-GUIDE.md +16 -7
  179. package/docs/guides/account-resolution.md +86 -0
  180. package/docs/llms.txt +3 -2
  181. package/docs/migration-14.x-rc-worksheet.md +4 -4
  182. package/docs/migration-4.x-to-5.x.md +1 -0
  183. package/docs/migration-agent-resolution-3.3.md +123 -0
  184. package/docs/recipes/verifying-inbound-webhooks.md +56 -15
  185. package/package.json +2 -2
@@ -16,6 +16,8 @@ export interface ResolveAccountOptions {
16
16
  forTask?: string;
17
17
  /** Billing party for buyer-declared accounts when the seller has no default. */
18
18
  billing?: 'operator' | 'agent' | 'advertiser';
19
+ paymentTerms?: import('../types/tools.generated').PaymentTerms;
20
+ billingEntity?: import('../types/tools.generated').BusinessEntity;
19
21
  /** An account_id or a callback choosing one of the eligible list_accounts rows. */
20
22
  select?: string | ((accounts: readonly ListedAccount[]) => string);
21
23
  }
@@ -0,0 +1,65 @@
1
+ import type { AccountReference, BusinessEntity, PaymentTerms, SyncAccountsResponse } from '../types/tools.generated.mjs';
2
+ import type { TaskOptions, TaskResult } from './ConversationTypes.mjs';
3
+ export type AccountPolicy = 'auto' | 'strict' | 'off';
4
+ export interface EnsureAccountOptions {
5
+ billing?: 'operator' | 'agent' | 'advertiser';
6
+ paymentTerms?: PaymentTerms;
7
+ billingEntity?: BusinessEntity;
8
+ }
9
+ export interface ProvisionedAccount {
10
+ account: AccountReference;
11
+ account_id?: string;
12
+ status: string;
13
+ pendingTaskId?: string;
14
+ /** Hashes of explicitly selected setup options; billing identities themselves are never persisted. */
15
+ setupTerms?: Partial<Record<keyof EnsureAccountOptions, string>>;
16
+ /** Stored reference aliases for authoritative repair after restart. */
17
+ aliases?: AccountReference[];
18
+ }
19
+ /** Partitioned by seller and caller scope. Implementations must provide read-your-writes. */
20
+ export interface BuyerAccountStorage {
21
+ get(key: string): Promise<ProvisionedAccount | undefined>;
22
+ set(key: string, account: ProvisionedAccount): Promise<void>;
23
+ }
24
+ export interface BuyerAccountRegistryOptions {
25
+ maxEntries?: number;
26
+ normalizeOptions?: (options: EnsureAccountOptions, taskOptions?: TaskOptions) => Promise<EnsureAccountOptions>;
27
+ }
28
+ export declare class BuyerAccountRegistry {
29
+ private scope;
30
+ private provision;
31
+ private storage?;
32
+ private repair?;
33
+ private entries;
34
+ private pending;
35
+ private writes;
36
+ private repairs;
37
+ private repairWaiters;
38
+ private invalidatedHandles;
39
+ private observationEpoch;
40
+ private observationFloor;
41
+ private statusEpochs;
42
+ private readonly maxEntries;
43
+ private readonly normalizeOptions?;
44
+ constructor(scope: () => string, provision: (key: AccountReference, options: EnsureAccountOptions, taskOptions?: TaskOptions) => Promise<TaskResult<SyncAccountsResponse>>, storage?: BuyerAccountStorage | undefined, repair?: ((accountId: string, taskOptions?: TaskOptions) => Promise<readonly unknown[]>) | undefined, options?: BuyerAccountRegistryOptions);
45
+ private key;
46
+ /** Capture before a seller request; observations older than a status repair are ignored. */
47
+ captureObservation(): number;
48
+ private observationIsCurrent;
49
+ private remember;
50
+ get(account: AccountReference): Promise<ProvisionedAccount | undefined>;
51
+ ensure(account: AccountReference, options?: EnsureAccountOptions, taskOptions?: TaskOptions, onTaskResult?: (result: TaskResult<unknown>) => void): Promise<ProvisionedAccount>;
52
+ private write;
53
+ private record;
54
+ private enqueue;
55
+ observeSync(refs: readonly AccountReference[], rows: readonly unknown[], dryRun?: boolean, observationEpoch?: number): Promise<void>;
56
+ private reconcileId;
57
+ observeList(rows: readonly unknown[], queriedAccountId?: string, observationEpoch?: number): Promise<void>;
58
+ private observeListAtScope;
59
+ /** After verifying account.status_changed, repair aliases by handle from the authoritative seller. */
60
+ applyStatusChange(notification: {
61
+ account_id: string;
62
+ }, options?: TaskOptions): Promise<void>;
63
+ private repairStatus;
64
+ private runRepair;
65
+ }
@@ -0,0 +1,65 @@
1
+ import type { AccountReference, BusinessEntity, PaymentTerms, SyncAccountsResponse } from '../types/tools.generated';
2
+ import type { TaskOptions, TaskResult } from './ConversationTypes';
3
+ export type AccountPolicy = 'auto' | 'strict' | 'off';
4
+ export interface EnsureAccountOptions {
5
+ billing?: 'operator' | 'agent' | 'advertiser';
6
+ paymentTerms?: PaymentTerms;
7
+ billingEntity?: BusinessEntity;
8
+ }
9
+ export interface ProvisionedAccount {
10
+ account: AccountReference;
11
+ account_id?: string;
12
+ status: string;
13
+ pendingTaskId?: string;
14
+ /** Hashes of explicitly selected setup options; billing identities themselves are never persisted. */
15
+ setupTerms?: Partial<Record<keyof EnsureAccountOptions, string>>;
16
+ /** Stored reference aliases for authoritative repair after restart. */
17
+ aliases?: AccountReference[];
18
+ }
19
+ /** Partitioned by seller and caller scope. Implementations must provide read-your-writes. */
20
+ export interface BuyerAccountStorage {
21
+ get(key: string): Promise<ProvisionedAccount | undefined>;
22
+ set(key: string, account: ProvisionedAccount): Promise<void>;
23
+ }
24
+ export interface BuyerAccountRegistryOptions {
25
+ maxEntries?: number;
26
+ normalizeOptions?: (options: EnsureAccountOptions, taskOptions?: TaskOptions) => Promise<EnsureAccountOptions>;
27
+ }
28
+ export declare class BuyerAccountRegistry {
29
+ private scope;
30
+ private provision;
31
+ private storage?;
32
+ private repair?;
33
+ private entries;
34
+ private pending;
35
+ private writes;
36
+ private repairs;
37
+ private repairWaiters;
38
+ private invalidatedHandles;
39
+ private observationEpoch;
40
+ private observationFloor;
41
+ private statusEpochs;
42
+ private readonly maxEntries;
43
+ private readonly normalizeOptions?;
44
+ constructor(scope: () => string, provision: (key: AccountReference, options: EnsureAccountOptions, taskOptions?: TaskOptions) => Promise<TaskResult<SyncAccountsResponse>>, storage?: BuyerAccountStorage | undefined, repair?: ((accountId: string, taskOptions?: TaskOptions) => Promise<readonly unknown[]>) | undefined, options?: BuyerAccountRegistryOptions);
45
+ private key;
46
+ /** Capture before a seller request; observations older than a status repair are ignored. */
47
+ captureObservation(): number;
48
+ private observationIsCurrent;
49
+ private remember;
50
+ get(account: AccountReference): Promise<ProvisionedAccount | undefined>;
51
+ ensure(account: AccountReference, options?: EnsureAccountOptions, taskOptions?: TaskOptions, onTaskResult?: (result: TaskResult<unknown>) => void): Promise<ProvisionedAccount>;
52
+ private write;
53
+ private record;
54
+ private enqueue;
55
+ observeSync(refs: readonly AccountReference[], rows: readonly unknown[], dryRun?: boolean, observationEpoch?: number): Promise<void>;
56
+ private reconcileId;
57
+ observeList(rows: readonly unknown[], queriedAccountId?: string, observationEpoch?: number): Promise<void>;
58
+ private observeListAtScope;
59
+ /** After verifying account.status_changed, repair aliases by handle from the authoritative seller. */
60
+ applyStatusChange(notification: {
61
+ account_id: string;
62
+ }, options?: TaskOptions): Promise<void>;
63
+ private repairStatus;
64
+ private runRepair;
65
+ }
@@ -0,0 +1,518 @@
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 buyer_account_registry_exports = {};
20
+ __export(buyer_account_registry_exports, {
21
+ BuyerAccountRegistry: () => BuyerAccountRegistry
22
+ });
23
+ module.exports = __toCommonJS(buyer_account_registry_exports);
24
+ var import_node_util = require("node:util");
25
+ var import_node_crypto = require("node:crypto");
26
+ var import_account_key = require('./account-key.js');
27
+ var import_account_resolution = require('./account-resolution.js');
28
+ var import_errors = require('../errors/index.js');
29
+ var import_abort = require('../protocols/abort.js');
30
+ var import_task_deadline = require('./task-deadline.js');
31
+ function setupTerms(options) {
32
+ const stable = (value) => Array.isArray(value) ? value.map(stable) : value && typeof value === "object" ? Object.fromEntries(
33
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, stable(item)])
34
+ ) : value;
35
+ return Object.fromEntries(
36
+ Object.entries(options).map(([key, value]) => [
37
+ key,
38
+ (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(stable(value))).digest("hex")
39
+ ])
40
+ );
41
+ }
42
+ class BuyerAccountRegistry {
43
+ constructor(scope, provision, storage, repair, options = {}) {
44
+ this.scope = scope;
45
+ this.provision = provision;
46
+ this.storage = storage;
47
+ this.repair = repair;
48
+ this.maxEntries = options.maxEntries ?? 1e4;
49
+ this.normalizeOptions = options.normalizeOptions;
50
+ if (!Number.isSafeInteger(this.maxEntries) || this.maxEntries < 2)
51
+ throw new Error("Account registry maxEntries must be an integer >= 2.");
52
+ }
53
+ scope;
54
+ provision;
55
+ storage;
56
+ repair;
57
+ entries = /* @__PURE__ */ new Map();
58
+ pending = /* @__PURE__ */ new Map();
59
+ writes = Promise.resolve();
60
+ repairs = /* @__PURE__ */ new Map();
61
+ repairWaiters = /* @__PURE__ */ new Map();
62
+ invalidatedHandles = /* @__PURE__ */ new Set();
63
+ observationEpoch = 0;
64
+ observationFloor = 0;
65
+ statusEpochs = /* @__PURE__ */ new Map();
66
+ maxEntries;
67
+ normalizeOptions;
68
+ key(account, scope = this.scope()) {
69
+ return `${scope}:${(0, import_account_key.accountReferenceKey)(account)}`;
70
+ }
71
+ /** Capture before a seller request; observations older than a status repair are ignored. */
72
+ captureObservation() {
73
+ return this.observationEpoch;
74
+ }
75
+ observationIsCurrent(accountId, epoch, scope) {
76
+ return epoch === void 0 || epoch >= this.observationFloor && (!accountId || (this.statusEpochs.get(this.key({ account_id: accountId }, scope)) ?? 0) <= epoch);
77
+ }
78
+ remember(key, entry) {
79
+ if (!this.entries.has(key) && this.entries.size >= this.maxEntries) {
80
+ if (!this.storage)
81
+ throw new import_errors.AccountSetupRequiredError(
82
+ "Account registry capacity reached; configure durable storage or increase maxEntries."
83
+ );
84
+ this.entries.delete(this.entries.keys().next().value);
85
+ }
86
+ this.entries.set(key, structuredClone(entry));
87
+ }
88
+ async get(account) {
89
+ const key = this.key(account);
90
+ let entry = this.entries.get(key);
91
+ if (!entry) {
92
+ const persisted = await this.storage?.get(key);
93
+ entry = this.entries.get(key) ?? persisted;
94
+ }
95
+ if (key !== this.key(account) || entry && (0, import_account_key.accountReferenceKey)(entry.account) !== (0, import_account_key.accountReferenceKey)(account))
96
+ return void 0;
97
+ if (entry) this.remember(key, entry);
98
+ if (entry?.account_id && this.invalidatedHandles.has(this.key({ account_id: entry.account_id })))
99
+ return { ...structuredClone(entry), status: "unknown" };
100
+ return entry ? structuredClone(entry) : void 0;
101
+ }
102
+ async ensure(account, options = {}, taskOptions, onTaskResult) {
103
+ (0, import_abort.throwIfAborted)(taskOptions?.signal);
104
+ if (taskOptions?.timeout !== void 0 && (!Number.isFinite(taskOptions.timeout) || taskOptions.timeout < 0 || taskOptions.timeout > import_abort.MAX_TIMER_DELAY_MS))
105
+ throw new RangeError(`timeout must be a finite non-negative number <= ${import_abort.MAX_TIMER_DELAY_MS}`);
106
+ account = structuredClone(account);
107
+ if (this.normalizeOptions) options = await this.normalizeOptions(structuredClone(options), taskOptions);
108
+ options = structuredClone(Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0)));
109
+ const scope = this.scope();
110
+ const key = this.key(account, scope);
111
+ const current = await this.get(account);
112
+ (0, import_abort.throwIfAborted)(taskOptions?.signal);
113
+ if (scope !== this.scope()) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
114
+ const shared = this.pending.get(key);
115
+ const wait = (promise) => (0, import_task_deadline.withTaskDeadline)(
116
+ taskOptions,
117
+ (options2) => (0, import_abort.withAbortSignal)([options2.signal], void 0, () => promise.then((entry2) => structuredClone(entry2)))
118
+ );
119
+ if (shared) {
120
+ if (!(0, import_node_util.isDeepStrictEqual)(shared.options, options))
121
+ throw new import_errors.AccountSetupRequiredError("Provisioning is already in progress with different billing terms.");
122
+ const entry2 = await wait(shared.promise);
123
+ if (shared.result) onTaskResult?.(shared.result);
124
+ return entry2;
125
+ }
126
+ const terms = setupTerms(options);
127
+ if (current?.status === "failed_provisioning" && current.setupTerms && !(0, import_node_util.isDeepStrictEqual)(current.setupTerms, terms))
128
+ throw new import_errors.AccountSetupRequiredError(
129
+ "The pending account was provisioned with different billing terms. Call syncAccounts explicitly to change terms."
130
+ );
131
+ if (current && current.status !== "failed_provisioning") {
132
+ if (Object.entries(terms ?? {}).some(
133
+ ([name, value]) => current.setupTerms?.[name] !== void 0 && current.setupTerms[name] !== value
134
+ ))
135
+ throw new import_errors.AccountSetupRequiredError(
136
+ "The account was provisioned with different billing terms. Call syncAccounts explicitly to change terms."
137
+ );
138
+ if (current.status !== "active" && current.account_id && this.repair) {
139
+ try {
140
+ await this.repairStatus(current.account_id, taskOptions, false);
141
+ } catch (error) {
142
+ (0, import_abort.throwIfAborted)(taskOptions?.signal);
143
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) throw error;
144
+ if (scope !== this.scope())
145
+ throw new import_errors.AccountNotFoundError("Caller credentials changed during reconciliation.");
146
+ return current;
147
+ }
148
+ const refreshed = await this.get(account) ?? current;
149
+ if (scope !== this.scope()) throw new import_errors.AccountNotFoundError("Caller credentials changed during reconciliation.");
150
+ if (refreshed.status === "unknown")
151
+ throw new import_errors.AccountNotFoundError(
152
+ "The seller no longer lists this account. Call syncAccounts explicitly to reestablish it."
153
+ );
154
+ return refreshed;
155
+ }
156
+ if (current.status === "unknown")
157
+ throw new import_errors.AccountNotFoundError(
158
+ "Reconcile this account with listAccounts or explicitly reestablish it with syncAccounts."
159
+ );
160
+ if (current.status === "provisioning" && current.pendingTaskId)
161
+ throw new import_errors.AccountSetupRequiredError(
162
+ `Reconcile pending sync_accounts task ${current.pendingTaskId} and observe its completed account rows before provisioning again.`
163
+ );
164
+ if (current.status !== "pending_approval" || current.account_id) return current;
165
+ if (!current.setupTerms || !(0, import_node_util.isDeepStrictEqual)(current.setupTerms, terms))
166
+ throw new import_errors.AccountSetupRequiredError(
167
+ "Provide the original billing options to refresh a legacy account without a handle, or call syncAccounts explicitly."
168
+ );
169
+ }
170
+ const requiredEntries = current ? 1 : 2;
171
+ if (!this.storage && this.entries.size + this.pending.size * 2 + requiredEntries > this.maxEntries) {
172
+ throw new import_errors.AccountSetupRequiredError(
173
+ "Account registry capacity reached; configure durable storage or increase maxEntries."
174
+ );
175
+ }
176
+ const pending = { promise: void 0, options: structuredClone(options) };
177
+ let callbackFailed = false;
178
+ let callbackError;
179
+ const notify = (result) => {
180
+ try {
181
+ onTaskResult?.(result);
182
+ } catch (error) {
183
+ callbackFailed = true;
184
+ callbackError = error;
185
+ }
186
+ };
187
+ const operationOptions = { ...taskOptions, signal: void 0, timeout: void 0 };
188
+ const observationEpoch = this.captureObservation();
189
+ const request = this.provision(structuredClone(account), pending.options, operationOptions).then(async (initial) => {
190
+ let result = initial;
191
+ pending.result = result;
192
+ notify(result);
193
+ if (this.key(account) !== key) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
194
+ if (!result.success)
195
+ throw (0, import_errors.adcpErrorToTypedError)(result.adcpError ?? { code: "ACCOUNT_NOT_FOUND", message: result.error }) ?? new Error(result.error);
196
+ if (result.status !== "completed") {
197
+ const provisional = {
198
+ account: structuredClone(account),
199
+ status: "provisioning",
200
+ setupTerms: current?.setupTerms ?? terms,
201
+ ...result.metadata.taskId && { pendingTaskId: result.metadata.taskId }
202
+ };
203
+ await this.enqueue(async () => {
204
+ const latest = await this.get(account);
205
+ if (!latest || latest.status === "failed_provisioning" || latest.status === current?.status && latest.account_id === current?.account_id)
206
+ await this.write(provisional, scope);
207
+ });
208
+ if (!result.submitted) return provisional;
209
+ result = await result.submitted.waitForCompletion();
210
+ pending.result = result;
211
+ notify(result);
212
+ if (!result.success) {
213
+ await this.enqueue(async () => {
214
+ const latest = await this.get(account);
215
+ if (!latest || latest.status === "provisioning")
216
+ await this.write(
217
+ {
218
+ account: structuredClone(account),
219
+ status: "failed_provisioning",
220
+ setupTerms: current?.setupTerms ?? terms
221
+ },
222
+ scope
223
+ );
224
+ });
225
+ throw (0, import_errors.adcpErrorToTypedError)(result.adcpError ?? { code: "ACCOUNT_SETUP_REQUIRED", message: result.error }) ?? new Error(result.error);
226
+ }
227
+ }
228
+ if (this.key(account) !== key) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
229
+ if (result.status !== "completed" || !result.data || !("accounts" in result.data))
230
+ throw new import_errors.AccountSetupRequiredError(
231
+ "sync_accounts has not completed; observe its completion before provisioning again."
232
+ );
233
+ await this.observeSync([account], result.data.accounts, false, observationEpoch);
234
+ const entry2 = await this.get(account);
235
+ if (scope !== this.scope()) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
236
+ if (!entry2 || entry2.status === "provisioning" || entry2.status === "failed_provisioning") {
237
+ await this.enqueue(async () => {
238
+ const latest = await this.get(account);
239
+ if (!latest || ["provisioning", "failed_provisioning"].includes(latest.status))
240
+ await this.write(
241
+ {
242
+ account,
243
+ status: "failed_provisioning",
244
+ setupTerms: current?.setupTerms ?? terms
245
+ },
246
+ scope
247
+ );
248
+ });
249
+ const failed = result.data.accounts.find((row) => row.action === "failed");
250
+ const error = failed?.errors?.[0];
251
+ throw (error && (0, import_errors.adcpErrorToTypedError)(error)) ?? new import_errors.AccountNotFoundError("sync_accounts did not establish the requested account.");
252
+ }
253
+ let settled = entry2;
254
+ await this.enqueue(async () => {
255
+ const latest = await this.get(account);
256
+ if (scope !== this.scope()) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
257
+ if (!latest) throw new import_errors.AccountNotFoundError("The provisioned account is no longer registered.");
258
+ settled = latest;
259
+ if (latest.account_id !== entry2.account_id) return;
260
+ settled = { ...latest, setupTerms: setupTerms(options) };
261
+ await this.write(settled, scope);
262
+ if (settled.account_id && !("account_id" in account)) {
263
+ const idEntry = await this.get({ account_id: settled.account_id });
264
+ if (scope !== this.scope()) throw new import_errors.AccountNotFoundError("Caller credentials changed during provisioning.");
265
+ if (idEntry) await this.write({ ...idEntry, setupTerms: settled.setupTerms }, scope);
266
+ }
267
+ });
268
+ return settled;
269
+ });
270
+ pending.promise = request;
271
+ this.pending.set(key, pending);
272
+ const cleanup = () => {
273
+ if (this.pending.get(key) === pending) this.pending.delete(key);
274
+ };
275
+ void request.then(cleanup, cleanup);
276
+ const entry = await wait(request);
277
+ if (callbackFailed) throw callbackError;
278
+ return entry;
279
+ }
280
+ async write(entry, scope, isCurrent = () => true) {
281
+ if (!isCurrent()) return;
282
+ const key = this.key(entry.account, scope);
283
+ if (scope === this.scope()) this.remember(key, entry);
284
+ await this.storage?.set(key, structuredClone(entry));
285
+ }
286
+ async record(ref, row, scope, preserveTerms = false, isCurrent = () => true) {
287
+ const entry = {
288
+ account: structuredClone(ref),
289
+ status: row.status,
290
+ ...row.account_id && { account_id: row.account_id }
291
+ };
292
+ const prior = await this.get(ref);
293
+ if (scope !== this.scope() || !isCurrent()) return;
294
+ const idRef = row.account_id && !("account_id" in ref) ? { account_id: row.account_id } : void 0;
295
+ const priorId = idRef ? await this.get(idRef) : void 0;
296
+ if (scope !== this.scope() || !isCurrent()) return;
297
+ const aliases = new Map((priorId?.aliases ?? []).map((alias) => [(0, import_account_key.accountReferenceKey)(alias), alias]));
298
+ if (idRef) {
299
+ aliases.set((0, import_account_key.accountReferenceKey)(ref), structuredClone(ref));
300
+ if (aliases.size > this.maxEntries)
301
+ throw new import_errors.AccountSetupRequiredError("Account alias capacity reached; increase registry maxEntries.");
302
+ }
303
+ if (!("account_id" in ref) && prior?.account_id && prior.account_id !== row.account_id) {
304
+ const oldId = await this.get({ account_id: prior.account_id });
305
+ if (scope !== this.scope() || !isCurrent()) return;
306
+ if (oldId?.aliases) {
307
+ await this.write(
308
+ { ...oldId, aliases: oldId.aliases.filter((alias) => (0, import_account_key.accountReferenceKey)(alias) !== (0, import_account_key.accountReferenceKey)(ref)) },
309
+ scope,
310
+ isCurrent
311
+ );
312
+ }
313
+ }
314
+ if (preserveTerms && prior?.setupTerms) entry.setupTerms = prior.setupTerms;
315
+ if ("account_id" in ref) {
316
+ if (prior?.aliases) entry.aliases = prior.aliases;
317
+ }
318
+ await this.write(entry, scope, isCurrent);
319
+ if (!idRef || scope !== this.scope() || !isCurrent()) return;
320
+ await this.write(
321
+ {
322
+ account: idRef,
323
+ account_id: row.account_id,
324
+ status: row.status,
325
+ aliases: [...aliases.values()],
326
+ ...preserveTerms && priorId?.setupTerms && { setupTerms: priorId.setupTerms }
327
+ },
328
+ scope,
329
+ isCurrent
330
+ );
331
+ }
332
+ enqueue(run) {
333
+ const next = this.writes.then(run);
334
+ this.writes = next.catch(() => {
335
+ });
336
+ return next;
337
+ }
338
+ async observeSync(refs, rows, dryRun = false, observationEpoch) {
339
+ if (dryRun) return;
340
+ const scope = this.scope();
341
+ return this.enqueue(async () => {
342
+ if (scope !== this.scope()) return;
343
+ for (const ref of refs) {
344
+ const candidates = rows.filter((value) => {
345
+ if (!value || typeof value !== "object") return false;
346
+ const row2 = value;
347
+ if ("account_id" in ref) return row2.account_id === ref.account_id;
348
+ return row2.brand?.domain === ref.brand.domain && row2.operator === ref.operator && (!ref.brand.brand_id || row2.brand.brand_id === ref.brand.brand_id) && (0, import_account_resolution.sameCountrySet)(ref.brand.countries, row2.brand.countries) && (!ref.operator_unit || row2.operator_unit?.id === ref.operator_unit.id) && (!ref.currency || row2.currency === ref.currency) && (!ref.timezone || row2.timezone === ref.timezone) && (row2.sandbox === void 0 || row2.sandbox === true === (ref.sandbox === true));
349
+ });
350
+ if (candidates.length !== 1) continue;
351
+ let row = candidates[0];
352
+ if (row.action === "failed" || typeof row.status !== "string") continue;
353
+ const prior = await this.get(ref);
354
+ if (scope !== this.scope()) return;
355
+ let rowEpoch = observationEpoch;
356
+ let repairedBinding = false;
357
+ if (!this.observationIsCurrent(row.account_id, rowEpoch, scope)) {
358
+ if (!row.account_id || prior?.account_id && prior.account_id !== row.account_id) continue;
359
+ const captured = this.captureObservation();
360
+ const authoritative = await this.get({ account_id: row.account_id });
361
+ if (scope !== this.scope()) return;
362
+ row = {
363
+ ...row,
364
+ status: captured === this.captureObservation() ? authoritative?.status ?? "unknown" : "unknown"
365
+ };
366
+ rowEpoch = this.captureObservation();
367
+ repairedBinding = true;
368
+ }
369
+ const isCurrent = () => scope === this.scope() && this.observationIsCurrent(row.account_id, rowEpoch, scope);
370
+ await this.record(ref, row, scope, false, isCurrent);
371
+ if (!isCurrent() || repairedBinding) continue;
372
+ for (const id of [row.account_id])
373
+ if (id) {
374
+ const key = this.key({ account_id: id }, scope);
375
+ this.repairs.delete(key);
376
+ this.invalidatedHandles.delete(key);
377
+ }
378
+ }
379
+ });
380
+ }
381
+ async reconcileId(accountId, status, scope, isCurrent = () => true) {
382
+ if (scope !== this.scope() || !isCurrent()) return;
383
+ const idRef = { account_id: accountId };
384
+ const indexed = await this.get(idRef);
385
+ if (scope !== this.scope() || !isCurrent()) return;
386
+ const aliases = new Map((indexed?.aliases ?? []).map((ref) => [(0, import_account_key.accountReferenceKey)(ref), ref]));
387
+ for (const [key, entry] of this.entries) {
388
+ if (key === this.key(entry.account, scope) && entry.account_id === accountId && !("account_id" in entry.account)) {
389
+ aliases.set((0, import_account_key.accountReferenceKey)(entry.account), entry.account);
390
+ }
391
+ }
392
+ for (const ref of aliases.values()) {
393
+ const prior = await this.get(ref);
394
+ if (scope !== this.scope() || !isCurrent()) return;
395
+ if (!prior || prior.account_id !== accountId) {
396
+ aliases.delete((0, import_account_key.accountReferenceKey)(ref));
397
+ continue;
398
+ }
399
+ await this.write({ ...prior, account: ref, account_id: accountId, status }, scope, isCurrent);
400
+ }
401
+ if (scope !== this.scope() || !isCurrent()) return;
402
+ if (indexed || aliases.size)
403
+ await this.write(
404
+ { ...indexed, account: idRef, account_id: accountId, status, aliases: [...aliases.values()] },
405
+ scope,
406
+ isCurrent
407
+ );
408
+ }
409
+ async observeList(rows, queriedAccountId, observationEpoch) {
410
+ const scope = this.scope();
411
+ return this.observeListAtScope(rows, queriedAccountId, scope, void 0, observationEpoch);
412
+ }
413
+ async observeListAtScope(rows, queriedAccountId, scope, isCurrent, observationEpoch) {
414
+ return this.enqueue(async () => {
415
+ if (scope !== this.scope() || isCurrent && !isCurrent()) return;
416
+ if (!this.observationIsCurrent(queriedAccountId, observationEpoch, scope)) return;
417
+ let foundQuery = false;
418
+ for (const value of rows) {
419
+ if (!value || typeof value !== "object") continue;
420
+ const row = value;
421
+ if (typeof row.account_id !== "string" || typeof row.status !== "string") continue;
422
+ if (!this.observationIsCurrent(row.account_id, observationEpoch, scope)) continue;
423
+ const current = () => scope === this.scope() && (!isCurrent || isCurrent()) && this.observationIsCurrent(row.account_id, observationEpoch, scope);
424
+ if (row.account_id === queriedAccountId) foundQuery = true;
425
+ await this.reconcileId(row.account_id, row.status, scope, current);
426
+ await this.record({ account_id: row.account_id }, row, scope, true, current);
427
+ if (row.brand?.domain && row.operator) {
428
+ const ref = {
429
+ brand: row.brand,
430
+ operator: row.operator,
431
+ ...row.operator_unit && { operator_unit: row.operator_unit },
432
+ ...row.currency && { currency: row.currency },
433
+ ...row.timezone && { timezone: row.timezone },
434
+ ...row.sandbox !== void 0 && { sandbox: row.sandbox }
435
+ };
436
+ const prior = await this.get(ref);
437
+ if (scope !== this.scope()) return;
438
+ if (!prior?.account_id || prior.account_id === row.account_id)
439
+ await this.record(ref, row, scope, true, current);
440
+ }
441
+ if (!isCurrent && current()) {
442
+ const key = this.key({ account_id: row.account_id }, scope);
443
+ this.repairs.delete(key);
444
+ this.invalidatedHandles.delete(key);
445
+ }
446
+ }
447
+ if (queriedAccountId && !foundQuery) {
448
+ const current = () => scope === this.scope() && (!isCurrent || isCurrent()) && this.observationIsCurrent(queriedAccountId, observationEpoch, scope);
449
+ await this.reconcileId(queriedAccountId, "unknown", scope, current);
450
+ if (!isCurrent && current()) {
451
+ const key = this.key({ account_id: queriedAccountId }, scope);
452
+ this.repairs.delete(key);
453
+ this.invalidatedHandles.delete(key);
454
+ }
455
+ }
456
+ });
457
+ }
458
+ /** After verifying account.status_changed, repair aliases by handle from the authoritative seller. */
459
+ async applyStatusChange(notification, options) {
460
+ return this.repairStatus(notification.account_id, options, true);
461
+ }
462
+ async repairStatus(accountId, options, invalidate) {
463
+ (0, import_abort.throwIfAborted)(options?.signal);
464
+ const key = this.key({ account_id: accountId });
465
+ let operation = !invalidate ? this.repairWaiters.get(key) : void 0;
466
+ if (!operation) {
467
+ operation = this.runRepair(accountId, { ...options, signal: void 0, timeout: void 0 }, invalidate);
468
+ this.repairWaiters.set(key, operation);
469
+ const cleanup = () => {
470
+ if (this.repairWaiters.get(key) === operation) this.repairWaiters.delete(key);
471
+ };
472
+ void operation.then(cleanup, cleanup);
473
+ }
474
+ const wait = (promise) => (0, import_task_deadline.withTaskDeadline)(options, (taskOptions) => (0, import_abort.withAbortSignal)([taskOptions.signal], void 0, () => promise));
475
+ await wait(operation);
476
+ let newer = this.repairWaiters.get(key);
477
+ while (newer && newer !== operation) {
478
+ operation = newer;
479
+ await wait(operation);
480
+ newer = this.repairWaiters.get(key);
481
+ }
482
+ }
483
+ async runRepair(accountId, options, invalidate) {
484
+ if (!this.repair) throw new Error("Account registry requires a list_accounts repair callback.");
485
+ const scope = this.scope();
486
+ const key = this.key({ account_id: accountId }, scope);
487
+ const token = {};
488
+ this.statusEpochs.delete(key);
489
+ this.statusEpochs.set(key, ++this.observationEpoch);
490
+ if (this.statusEpochs.size > this.maxEntries) {
491
+ const oldestKey = this.statusEpochs.keys().next().value;
492
+ this.observationFloor = this.statusEpochs.get(oldestKey);
493
+ this.statusEpochs.delete(oldestKey);
494
+ }
495
+ this.repairs.set(key, token);
496
+ if (invalidate) this.invalidatedHandles.add(key);
497
+ let invalidationPersisted = !invalidate;
498
+ try {
499
+ if (invalidate) {
500
+ await this.enqueue(() => this.reconcileId(accountId, "unknown", scope, () => this.repairs.get(key) === token));
501
+ invalidationPersisted = true;
502
+ }
503
+ const rows = (await this.repair(accountId, options)).filter(
504
+ (row) => row !== null && typeof row === "object" && row.account_id === accountId
505
+ );
506
+ await this.observeListAtScope(rows, accountId, scope, () => this.repairs.get(key) === token);
507
+ } finally {
508
+ if (this.repairs.get(key) === token) {
509
+ this.repairs.delete(key);
510
+ if (invalidationPersisted) this.invalidatedHandles.delete(key);
511
+ }
512
+ }
513
+ }
514
+ }
515
+ // Annotate the CommonJS export names for ESM import in node:
516
+ 0 && (module.exports = {
517
+ BuyerAccountRegistry
518
+ });