@adcp/sdk 14.0.0 → 14.2.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.
- package/dist/lib/adapters/implicit-account-store.d.mts +12 -7
- package/dist/lib/adapters/implicit-account-store.d.ts +12 -7
- package/dist/lib/adapters/implicit-account-store.js +69 -15
- package/dist/lib/adapters/implicit-account-store.mjs +69 -15
- package/dist/lib/core/AgentClient.d.mts +1 -0
- package/dist/lib/core/AgentClient.d.ts +1 -0
- package/dist/lib/core/AgentClient.js +3 -0
- package/dist/lib/core/AgentClient.mjs +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +35 -2
- package/dist/lib/core/SingleAgentClient.d.ts +35 -2
- package/dist/lib/core/SingleAgentClient.js +377 -36
- package/dist/lib/core/SingleAgentClient.mjs +387 -38
- package/dist/lib/core/TaskExecutor.d.mts +3 -1
- package/dist/lib/core/TaskExecutor.d.ts +3 -1
- package/dist/lib/core/TaskExecutor.js +17 -12
- package/dist/lib/core/TaskExecutor.mjs +17 -12
- package/dist/lib/core/account-key.d.mts +3 -0
- package/dist/lib/core/account-key.d.ts +3 -0
- package/dist/lib/core/account-key.js +41 -0
- package/dist/lib/core/account-key.mjs +17 -0
- package/dist/lib/core/account-resolution.d.mts +2 -0
- package/dist/lib/core/account-resolution.d.ts +2 -0
- package/dist/lib/core/buyer-account-registry.d.mts +93 -0
- package/dist/lib/core/buyer-account-registry.d.ts +93 -0
- package/dist/lib/core/buyer-account-registry.js +602 -0
- package/dist/lib/core/buyer-account-registry.mjs +578 -0
- package/dist/lib/core/product-cache.d.mts +18 -0
- package/dist/lib/core/product-cache.d.ts +18 -0
- package/dist/lib/core/product-cache.js +137 -0
- package/dist/lib/core/product-cache.mjs +112 -0
- package/dist/lib/errors/index.d.mts +40 -1
- package/dist/lib/errors/index.d.ts +40 -1
- package/dist/lib/errors/index.js +69 -3
- package/dist/lib/errors/index.mjs +64 -3
- package/dist/lib/governance/authorization.d.mts +17 -1
- package/dist/lib/governance/authorization.d.ts +17 -1
- package/dist/lib/governance/authorization.js +55 -7
- package/dist/lib/governance/authorization.mjs +59 -7
- package/dist/lib/governance/index.d.mts +2 -2
- package/dist/lib/governance/index.d.ts +2 -2
- package/dist/lib/governance/index.js +2 -0
- package/dist/lib/governance/index.mjs +3 -1
- package/dist/lib/index.d.mts +7 -4
- package/dist/lib/index.d.ts +7 -4
- package/dist/lib/index.js +29 -0
- package/dist/lib/index.mjs +31 -1
- package/dist/lib/net/agent-transport-fetch.d.mts +4 -0
- package/dist/lib/net/agent-transport-fetch.d.ts +4 -0
- package/dist/lib/net/agent-transport-fetch.js +18 -5
- package/dist/lib/net/agent-transport-fetch.mjs +17 -5
- package/dist/lib/protocols/a2a.js +9 -1
- package/dist/lib/protocols/a2a.mjs +9 -1
- package/dist/lib/protocols/index.js +9 -2
- package/dist/lib/protocols/index.mjs +9 -2
- package/dist/lib/protocols/mcp-modern.js +2 -1
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +5 -2
- package/dist/lib/protocols/mcp.mjs +5 -2
- package/dist/lib/protocols/rawResponseCapture.d.mts +6 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +6 -0
- package/dist/lib/protocols/rawResponseCapture.js +41 -29
- package/dist/lib/protocols/rawResponseCapture.mjs +40 -29
- package/dist/lib/protocols/signedRequestRejection.d.mts +9 -0
- package/dist/lib/protocols/signedRequestRejection.d.ts +9 -0
- package/dist/lib/protocols/signedRequestRejection.js +209 -0
- package/dist/lib/protocols/signedRequestRejection.mjs +189 -0
- package/dist/lib/protocols/transportDiagnostics.d.mts +1 -0
- package/dist/lib/protocols/transportDiagnostics.d.ts +1 -0
- package/dist/lib/protocols/transportDiagnostics.js +2 -0
- package/dist/lib/protocols/transportDiagnostics.mjs +1 -0
- package/dist/lib/registry/types.generated.d.mts +112 -45
- package/dist/lib/registry/types.generated.d.ts +112 -45
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-provisioning.d.mts +2 -0
- package/dist/lib/server/account-provisioning.d.ts +2 -0
- package/dist/lib/server/account-provisioning.js +30 -0
- package/dist/lib/server/account-provisioning.mjs +6 -0
- package/dist/lib/server/account-reference-warnings.d.mts +12 -0
- package/dist/lib/server/account-reference-warnings.d.ts +12 -0
- package/dist/lib/server/account-reference-warnings.js +48 -0
- package/dist/lib/server/account-reference-warnings.mjs +23 -0
- package/dist/lib/server/auth-signature.js +1 -0
- package/dist/lib/server/auth-signature.mjs +1 -0
- package/dist/lib/server/create-adcp-server.d.mts +34 -0
- package/dist/lib/server/create-adcp-server.d.ts +34 -0
- package/dist/lib/server/create-adcp-server.js +225 -14
- package/dist/lib/server/create-adcp-server.mjs +225 -14
- package/dist/lib/server/decisioning/account.d.mts +2 -0
- package/dist/lib/server/decisioning/account.d.ts +2 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +49 -10
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +49 -10
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +3 -1
- package/dist/lib/signing/agent-resolver/consistency.d.mts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.d.ts +6 -13
- package/dist/lib/signing/agent-resolver/consistency.js +0 -1
- package/dist/lib/signing/agent-resolver/consistency.mjs +0 -1
- package/dist/lib/signing/agent-resolver/errors.d.mts +3 -1
- package/dist/lib/signing/agent-resolver/errors.d.ts +3 -1
- package/dist/lib/signing/agent-resolver/errors.js +6 -0
- package/dist/lib/signing/agent-resolver/errors.mjs +6 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.mts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.d.ts +11 -0
- package/dist/lib/signing/agent-resolver/fetch-helpers.js +37 -2
- package/dist/lib/signing/agent-resolver/fetch-helpers.mjs +40 -3
- package/dist/lib/signing/agent-resolver/jwks-set.js +24 -3
- package/dist/lib/signing/agent-resolver/jwks-set.mjs +24 -3
- package/dist/lib/signing/agent-resolver/legacy-brand.d.mts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.d.ts +15 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.js +60 -0
- package/dist/lib/signing/agent-resolver/legacy-brand.mjs +36 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.mts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.d.ts +13 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.js +108 -0
- package/dist/lib/signing/agent-resolver/operator-authorization.mjs +84 -0
- package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +14 -4
- package/dist/lib/signing/agent-resolver/resolve-agent.js +148 -137
- package/dist/lib/signing/agent-resolver/resolve-agent.mjs +157 -139
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +7 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +50 -17
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +50 -17
- package/dist/lib/signing/agent-resolver/select-agent.d.mts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.d.ts +14 -15
- package/dist/lib/signing/agent-resolver/select-agent.js +98 -13
- package/dist/lib/signing/agent-resolver/select-agent.mjs +95 -13
- package/dist/lib/signing/brand-jwks.d.mts +29 -75
- package/dist/lib/signing/brand-jwks.d.ts +29 -75
- package/dist/lib/signing/brand-jwks.js +120 -182
- package/dist/lib/signing/brand-jwks.mjs +120 -182
- package/dist/lib/signing/errors.d.mts +7 -3
- package/dist/lib/signing/errors.d.ts +7 -3
- package/dist/lib/signing/errors.js +7 -2
- package/dist/lib/signing/errors.mjs +7 -2
- package/dist/lib/signing/jwks-https.d.mts +7 -0
- package/dist/lib/signing/jwks-https.d.ts +7 -0
- package/dist/lib/signing/jwks-https.js +31 -8
- package/dist/lib/signing/jwks-https.mjs +31 -8
- package/dist/lib/signing/jwks.d.mts +8 -0
- package/dist/lib/signing/jwks.d.ts +8 -0
- package/dist/lib/signing/middleware.js +2 -1
- package/dist/lib/signing/middleware.mjs +2 -1
- package/dist/lib/signing/publisher-pins.d.mts +11 -0
- package/dist/lib/signing/publisher-pins.d.ts +11 -0
- package/dist/lib/signing/publisher-pins.js +125 -0
- package/dist/lib/signing/publisher-pins.mjs +101 -0
- package/dist/lib/signing/server.d.mts +1 -0
- package/dist/lib/signing/server.d.ts +1 -0
- package/dist/lib/signing/types.d.mts +5 -0
- package/dist/lib/signing/types.d.ts +5 -0
- package/dist/lib/signing/verifier.js +50 -5
- package/dist/lib/signing/verifier.mjs +50 -5
- package/dist/lib/signing/webhook-verifier.d.mts +7 -2
- package/dist/lib/signing/webhook-verifier.d.ts +7 -2
- package/dist/lib/signing/webhook-verifier.js +42 -2
- package/dist/lib/signing/webhook-verifier.mjs +42 -2
- package/dist/lib/testing/storyboard/account-policy.d.mts +2 -0
- package/dist/lib/testing/storyboard/account-policy.d.ts +2 -0
- package/dist/lib/testing/storyboard/account-policy.js +35 -0
- package/dist/lib/testing/storyboard/account-policy.mjs +11 -0
- package/dist/lib/testing/storyboard/context.js +6 -0
- package/dist/lib/testing/storyboard/context.mjs +6 -0
- package/dist/lib/testing/storyboard/request-builder.js +12 -2
- package/dist/lib/testing/storyboard/request-builder.mjs +12 -2
- package/dist/lib/testing/storyboard/runner.js +3 -2
- package/dist/lib/testing/storyboard/runner.mjs +3 -2
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/accept-proposal.d.ts +19 -1
- package/dist/lib/types/buy-products.d.ts +19 -1
- package/dist/lib/types/check-governance.d.ts +19 -1
- package/dist/lib/types/comply-test-controller.d.ts +19 -1
- package/dist/lib/types/control-media-buy.d.ts +19 -1
- package/dist/lib/types/core.generated.d.mts +14 -1
- package/dist/lib/types/core.generated.d.ts +14 -1
- package/dist/lib/types/create-media-buy.d.ts +14 -1
- package/dist/lib/types/get-media-buys.d.ts +14 -1
- package/dist/lib/types/get-products.d.ts +19 -1
- package/dist/lib/types/list-products.d.ts +19 -1
- package/dist/lib/types/refine-proposals.d.ts +19 -1
- package/dist/lib/types/request-proposals.d.ts +19 -1
- package/dist/lib/types/schemas.generated.d.ts +12 -3
- package/dist/lib/types/schemas.generated.js +4 -1
- package/dist/lib/types/schemas.generated.mjs +4 -1
- package/dist/lib/types/tools.generated.d.mts +14 -1
- package/dist/lib/types/tools.generated.d.ts +14 -1
- package/dist/lib/types/update-media-buy.d.ts +14 -1
- 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/dist/lib/webhooks/index.d.mts +24 -0
- package/dist/lib/webhooks/index.d.ts +24 -0
- package/dist/lib/webhooks/index.js +50 -24
- package/dist/lib/webhooks/index.mjs +49 -24
- package/dist/lib/wholesale-feed-sync/index.d.mts +2 -0
- package/dist/lib/wholesale-feed-sync/index.d.ts +2 -0
- package/dist/lib/wholesale-feed-sync/index.js +7 -0
- package/dist/lib/wholesale-feed-sync/index.mjs +4 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.mts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.d.ts +97 -0
- package/dist/lib/wholesale-feed-sync/mirror.js +350 -0
- package/dist/lib/wholesale-feed-sync/mirror.mjs +322 -0
- package/dist/lib/wholesale-feed-sync/sync.d.mts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.d.ts +13 -29
- package/dist/lib/wholesale-feed-sync/sync.js +208 -281
- package/dist/lib/wholesale-feed-sync/sync.mjs +213 -281
- package/dist/lib/wholesale-feed-sync/types.d.mts +4 -3
- package/dist/lib/wholesale-feed-sync/types.d.ts +4 -3
- package/docs/README.md +6 -0
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/BUILD-AN-AGENT.md +2 -2
- package/docs/guides/BUYER-QUICKSTART-3.2.md +2 -0
- package/docs/guides/BUYER-STORAGE.md +3 -0
- package/docs/guides/FIRST-CALL-TO-A-SELLER.md +106 -0
- package/docs/guides/SIGNING-GUIDE.md +16 -7
- package/docs/guides/account-resolution.md +132 -10
- package/docs/llms.txt +3 -2
- package/docs/migration-14.0-to-14.1.md +85 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-4.x-to-5.x.md +1 -0
- package/docs/migration-agent-resolution-3.3.md +125 -0
- package/docs/recipes/verifying-inbound-webhooks.md +60 -15
- package/package.json +3 -2
- package/skills/adcp-brand.previous/SKILL.md +0 -200
- package/skills/adcp-creative.previous/SKILL.md +0 -305
- package/skills/adcp-governance.previous/SKILL.md +0 -566
- package/skills/adcp-measurement.previous/SKILL.md +0 -136
- package/skills/adcp-media-buy.previous/SKILL.md +0 -556
- package/skills/adcp-si.previous/SKILL.md +0 -206
- package/skills/adcp-signals.previous/SKILL.md +0 -204
|
@@ -23,12 +23,17 @@ __export(sync_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(sync_exports);
|
|
24
24
|
var import_node_events = require("node:events");
|
|
25
25
|
var import_node_util = require("node:util");
|
|
26
|
-
var
|
|
26
|
+
var import_mirror = require('./mirror.js');
|
|
27
27
|
var import_webhook_notification = require('./webhook-notification.js');
|
|
28
|
+
const bootstrapReadFailures = /* @__PURE__ */ new WeakSet();
|
|
29
|
+
function supersededRepairError() {
|
|
30
|
+
const error = new Error("WholesaleFeedSync: repair superseded repeatedly; retry webhook delivery.");
|
|
31
|
+
bootstrapReadFailures.add(error);
|
|
32
|
+
return error;
|
|
33
|
+
}
|
|
28
34
|
const DEFAULT_PROBE_INTERVAL_MS = 6e5;
|
|
29
35
|
const DEFAULT_CAPABILITY_REFRESH_INTERVAL_MS = 864e5;
|
|
30
36
|
const DEFAULT_PERSISTENCE_TIMEOUT_MS = 3e4;
|
|
31
|
-
const DEFAULT_BOOTSTRAP_PAGE_LIMIT = 100;
|
|
32
37
|
const VERSION_MISMATCH_RECOVERY_ATTEMPTS = 3;
|
|
33
38
|
const VERSION_MISMATCH_RECOVERY_BACKOFF_MS = 5;
|
|
34
39
|
class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
@@ -69,11 +74,10 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
69
74
|
probeTimer = null;
|
|
70
75
|
capabilityTimer = null;
|
|
71
76
|
lifecycleEpoch = 0;
|
|
77
|
+
mirrorRevision = 0;
|
|
72
78
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* agents (products-feed + signals-wholesale-only, or vice versa) this
|
|
76
|
-
* may differ from `signals.mode`.
|
|
79
|
+
* Product index view. `mode` identifies the product sync strategy and may
|
|
80
|
+
* differ from `signals.mode` for agents with mixed feed capabilities.
|
|
77
81
|
*/
|
|
78
82
|
products = {
|
|
79
83
|
list: () => [...this.productIndex.values()],
|
|
@@ -108,19 +112,12 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
108
112
|
},
|
|
109
113
|
_mode: "manual",
|
|
110
114
|
/**
|
|
111
|
-
*
|
|
112
|
-
* `
|
|
113
|
-
* agent only supports brief-mode discovery — `signals.list()` will
|
|
114
|
-
* be empty until adopters call into the agent with their own briefs.
|
|
115
|
+
* True when `get_signals` supports `discovery_mode: 'wholesale'`.
|
|
116
|
+
* Otherwise `list()` is empty; use client brief discovery instead.
|
|
115
117
|
*/
|
|
116
118
|
queryable: true
|
|
117
119
|
};
|
|
118
|
-
|
|
119
|
-
* One-shot console warning when adopters call `signals.list()` or
|
|
120
|
-
* `signals.search()` against an agent that doesn't support wholesale
|
|
121
|
-
* signal enumeration. Without this, empty results read as "no signals
|
|
122
|
-
* match" rather than "the agent doesn't browse, only briefs."
|
|
123
|
-
*/
|
|
120
|
+
// Warn once when empty signal results reflect missing wholesale support.
|
|
124
121
|
warnIfSignalsNotQueryable() {
|
|
125
122
|
if (this.signals.queryable || this.signalsQueryableWarned) return;
|
|
126
123
|
if (this._state === "idle" || this._state === "bootstrapping") return;
|
|
@@ -146,14 +143,9 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
146
143
|
}
|
|
147
144
|
// ====== Lifecycle ======
|
|
148
145
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* Safe to call repeatedly — concurrent calls await the in-flight
|
|
154
|
-
* bootstrap and return when it completes (no duplicate bootstrap, no
|
|
155
|
-
* silent drop). Sequential calls re-probe capabilities and re-bootstrap,
|
|
156
|
-
* equivalent to calling `refresh()` after a mode upgrade.
|
|
146
|
+
* Discover capabilities, bootstrap the mirror, and schedule auto-poll probes
|
|
147
|
+
* for versioned sellers. Concurrent calls share the bootstrap; sequential
|
|
148
|
+
* calls re-probe capabilities and refresh the mirror.
|
|
157
149
|
*/
|
|
158
150
|
async start() {
|
|
159
151
|
if (this.startPromise && this.startPromiseEpoch === this.lifecycleEpoch) return this.startPromise;
|
|
@@ -172,12 +164,13 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
172
164
|
const epoch = this.lifecycleEpoch;
|
|
173
165
|
if (!await this.restorePersistedState(epoch)) return;
|
|
174
166
|
if (!await this.resolveMode(epoch)) return;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
167
|
+
try {
|
|
168
|
+
await this.bootstrapWithRetries({ epoch });
|
|
169
|
+
} finally {
|
|
170
|
+
if (this.isLifecycleCurrent(epoch)) {
|
|
171
|
+
if (this._mode === "auto-poll") this.scheduleProbe(epoch);
|
|
172
|
+
if (this.capabilityRefreshIntervalMs > 0) this.scheduleCapabilityRefresh(epoch);
|
|
173
|
+
}
|
|
181
174
|
}
|
|
182
175
|
}
|
|
183
176
|
/** Stop all background activity. Preserves in-memory state and version tokens. */
|
|
@@ -187,7 +180,8 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
187
180
|
if (this.capabilityTimer) clearTimeout(this.capabilityTimer);
|
|
188
181
|
this.probeTimer = null;
|
|
189
182
|
this.capabilityTimer = null;
|
|
190
|
-
if (this._state === "syncing" || this._state === "bootstrapping"
|
|
183
|
+
if (this._state === "syncing" || this._state === "bootstrapping" || this._state === "degraded")
|
|
184
|
+
this.setState("idle");
|
|
191
185
|
}
|
|
192
186
|
/**
|
|
193
187
|
* Stop, clear all indexes and version tokens. Call `start()` again to
|
|
@@ -195,6 +189,7 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
195
189
|
*/
|
|
196
190
|
async reset() {
|
|
197
191
|
this.stop();
|
|
192
|
+
++this.mirrorRevision;
|
|
198
193
|
this.productIndex.clear();
|
|
199
194
|
this.signalIndex.clear();
|
|
200
195
|
this.productWholesaleFeedVersion = void 0;
|
|
@@ -220,7 +215,7 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
220
215
|
async refresh() {
|
|
221
216
|
const epoch = this.lifecycleEpoch;
|
|
222
217
|
this.emit("resyncing", { reason: "manual" });
|
|
223
|
-
await this.
|
|
218
|
+
await this.bootstrapWithRetries({ emitDiffs: true, epoch, propagateFailure: true });
|
|
224
219
|
}
|
|
225
220
|
/**
|
|
226
221
|
* Apply one legacy-view account-level wholesale feed webhook to the local mirror.
|
|
@@ -269,6 +264,11 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
269
264
|
this.rememberLastWebhookEventId(event.event_id);
|
|
270
265
|
throw err;
|
|
271
266
|
}
|
|
267
|
+
if (!this._lastSyncedAt && event.event_type !== "wholesale_feed.bulk_change") {
|
|
268
|
+
if (!await this.recoverFromVersionMismatch(event, epoch)) return;
|
|
269
|
+
await this.markWebhookProcessed(dedupeKey, eventDedupeKey);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
272
|
if (webhook.previous_wholesale_feed_version && currentVersion && webhook.previous_wholesale_feed_version !== currentVersion) {
|
|
273
273
|
if (!await this.recoverFromVersionMismatch(event, epoch)) return;
|
|
274
274
|
await this.markWebhookProcessed(dedupeKey, eventDedupeKey);
|
|
@@ -279,8 +279,10 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
279
279
|
try {
|
|
280
280
|
if (!await this.recoverFromBulkChange(event, epoch)) return;
|
|
281
281
|
} catch (err) {
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
if (!(err instanceof Error && bootstrapReadFailures.has(err))) {
|
|
283
|
+
await this.markWebhookProcessed(dedupeKey, eventDedupeKey);
|
|
284
|
+
this.rememberLastWebhookEventId(event.event_id);
|
|
285
|
+
}
|
|
284
286
|
throw err;
|
|
285
287
|
}
|
|
286
288
|
await this.markWebhookProcessed(dedupeKey, eventDedupeKey);
|
|
@@ -347,10 +349,24 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
347
349
|
return true;
|
|
348
350
|
}
|
|
349
351
|
// ====== Private: bootstrap (wholesale enumeration) ======
|
|
352
|
+
async bootstrapWithRetries(options) {
|
|
353
|
+
for (let attempt = 0; attempt < VERSION_MISMATCH_RECOVERY_ATTEMPTS; attempt++) {
|
|
354
|
+
const revision = this.mirrorRevision;
|
|
355
|
+
if (await this.bootstrap({ ...options, conditional: attempt === 0 ? void 0 : false })) return;
|
|
356
|
+
if (!this.isLifecycleCurrent(options.epoch) || revision === this.mirrorRevision) return;
|
|
357
|
+
}
|
|
358
|
+
const error = new Error("WholesaleFeedSync: refresh superseded repeatedly; retry start or refresh.");
|
|
359
|
+
this.handleBootstrapFailure({ error });
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
350
362
|
async bootstrap(options = {}) {
|
|
351
363
|
const epoch = options.epoch ?? this.lifecycleEpoch;
|
|
352
364
|
if (!this.isLifecycleCurrent(epoch)) return false;
|
|
353
365
|
this.setState("bootstrapping");
|
|
366
|
+
const previousLastSyncedAt = this._lastSyncedAt;
|
|
367
|
+
const expectedRevision = this.mirrorRevision;
|
|
368
|
+
let reportedFailure;
|
|
369
|
+
let committed = false;
|
|
354
370
|
try {
|
|
355
371
|
const previousProducts = new Map(this.productIndex);
|
|
356
372
|
const previousSignals = new Map(this.signalIndex);
|
|
@@ -362,14 +378,50 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
362
378
|
const refreshProducts = entities !== "signals";
|
|
363
379
|
const refreshSignals = entities !== "products" && this.signals.queryable;
|
|
364
380
|
if (refreshProducts) {
|
|
365
|
-
productResult = await this.bootstrapProducts(epoch);
|
|
381
|
+
productResult = await this.bootstrapProducts(epoch, options.conditional);
|
|
366
382
|
if (productResult.cancelled) return false;
|
|
383
|
+
if (this.mirrorRevision !== expectedRevision) {
|
|
384
|
+
this.setState(this._lastSyncedAt ? "syncing" : "idle");
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if (productResult.failure) {
|
|
388
|
+
const failure = productResult.failure;
|
|
389
|
+
reportedFailure = failure.error;
|
|
390
|
+
this.handleBootstrapFailure(failure);
|
|
391
|
+
if (options.propagateFailure) {
|
|
392
|
+
bootstrapReadFailures.add(failure.error);
|
|
393
|
+
if (failure.adcpError) Object.assign(failure.error, { adcpError: failure.adcpError });
|
|
394
|
+
throw failure.error;
|
|
395
|
+
}
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
367
398
|
}
|
|
368
399
|
if (refreshSignals) {
|
|
369
|
-
signalResult = await this.bootstrapSignals(epoch);
|
|
400
|
+
signalResult = await this.bootstrapSignals(epoch, options.conditional);
|
|
370
401
|
if (signalResult.cancelled) return false;
|
|
402
|
+
if (this.mirrorRevision !== expectedRevision) {
|
|
403
|
+
this.setState(this._lastSyncedAt ? "syncing" : "idle");
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
if (signalResult.failure) {
|
|
407
|
+
const failure = signalResult.failure;
|
|
408
|
+
reportedFailure = failure.error;
|
|
409
|
+
this.handleBootstrapFailure(failure);
|
|
410
|
+
if (options.propagateFailure) {
|
|
411
|
+
bootstrapReadFailures.add(failure.error);
|
|
412
|
+
if (failure.adcpError) Object.assign(failure.error, { adcpError: failure.adcpError });
|
|
413
|
+
throw failure.error;
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
371
417
|
}
|
|
372
418
|
if (!this.isLifecycleCurrent(epoch)) return false;
|
|
419
|
+
if (this.mirrorRevision !== expectedRevision) {
|
|
420
|
+
this.setState(this._lastSyncedAt ? "syncing" : "idle");
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
++this.mirrorRevision;
|
|
424
|
+
committed = true;
|
|
373
425
|
if (refreshProducts && productResult) {
|
|
374
426
|
this.commitProductMetadata(productResult.metadata);
|
|
375
427
|
if (!productResult.unchanged) {
|
|
@@ -401,77 +453,91 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
401
453
|
return true;
|
|
402
454
|
} catch (err) {
|
|
403
455
|
if (!this.isLifecycleCurrent(epoch)) return false;
|
|
404
|
-
this.
|
|
456
|
+
if (!committed && this.mirrorRevision !== expectedRevision && err !== reportedFailure) return false;
|
|
457
|
+
if (err === reportedFailure) throw err;
|
|
458
|
+
this._lastSyncedAt = previousLastSyncedAt;
|
|
459
|
+
this.setState(this._lastSyncedAt ? "degraded" : "error");
|
|
405
460
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
406
461
|
this.errorHandler?.(error);
|
|
407
|
-
this.emit("error", { error });
|
|
462
|
+
if (this.listenerCount("error") > 0) this.emit("error", { error });
|
|
463
|
+
if (options.propagateFailure) bootstrapReadFailures.add(error);
|
|
408
464
|
throw error;
|
|
409
465
|
}
|
|
410
466
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
do {
|
|
417
|
-
const params = {
|
|
418
|
-
buying_mode: "wholesale",
|
|
419
|
-
pagination: { max_results: DEFAULT_BOOTSTRAP_PAGE_LIMIT, ...cursor && { cursor } },
|
|
420
|
-
...this.account && { account: this.account }
|
|
421
|
-
};
|
|
422
|
-
if (!cursor && metadata.wholesaleFeedVersion && this._capabilities.wholesaleFeedVersioning) {
|
|
423
|
-
params.if_wholesale_feed_version = metadata.wholesaleFeedVersion;
|
|
424
|
-
if (metadata.pricingVersion) params.if_pricing_version = metadata.pricingVersion;
|
|
425
|
-
}
|
|
426
|
-
const result = await this.client.getProducts(params);
|
|
427
|
-
if (!this.isLifecycleCurrent(epoch)) return { cancelled: true, unchanged: false, items: into, metadata };
|
|
428
|
-
const body = result.data;
|
|
429
|
-
if (!body) return { cancelled: false, unchanged: false, items: into, metadata };
|
|
430
|
-
if (body.unchanged) {
|
|
431
|
-
metadata = mergeFeedMetadata(metadata, body);
|
|
432
|
-
return { cancelled: false, unchanged: true, items: into, metadata };
|
|
433
|
-
}
|
|
434
|
-
const products = Array.isArray(body.products) ? body.products : [];
|
|
435
|
-
for (const product of products) {
|
|
436
|
-
const id = product.product_id;
|
|
437
|
-
if (typeof id === "string") into.set(id, product);
|
|
438
|
-
}
|
|
439
|
-
metadata = mergeFeedMetadata(metadata, body);
|
|
440
|
-
cursor = body.pagination?.has_more ? body.pagination?.cursor : void 0;
|
|
441
|
-
} while (cursor);
|
|
442
|
-
return { cancelled: false, unchanged: false, items: into, metadata };
|
|
467
|
+
handleBootstrapFailure(failure) {
|
|
468
|
+
this.setState(this._lastSyncedAt ? "degraded" : "error");
|
|
469
|
+
this.errorHandler?.(failure.error);
|
|
470
|
+
if (this.listenerCount("error") > 0) this.emit("error", failure);
|
|
471
|
+
return false;
|
|
443
472
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
metadata = mergeFeedMetadata(metadata, body);
|
|
464
|
-
return { cancelled: false, unchanged: true, items: into, metadata };
|
|
473
|
+
bootstrapProducts(epoch, conditional) {
|
|
474
|
+
return this.bootstrapFeed("product", epoch, conditional);
|
|
475
|
+
}
|
|
476
|
+
bootstrapSignals(epoch, conditional) {
|
|
477
|
+
return this.bootstrapFeed("signal", epoch, conditional);
|
|
478
|
+
}
|
|
479
|
+
async bootstrapFeed(entity, epoch, conditional) {
|
|
480
|
+
const store = new import_mirror.InMemoryWholesaleFeedMirrorStore();
|
|
481
|
+
const scope = { agentUrl: "shell", accountKey: "shell", entity };
|
|
482
|
+
const metadata = entity === "product" ? this.currentProductMetadata() : this.currentSignalMetadata();
|
|
483
|
+
const previous = entity === "product" ? [...this.productIndex.values()] : [...this.signalIndex.values()];
|
|
484
|
+
store.restore(scope, { revision: 0, items: previous, ...metadata });
|
|
485
|
+
let readException;
|
|
486
|
+
const read = async (call) => {
|
|
487
|
+
try {
|
|
488
|
+
return await call();
|
|
489
|
+
} catch (cause) {
|
|
490
|
+
readException = cause instanceof Error ? cause : new Error(String(cause));
|
|
491
|
+
throw cause;
|
|
465
492
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
493
|
+
};
|
|
494
|
+
const outcome = await (0, import_mirror.refreshWholesaleFeed)({
|
|
495
|
+
client: {
|
|
496
|
+
getAdcpCapabilities: this.client.getAdcpCapabilities.bind(this.client),
|
|
497
|
+
getProducts: (params) => read(() => this.client.getProducts(params)),
|
|
498
|
+
getSignals: (params) => read(() => this.client.getSignals(params))
|
|
499
|
+
},
|
|
500
|
+
store,
|
|
501
|
+
scope,
|
|
502
|
+
account: this.account,
|
|
503
|
+
conditional: conditional ?? this._capabilities.wholesaleFeedVersioning,
|
|
504
|
+
isCurrent: () => this.isLifecycleCurrent(epoch)
|
|
505
|
+
});
|
|
506
|
+
if (outcome.outcome === "superseded") return { cancelled: true, unchanged: false, items: /* @__PURE__ */ new Map(), metadata };
|
|
507
|
+
if (outcome.outcome === "degraded") {
|
|
508
|
+
if (readException) throw readException;
|
|
509
|
+
return {
|
|
510
|
+
cancelled: false,
|
|
511
|
+
unchanged: false,
|
|
512
|
+
items: /* @__PURE__ */ new Map(),
|
|
513
|
+
metadata,
|
|
514
|
+
failure: {
|
|
515
|
+
error: new Error(
|
|
516
|
+
`${entity === "product" ? "Product" : "Signal"} bootstrap failed: ${outcome.cause.message}`,
|
|
517
|
+
{
|
|
518
|
+
cause: outcome.cause
|
|
519
|
+
}
|
|
520
|
+
),
|
|
521
|
+
adcpError: outcome.error
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const snapshot = outcome.snapshot;
|
|
526
|
+
return {
|
|
527
|
+
cancelled: false,
|
|
528
|
+
unchanged: outcome.outcome === "unchanged",
|
|
529
|
+
items: new Map(
|
|
530
|
+
snapshot.items.map((item) => [
|
|
531
|
+
entity === "product" ? item.product_id : item.signal_agent_segment_id,
|
|
532
|
+
item
|
|
533
|
+
])
|
|
534
|
+
),
|
|
535
|
+
metadata: {
|
|
536
|
+
wholesaleFeedVersion: snapshot.wholesaleFeedVersion,
|
|
537
|
+
pricingVersion: snapshot.pricingVersion,
|
|
538
|
+
cacheScope: snapshot.cacheScope
|
|
470
539
|
}
|
|
471
|
-
|
|
472
|
-
cursor = body.pagination?.has_more ? body.pagination?.cursor : void 0;
|
|
473
|
-
} while (cursor);
|
|
474
|
-
return { cancelled: false, unchanged: false, items: into, metadata };
|
|
540
|
+
};
|
|
475
541
|
}
|
|
476
542
|
async recoverFromBulkChange(event, epoch = this.lifecycleEpoch) {
|
|
477
543
|
this.emit("resyncing", { reason: "bulk_change" });
|
|
@@ -482,14 +548,22 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
482
548
|
);
|
|
483
549
|
}
|
|
484
550
|
const entities = affected === "product" ? "products" : "signals";
|
|
485
|
-
|
|
551
|
+
for (let attempt = 0; attempt < VERSION_MISMATCH_RECOVERY_ATTEMPTS; attempt++) {
|
|
552
|
+
if (await this.bootstrap({ emitDiffs: true, entities, epoch, propagateFailure: true })) return true;
|
|
553
|
+
if (!this.isLifecycleCurrent(epoch)) return false;
|
|
554
|
+
}
|
|
555
|
+
throw supersededRepairError();
|
|
486
556
|
}
|
|
487
557
|
async recoverFromVersionMismatch(event, epoch = this.lifecycleEpoch) {
|
|
488
558
|
this.emit("resyncing", { reason: "version_mismatch" });
|
|
489
559
|
const beforeVersion = this.currentWholesaleFeedVersionForEvent(event);
|
|
490
560
|
for (let attempt = 1; attempt <= VERSION_MISMATCH_RECOVERY_ATTEMPTS; attempt++) {
|
|
491
|
-
const recovered = await this.bootstrap({ emitDiffs: true, epoch });
|
|
492
|
-
if (!recovered)
|
|
561
|
+
const recovered = await this.bootstrap({ emitDiffs: true, epoch, propagateFailure: true });
|
|
562
|
+
if (!recovered) {
|
|
563
|
+
if (!this.isLifecycleCurrent(epoch)) return false;
|
|
564
|
+
if (attempt === VERSION_MISMATCH_RECOVERY_ATTEMPTS) throw supersededRepairError();
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
493
567
|
const afterVersion = this.currentWholesaleFeedVersionForEvent(event);
|
|
494
568
|
if (afterVersion !== beforeVersion) return true;
|
|
495
569
|
if (attempt < VERSION_MISMATCH_RECOVERY_ATTEMPTS) {
|
|
@@ -510,11 +584,12 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
510
584
|
await this.probeVersion(epoch);
|
|
511
585
|
} catch (err) {
|
|
512
586
|
if (!this.isLifecycleCurrent(epoch)) return;
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
587
|
+
if (this._state !== "degraded" && this._state !== "error") {
|
|
588
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
589
|
+
this.handleBootstrapFailure({ error });
|
|
590
|
+
}
|
|
516
591
|
}
|
|
517
|
-
if (this.isLifecycleCurrent(epoch) && this._state === "syncing" && this._mode === "auto-poll") {
|
|
592
|
+
if (this.isLifecycleCurrent(epoch) && (this._state === "syncing" || this._state === "degraded" || this._state === "error") && this._mode === "auto-poll") {
|
|
518
593
|
this.scheduleProbe(epoch);
|
|
519
594
|
}
|
|
520
595
|
}
|
|
@@ -541,7 +616,7 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
541
616
|
this.emit("error", { error });
|
|
542
617
|
this.errorHandler?.(error);
|
|
543
618
|
}
|
|
544
|
-
if (this.isLifecycleCurrent(epoch) && this._state === "syncing" && this.capabilityRefreshIntervalMs > 0) {
|
|
619
|
+
if (this.isLifecycleCurrent(epoch) && (this._state === "syncing" || this._state === "degraded" || this._state === "error") && this.capabilityRefreshIntervalMs > 0) {
|
|
545
620
|
this.scheduleCapabilityRefresh(epoch);
|
|
546
621
|
}
|
|
547
622
|
}
|
|
@@ -642,63 +717,16 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
642
717
|
}
|
|
643
718
|
}
|
|
644
719
|
applyEvent(event) {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
case "product.priced": {
|
|
657
|
-
const payload = event.payload;
|
|
658
|
-
const existing = this.productIndex.get(payload.product_id);
|
|
659
|
-
if (existing && Array.isArray(payload.pricing_options)) {
|
|
660
|
-
this.productIndex.set(payload.product_id, {
|
|
661
|
-
...existing,
|
|
662
|
-
pricing_options: payload.pricing_options
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
case "product.removed": {
|
|
668
|
-
const payload = event.payload;
|
|
669
|
-
if (typeof payload.product_id === "string") this.productIndex.delete(payload.product_id);
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
case "signal.created":
|
|
673
|
-
case "signal.updated": {
|
|
674
|
-
const payload = event.payload;
|
|
675
|
-
if (typeof payload.signal_agent_segment_id !== "string") return;
|
|
676
|
-
if (payload.signal) {
|
|
677
|
-
this.signalIndex.set(payload.signal_agent_segment_id, payload.signal);
|
|
678
|
-
}
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
case "signal.priced": {
|
|
682
|
-
const payload = event.payload;
|
|
683
|
-
const existing = this.signalIndex.get(payload.signal_agent_segment_id);
|
|
684
|
-
if (existing && Array.isArray(payload.pricing_options)) {
|
|
685
|
-
this.signalIndex.set(payload.signal_agent_segment_id, {
|
|
686
|
-
...existing,
|
|
687
|
-
pricing_options: payload.pricing_options
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
case "signal.removed": {
|
|
693
|
-
const payload = event.payload;
|
|
694
|
-
if (typeof payload.signal_agent_segment_id === "string") {
|
|
695
|
-
this.signalIndex.delete(payload.signal_agent_segment_id);
|
|
696
|
-
}
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
case "wholesale_feed.bulk_change":
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
720
|
+
++this.mirrorRevision;
|
|
721
|
+
const entity = event.event_type.startsWith("product.") ? "product" : "signal";
|
|
722
|
+
const items = (0, import_mirror.applyWholesaleFeedEvent)(
|
|
723
|
+
entity,
|
|
724
|
+
entity === "product" ? [...this.productIndex.values()] : [...this.signalIndex.values()],
|
|
725
|
+
event
|
|
726
|
+
);
|
|
727
|
+
if (!items) return;
|
|
728
|
+
if (entity === "product") this.productIndex = new Map(items.map((item) => [item.product_id, item]));
|
|
729
|
+
else this.signalIndex = new Map(items.map((item) => [item.signal_agent_segment_id, item]));
|
|
702
730
|
}
|
|
703
731
|
emitTypedEvent(event) {
|
|
704
732
|
switch (event.event_type) {
|
|
@@ -732,107 +760,23 @@ class WholesaleFeedSync extends import_node_events.EventEmitter {
|
|
|
732
760
|
}
|
|
733
761
|
// ====== Private: diff emission (auto-poll / manual refresh) ======
|
|
734
762
|
emitDiffs(previousProducts, previousSignals) {
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const
|
|
763
|
+
const events = [
|
|
764
|
+
...(0, import_mirror.diffWholesaleFeed)(
|
|
765
|
+
"product",
|
|
766
|
+
[...previousProducts.values()],
|
|
767
|
+
[...this.productIndex.values()],
|
|
768
|
+
this.productCacheScope
|
|
769
|
+
),
|
|
770
|
+
...(0, import_mirror.diffWholesaleFeed)(
|
|
771
|
+
"signal",
|
|
772
|
+
[...previousSignals.values()],
|
|
773
|
+
[...this.signalIndex.values()],
|
|
774
|
+
this.signalCacheScope
|
|
775
|
+
)
|
|
776
|
+
];
|
|
777
|
+
for (const event of events) {
|
|
750
778
|
this.emit("event", { event, synthetic: true });
|
|
751
|
-
this.emit(
|
|
752
|
-
};
|
|
753
|
-
for (const [id, product] of this.productIndex) {
|
|
754
|
-
const prev = previousProducts.get(id);
|
|
755
|
-
if (!prev) {
|
|
756
|
-
emit(
|
|
757
|
-
"product.created",
|
|
758
|
-
makeEvent("product.created", "product", id, {
|
|
759
|
-
product_id: id,
|
|
760
|
-
product,
|
|
761
|
-
applies_to: { scope: this.productCacheScope }
|
|
762
|
-
})
|
|
763
|
-
);
|
|
764
|
-
} else if (priceChanged(prev, product)) {
|
|
765
|
-
emit(
|
|
766
|
-
"product.priced",
|
|
767
|
-
makeEvent("product.priced", "product", id, {
|
|
768
|
-
product_id: id,
|
|
769
|
-
pricing_options: product.pricing_options ?? [],
|
|
770
|
-
applies_to: { scope: this.productCacheScope }
|
|
771
|
-
})
|
|
772
|
-
);
|
|
773
|
-
} else if (!(0, import_node_util.isDeepStrictEqual)(prev, product)) {
|
|
774
|
-
emit(
|
|
775
|
-
"product.updated",
|
|
776
|
-
makeEvent("product.updated", "product", id, {
|
|
777
|
-
product_id: id,
|
|
778
|
-
product,
|
|
779
|
-
applies_to: { scope: this.productCacheScope }
|
|
780
|
-
})
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
for (const [id] of previousProducts) {
|
|
785
|
-
if (!this.productIndex.has(id)) {
|
|
786
|
-
emit(
|
|
787
|
-
"product.removed",
|
|
788
|
-
makeEvent("product.removed", "product", id, {
|
|
789
|
-
product_id: id,
|
|
790
|
-
applies_to: { scope: this.productCacheScope }
|
|
791
|
-
})
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
for (const [id, signal] of this.signalIndex) {
|
|
796
|
-
const prev = previousSignals.get(id);
|
|
797
|
-
if (!prev) {
|
|
798
|
-
emit(
|
|
799
|
-
"signal.created",
|
|
800
|
-
makeEvent("signal.created", "signal", id, {
|
|
801
|
-
signal_agent_segment_id: id,
|
|
802
|
-
signal,
|
|
803
|
-
applies_to: { scope: this.signalCacheScope }
|
|
804
|
-
})
|
|
805
|
-
);
|
|
806
|
-
} else if (signalPriceChanged(prev, signal)) {
|
|
807
|
-
emit(
|
|
808
|
-
"signal.priced",
|
|
809
|
-
makeEvent("signal.priced", "signal", id, {
|
|
810
|
-
signal_agent_segment_id: id,
|
|
811
|
-
pricing_options: signal.pricing_options ?? [],
|
|
812
|
-
applies_to: { scope: this.signalCacheScope }
|
|
813
|
-
})
|
|
814
|
-
);
|
|
815
|
-
} else if (!(0, import_node_util.isDeepStrictEqual)(prev, signal)) {
|
|
816
|
-
emit(
|
|
817
|
-
"signal.updated",
|
|
818
|
-
makeEvent("signal.updated", "signal", id, {
|
|
819
|
-
signal_agent_segment_id: id,
|
|
820
|
-
signal,
|
|
821
|
-
applies_to: { scope: this.signalCacheScope }
|
|
822
|
-
})
|
|
823
|
-
);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
for (const [id] of previousSignals) {
|
|
827
|
-
if (!this.signalIndex.has(id)) {
|
|
828
|
-
emit(
|
|
829
|
-
"signal.removed",
|
|
830
|
-
makeEvent("signal.removed", "signal", id, {
|
|
831
|
-
signal_agent_segment_id: id,
|
|
832
|
-
applies_to: { scope: this.signalCacheScope }
|
|
833
|
-
})
|
|
834
|
-
);
|
|
835
|
-
}
|
|
779
|
+
this.emit(event.event_type, { event, synthetic: true });
|
|
836
780
|
}
|
|
837
781
|
}
|
|
838
782
|
// ====== Private: search ======
|
|
@@ -1009,16 +953,6 @@ function assertOptionalDate(value, field, invalid) {
|
|
|
1009
953
|
function parsePersistedDate(value) {
|
|
1010
954
|
return value === void 0 ? void 0 : new Date(value);
|
|
1011
955
|
}
|
|
1012
|
-
function priceChanged(prev, next) {
|
|
1013
|
-
const a = prev.pricing_options;
|
|
1014
|
-
const b = next.pricing_options;
|
|
1015
|
-
return !(0, import_node_util.isDeepStrictEqual)(a, b);
|
|
1016
|
-
}
|
|
1017
|
-
function signalPriceChanged(prev, next) {
|
|
1018
|
-
const a = prev.pricing_options;
|
|
1019
|
-
const b = next.pricing_options;
|
|
1020
|
-
return !(0, import_node_util.isDeepStrictEqual)(a, b);
|
|
1021
|
-
}
|
|
1022
956
|
function isUuidV7(value) {
|
|
1023
957
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
1024
958
|
}
|
|
@@ -1028,13 +962,6 @@ function compareUuidV7(a, b) {
|
|
|
1028
962
|
const normalizedB = b.toLowerCase();
|
|
1029
963
|
return normalizedA === normalizedB ? 0 : normalizedA > normalizedB ? 1 : -1;
|
|
1030
964
|
}
|
|
1031
|
-
function mergeFeedMetadata(current, body) {
|
|
1032
|
-
return {
|
|
1033
|
-
wholesaleFeedVersion: typeof body.wholesale_feed_version === "string" ? body.wholesale_feed_version : current.wholesaleFeedVersion,
|
|
1034
|
-
pricingVersion: typeof body.pricing_version === "string" ? body.pricing_version : current.pricingVersion,
|
|
1035
|
-
cacheScope: body.cache_scope === "public" || body.cache_scope === "account" ? body.cache_scope : current.cacheScope
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
965
|
async function sleep(ms) {
|
|
1039
966
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1040
967
|
}
|