@cimplify/sdk 0.104.0 → 0.104.1

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 (71) hide show
  1. package/dist/advanced.d.mts +3 -7
  2. package/dist/advanced.d.ts +3 -7
  3. package/dist/advanced.js +23 -23
  4. package/dist/advanced.mjs +4 -4
  5. package/dist/{client-BuLcOWLv.d.ts → catalogue-BlQ85Uma.d.mts} +415 -763
  6. package/dist/{client-D5AoobFc.d.mts → catalogue-C8TqOj9K.d.ts} +415 -763
  7. package/dist/{payment-g0HFkEDU.d.mts → checkout-BqK9XUz5.d.mts} +3824 -1446
  8. package/dist/{payment-g0HFkEDU.d.ts → checkout-BqK9XUz5.d.ts} +3824 -1446
  9. package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
  10. package/dist/{chunk-2WPVUIHX.mjs → chunk-6G3ANKQA.mjs} +1030 -360
  11. package/dist/{chunk-E4K2VQDD.js → chunk-BWEIMKLF.js} +541 -16
  12. package/dist/{chunk-IQFFSKE2.js → chunk-DQEXY542.js} +1345 -746
  13. package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
  14. package/dist/{chunk-YVAEY3VC.js → chunk-HYFA67A7.js} +1034 -364
  15. package/dist/{chunk-5RT4HYMP.mjs → chunk-L5SNEU2O.mjs} +524 -15
  16. package/dist/{chunk-4BKOKHE3.js → chunk-RBNBSQI7.mjs} +217 -19
  17. package/dist/{chunk-H3RATH4B.mjs → chunk-SFUJMS5E.js} +261 -2
  18. package/dist/{chunk-DYIAX3WI.mjs → chunk-U54CWUUT.mjs} +11 -2
  19. package/dist/{chunk-OKADBZAI.mjs → chunk-UFOWPN3D.mjs} +808 -574
  20. package/dist/{chunk-OCCNG6MO.mjs → chunk-V4457OKB.mjs} +1310 -722
  21. package/dist/{chunk-5BDYDZ4U.js → chunk-WXREIBFW.js} +892 -657
  22. package/dist/{chunk-7PDEX54K.js → chunk-XAUSDMMZ.js} +13 -3
  23. package/dist/{client-BVNWjk6W.d.ts → client-DhXeiUrf.d.ts} +2 -2
  24. package/dist/{client-fM716k7G.d.mts → client-mXiUrV4X.d.mts} +2 -2
  25. package/dist/{index-BtcoqrY1.d.ts → index-B0AdZvrM.d.mts} +9 -4
  26. package/dist/{index-D7Tf3v7c.d.mts → index-CK8Nk5uQ.d.ts} +9 -4
  27. package/dist/index-DPWI5XcU.d.ts +8 -0
  28. package/dist/index-DVfUh-ci.d.mts +8 -0
  29. package/dist/index.d.mts +31 -14
  30. package/dist/index.d.ts +31 -14
  31. package/dist/index.js +305 -133
  32. package/dist/index.mjs +6 -6
  33. package/dist/mock/cli.mjs +1442 -386
  34. package/dist/mock/library.js +1168 -352
  35. package/dist/mock/library.mjs +1168 -352
  36. package/dist/mock/msw.js +1168 -352
  37. package/dist/mock/msw.mjs +1168 -352
  38. package/dist/{price-BLIeAb8K.d.ts → price-6hQIIac9.d.ts} +1 -1
  39. package/dist/{price-Czq_cTC_.d.mts → price-BUDv1rI7.d.mts} +1 -1
  40. package/dist/react.d.mts +10 -5
  41. package/dist/react.d.ts +10 -5
  42. package/dist/react.js +227 -197
  43. package/dist/react.mjs +90 -60
  44. package/dist/{server-DKK_D-PP.d.ts → server-DJ0mSs9i.d.mts} +31 -57
  45. package/dist/{server-BkVhOIwn.d.mts → server-DSTX76Ki.d.ts} +31 -57
  46. package/dist/server.d.mts +3 -4
  47. package/dist/server.d.ts +3 -4
  48. package/dist/server.js +11 -11
  49. package/dist/server.mjs +5 -5
  50. package/dist/styles.css +2 -2
  51. package/dist/testing/msw.d.mts +2 -2
  52. package/dist/testing/msw.d.ts +2 -2
  53. package/dist/testing/msw.js +4 -4
  54. package/dist/testing/msw.mjs +3 -3
  55. package/dist/testing/suite.d.mts +5 -6
  56. package/dist/testing/suite.d.ts +5 -6
  57. package/dist/testing/suite.js +29 -28
  58. package/dist/testing/suite.mjs +10 -9
  59. package/dist/testing.d.mts +2177 -14
  60. package/dist/testing.d.ts +2177 -14
  61. package/dist/testing.js +167 -89
  62. package/dist/testing.mjs +24 -10
  63. package/dist/utils.d.mts +3 -4
  64. package/dist/utils.d.ts +3 -4
  65. package/dist/utils.js +35 -31
  66. package/dist/utils.mjs +2 -2
  67. package/package.json +9 -9
  68. package/registry/order-history.json +1 -1
  69. package/registry/order-summary.json +1 -1
  70. package/dist/link-D9iSVxt5.d.mts +0 -308
  71. package/dist/link-D9iSVxt5.d.ts +0 -308
@@ -1,8 +1,335 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkXREIZ56K_js = require('./chunk-XREIZ56K.js');
4
- var chunkIQFFSKE2_js = require('./chunk-IQFFSKE2.js');
5
- var chunk4BKOKHE3_js = require('./chunk-4BKOKHE3.js');
4
+ var chunkDQEXY542_js = require('./chunk-DQEXY542.js');
5
+ var chunkSFUJMS5E_js = require('./chunk-SFUJMS5E.js');
6
+
7
+ // src/types/observability.ts
8
+ var SESSION_CHANGE_SOURCE = {
9
+ RESPONSE: "response",
10
+ MANUAL: "manual",
11
+ CLEAR: "clear"
12
+ };
13
+
14
+ // src/utils/purchase-intent-resolver.ts
15
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
16
+ var DEFAULT_MAX_POLL_ATTEMPTS = 60;
17
+ var DEFAULT_MAX_ACTION_STEPS = 4;
18
+ var DEFAULT_MAX_TERMS_REVIEW_STEPS = 4;
19
+ function nonnegativeInteger(value, fallback) {
20
+ if (value === void 0 || !Number.isFinite(value)) return fallback;
21
+ return Math.max(0, Math.floor(value));
22
+ }
23
+ function abortError() {
24
+ const error = new Error("Purchase-intent resolution was cancelled.");
25
+ error.name = "AbortError";
26
+ return error;
27
+ }
28
+ async function abortableWait(milliseconds, signal) {
29
+ if (signal?.aborted) throw abortError();
30
+ if (milliseconds <= 0) return;
31
+ await new Promise((resolve, reject) => {
32
+ const timer = setTimeout(() => {
33
+ signal?.removeEventListener("abort", onAbort);
34
+ resolve();
35
+ }, milliseconds);
36
+ const onAbort = () => {
37
+ clearTimeout(timer);
38
+ reject(abortError());
39
+ };
40
+ signal?.addEventListener("abort", onAbort, { once: true });
41
+ });
42
+ }
43
+ var PurchaseIntentResolver = class {
44
+ constructor(dependencies) {
45
+ this.confirmation = dependencies.confirmation;
46
+ this.wait = dependencies.wait ?? abortableWait;
47
+ }
48
+ async resolve(intentId, options) {
49
+ const pollIntervalMs = nonnegativeInteger(
50
+ options.pollIntervalMs,
51
+ DEFAULT_POLL_INTERVAL_MS
52
+ );
53
+ const maxPollAttempts = nonnegativeInteger(
54
+ options.maxPollAttempts,
55
+ DEFAULT_MAX_POLL_ATTEMPTS
56
+ );
57
+ const maxActionSteps = nonnegativeInteger(options.maxActionSteps, DEFAULT_MAX_ACTION_STEPS);
58
+ const maxTermsReviewSteps = nonnegativeInteger(
59
+ options.maxTermsReviewSteps,
60
+ DEFAULT_MAX_TERMS_REVIEW_STEPS
61
+ );
62
+ let request = options.confirmation;
63
+ let pollAttempts = 0;
64
+ let actionSteps = 0;
65
+ let termsReviewSteps = 0;
66
+ this.ensureActive(options.signal);
67
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.CONFIRMING);
68
+ let responseResult = options.initialResponse ? chunkDQEXY542_js.ok(options.initialResponse) : await this.confirmation.confirm(intentId, request, { signal: options.signal });
69
+ while (responseResult.ok) {
70
+ this.ensureActive(options.signal);
71
+ const response = responseResult.value;
72
+ switch (response.status) {
73
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED:
74
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.COMPLETED, response);
75
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.COMPLETED, response });
76
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED:
77
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.FAILED, response);
78
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.FAILED, response });
79
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_OUTCOME_UNKNOWN:
80
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.OUTCOME_UNKNOWN, response);
81
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.OUTCOME_UNKNOWN, response });
82
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.COLLECTION_PROCESSING:
83
+ if (pollAttempts >= maxPollAttempts) {
84
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.TIMED_OUT, response });
85
+ }
86
+ pollAttempts += 1;
87
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.POLLING, response);
88
+ await this.wait(pollIntervalMs, options.signal);
89
+ responseResult = await this.confirmation.confirm(intentId, request, {
90
+ signal: options.signal
91
+ });
92
+ continue;
93
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED:
94
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED:
95
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED: {
96
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.AWAITING_ACTION, response);
97
+ if (!options.onActionRequired || actionSteps >= maxActionSteps) {
98
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.ACTION_REQUIRED, response });
99
+ }
100
+ actionSteps += 1;
101
+ const decision = await options.onActionRequired(response);
102
+ if (decision === chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP) {
103
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.ACTION_REQUIRED, response });
104
+ }
105
+ if (typeof decision === "object" && decision.kind === chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.SUBMIT) {
106
+ if (!this.confirmation.submitAction) {
107
+ return chunkDQEXY542_js.err(
108
+ new chunkSFUJMS5E_js.CimplifyError(
109
+ chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.ACTION_UNSUPPORTED,
110
+ "This confirmation transport cannot submit purchase-intent actions.",
111
+ false
112
+ )
113
+ );
114
+ }
115
+ responseResult = await this.confirmation.submitAction(
116
+ intentId,
117
+ response.attempt_id,
118
+ decision.request,
119
+ { signal: options.signal }
120
+ );
121
+ continue;
122
+ }
123
+ if (decision !== chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.CONTINUE) {
124
+ return chunkDQEXY542_js.err(
125
+ new chunkSFUJMS5E_js.CimplifyError(
126
+ chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.ACTION_UNSUPPORTED,
127
+ "The action callback returned an unsupported decision.",
128
+ false
129
+ )
130
+ );
131
+ }
132
+ await this.wait(pollIntervalMs, options.signal);
133
+ responseResult = await this.confirmation.confirm(intentId, request, {
134
+ signal: options.signal
135
+ });
136
+ continue;
137
+ }
138
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED: {
139
+ this.notify(options, chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.REVIEWING_TERMS, response);
140
+ if (!options.onTermsChanged || termsReviewSteps >= maxTermsReviewSteps) {
141
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED, response });
142
+ }
143
+ termsReviewSteps += 1;
144
+ const replacementRequest = await options.onTermsChanged(response);
145
+ if (!replacementRequest) {
146
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED, response });
147
+ }
148
+ request = replacementRequest;
149
+ responseResult = await this.confirmation.confirm(intentId, request, {
150
+ signal: options.signal
151
+ });
152
+ continue;
153
+ }
154
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
155
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
156
+ case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
157
+ return chunkDQEXY542_js.ok({ kind: chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED, response });
158
+ }
159
+ }
160
+ return responseResult;
161
+ }
162
+ ensureActive(signal) {
163
+ if (signal?.aborted) throw abortError();
164
+ }
165
+ notify(options, status, response) {
166
+ try {
167
+ options.onStatusChange?.(status, response);
168
+ } catch {
169
+ }
170
+ }
171
+ };
172
+
173
+ // src/purchase-intent.ts
174
+ var PURCHASE_INTENT_ROUTE = {
175
+ DIRECT_COLLECTION: "/api/v1/purchase-intents",
176
+ HOSTED_SESSION_COLLECTION: "/v1/checkout/sessions",
177
+ PREPARE: "prepare",
178
+ REFRESH: "refresh",
179
+ CONFIRM: "confirm",
180
+ REPLAY: "replay",
181
+ ATTEMPTS: "attempts",
182
+ ACTIONS: "actions"
183
+ };
184
+ function directIntentPath(intentId) {
185
+ const normalized = intentId.trim();
186
+ if (!normalized) throw new TypeError("intentId must not be empty");
187
+ return `${PURCHASE_INTENT_ROUTE.DIRECT_COLLECTION}/${encodeURIComponent(normalized)}`;
188
+ }
189
+ function hostedSessionPath(sessionId) {
190
+ const normalized = sessionId.trim();
191
+ if (!normalized) throw new TypeError("sessionId must not be empty");
192
+ return `${PURCHASE_INTENT_ROUTE.HOSTED_SESSION_COLLECTION}/${encodeURIComponent(normalized)}`;
193
+ }
194
+ var PurchaseIntentService = class {
195
+ constructor(transport) {
196
+ this.transport = transport;
197
+ this.resolver = new PurchaseIntentResolver({ confirmation: this });
198
+ }
199
+ mint(request, options) {
200
+ return chunkDQEXY542_js.safe(
201
+ this.transport.post(PURCHASE_INTENT_ROUTE.DIRECT_COLLECTION, request, {
202
+ idempotencyKey: request.client_intent_key,
203
+ signal: options?.signal,
204
+ timeoutMs: options?.timeoutMs
205
+ })
206
+ );
207
+ }
208
+ get(intentId, options) {
209
+ return chunkDQEXY542_js.safe(
210
+ this.transport.get(this.intentPath(intentId), {
211
+ signal: options?.signal,
212
+ timeoutMs: options?.timeoutMs
213
+ })
214
+ );
215
+ }
216
+ refresh(intentId, expectedRevision, options) {
217
+ const request = {
218
+ expected_intent_revision: expectedRevision
219
+ };
220
+ return chunkDQEXY542_js.safe(
221
+ this.transport.post(
222
+ `${this.intentPath(intentId)}/${PURCHASE_INTENT_ROUTE.REFRESH}`,
223
+ request,
224
+ {
225
+ signal: options?.signal,
226
+ timeoutMs: options?.timeoutMs
227
+ }
228
+ )
229
+ );
230
+ }
231
+ confirm(intentId, request, options) {
232
+ return chunkDQEXY542_js.safe(
233
+ this.transport.post(
234
+ `${this.intentPath(intentId)}/${PURCHASE_INTENT_ROUTE.CONFIRM}`,
235
+ request,
236
+ {
237
+ idempotencyKey: request.idempotency_key,
238
+ signal: options?.signal,
239
+ timeoutMs: options?.timeoutMs
240
+ }
241
+ )
242
+ );
243
+ }
244
+ submitAction(intentId, attemptId, request, options) {
245
+ const normalizedAttemptId = attemptId.trim();
246
+ if (!normalizedAttemptId) throw new TypeError("attemptId must not be empty");
247
+ return chunkDQEXY542_js.safe(
248
+ this.transport.post(
249
+ `${this.intentPath(intentId)}/${PURCHASE_INTENT_ROUTE.ATTEMPTS}/${encodeURIComponent(normalizedAttemptId)}/${PURCHASE_INTENT_ROUTE.ACTIONS}`,
250
+ request,
251
+ {
252
+ signal: options?.signal,
253
+ timeoutMs: options?.timeoutMs
254
+ }
255
+ )
256
+ );
257
+ }
258
+ resolve(intentId, options) {
259
+ return this.resolver.resolve(intentId, options);
260
+ }
261
+ /**
262
+ * Bind subsequent preparation/confirmation to one hosted checkout-session
263
+ * owner. The session ID is a route authority, not an intent-owner rewrite.
264
+ */
265
+ forHostedSession(sessionId) {
266
+ return new HostedPurchaseIntentService(this.transport, sessionId);
267
+ }
268
+ intentPath(intentId) {
269
+ return directIntentPath(intentId);
270
+ }
271
+ };
272
+ var HostedPurchaseIntentService = class {
273
+ constructor(transport, sessionId) {
274
+ this.transport = transport;
275
+ this.sessionPath = hostedSessionPath(sessionId);
276
+ this.resolver = new PurchaseIntentResolver({ confirmation: this });
277
+ }
278
+ prepare(request, options) {
279
+ return chunkDQEXY542_js.safe(
280
+ this.transport.post(
281
+ `${this.sessionPath}/${PURCHASE_INTENT_ROUTE.PREPARE}`,
282
+ request,
283
+ {
284
+ idempotencyKey: request.idempotency_key,
285
+ signal: options?.signal,
286
+ timeoutMs: options?.timeoutMs
287
+ }
288
+ )
289
+ );
290
+ }
291
+ confirm(_intentId, request, options) {
292
+ return chunkDQEXY542_js.safe(
293
+ this.transport.post(
294
+ `${this.sessionPath}/${PURCHASE_INTENT_ROUTE.CONFIRM}`,
295
+ request,
296
+ {
297
+ idempotencyKey: request.idempotency_key,
298
+ signal: options?.signal,
299
+ timeoutMs: options?.timeoutMs
300
+ }
301
+ )
302
+ );
303
+ }
304
+ replay(options) {
305
+ return chunkDQEXY542_js.safe(
306
+ this.transport.get(
307
+ `${this.sessionPath}/${PURCHASE_INTENT_ROUTE.REPLAY}`,
308
+ {
309
+ signal: options?.signal,
310
+ timeoutMs: options?.timeoutMs
311
+ }
312
+ )
313
+ );
314
+ }
315
+ submitAction(_intentId, attemptId, request, options) {
316
+ const normalized = attemptId.trim();
317
+ if (!normalized) throw new TypeError("attemptId must not be empty");
318
+ return chunkDQEXY542_js.safe(
319
+ this.transport.post(
320
+ `${this.sessionPath}/${PURCHASE_INTENT_ROUTE.ATTEMPTS}/${encodeURIComponent(normalized)}/${PURCHASE_INTENT_ROUTE.ACTIONS}`,
321
+ request,
322
+ {
323
+ signal: options?.signal,
324
+ timeoutMs: options?.timeoutMs
325
+ }
326
+ )
327
+ );
328
+ }
329
+ resolve(intentId, options) {
330
+ return this.resolver.resolve(intentId, options);
331
+ }
332
+ };
6
333
 
7
334
  // src/store-credit.ts
8
335
  var StoreCreditQueries = class {
@@ -14,18 +341,19 @@ var StoreCreditQueries = class {
14
341
  * currency. Requires a signed-in customer; returns an error otherwise.
15
342
  */
16
343
  async balance() {
17
- return chunkIQFFSKE2_js.safe(this.client.get("/api/v1/store-credit/balance"));
344
+ return chunkDQEXY542_js.safe(this.client.get("/api/v1/store-credit/balance"));
18
345
  }
19
346
  };
20
347
 
21
348
  // src/internal/analytics-session.ts
22
349
  var ANALYTICS_SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
23
- var ANALYTICS_SESSION_STORAGE_KEY = "cimplify_analytics_session";
24
- var ANALYTICS_SESSION_STATE_VERSION = 1;
350
+ var ANALYTICS_SESSION_STORAGE_KEY_PREFIX = "cimplify_analytics_session:v2:";
351
+ var ANALYTICS_SESSION_STATE_VERSION = 2;
25
352
  var MICROSECONDS_PER_MILLISECOND = 1e3;
26
353
  var MICROSECONDS_PER_SECOND = 1e6;
27
354
  var AnalyticsSessionCoordinator = class {
28
- constructor() {
355
+ constructor(identity) {
356
+ this.identity = identity;
29
357
  this.fallbackState = null;
30
358
  }
31
359
  beginEvent(nowMs = Date.now()) {
@@ -63,7 +391,7 @@ var AnalyticsSessionCoordinator = class {
63
391
  reset() {
64
392
  this.fallbackState = null;
65
393
  try {
66
- sessionStorage.removeItem(ANALYTICS_SESSION_STORAGE_KEY);
394
+ sessionStorage.removeItem(this.storageKey());
67
395
  } catch {
68
396
  }
69
397
  }
@@ -73,11 +401,11 @@ var AnalyticsSessionCoordinator = class {
73
401
  }
74
402
  read() {
75
403
  try {
76
- const serialized = sessionStorage.getItem(ANALYTICS_SESSION_STORAGE_KEY);
404
+ const serialized = sessionStorage.getItem(this.storageKey());
77
405
  if (!serialized) return this.fallbackState;
78
406
  const state = JSON.parse(serialized);
79
407
  if (!isPersistedSession(state)) {
80
- sessionStorage.removeItem(ANALYTICS_SESSION_STORAGE_KEY);
408
+ sessionStorage.removeItem(this.storageKey());
81
409
  return this.fallbackState;
82
410
  }
83
411
  this.fallbackState = state;
@@ -89,10 +417,13 @@ var AnalyticsSessionCoordinator = class {
89
417
  write(state) {
90
418
  this.fallbackState = state;
91
419
  try {
92
- sessionStorage.setItem(ANALYTICS_SESSION_STORAGE_KEY, JSON.stringify(state));
420
+ sessionStorage.setItem(this.storageKey(), JSON.stringify(state));
93
421
  } catch {
94
422
  }
95
423
  }
424
+ storageKey() {
425
+ return `${ANALYTICS_SESSION_STORAGE_KEY_PREFIX}${encodeURIComponent(this.identity)}`;
426
+ }
96
427
  };
97
428
  function newSession(nowMs) {
98
429
  return {
@@ -159,11 +490,127 @@ function generateSessionId() {
159
490
 
160
491
  // src/activity.ts
161
492
  var VISITOR_ID_STORAGE_KEY = "cimplify_visitor_id";
493
+ var ACTIVITY_RETRY_POLICY = {
494
+ maxRetries: 1,
495
+ jitterRatio: 0.2
496
+ };
497
+ var PAGE_VIEW_TRACKER_KEY = /* @__PURE__ */ Symbol.for("@cimplify/sdk.page-view-tracker-hub");
498
+ var PAGE_VIEW_TRACKER_VERSION = 2;
499
+ function trackerHost() {
500
+ return window;
501
+ }
502
+ function currentWindowTrackerHub() {
503
+ const candidate = trackerHost()[PAGE_VIEW_TRACKER_KEY];
504
+ return candidate?.version === PAGE_VIEW_TRACKER_VERSION && candidate.registrations instanceof Map && typeof candidate.recordAll === "function" ? candidate : null;
505
+ }
506
+ function weakReference(target) {
507
+ const WeakReference = globalThis.WeakRef;
508
+ if (WeakReference) return new WeakReference(target);
509
+ return { deref: () => target };
510
+ }
511
+ function latestLiveOwner(registration) {
512
+ let latest = null;
513
+ for (const [token, reference] of registration.owners) {
514
+ const owner = reference.deref();
515
+ if (!owner || owner.released) {
516
+ registration.owners.delete(token);
517
+ } else {
518
+ latest = owner;
519
+ }
520
+ }
521
+ return latest;
522
+ }
523
+ function recordRegistration(registration, path) {
524
+ if (path === registration.lastPath) return;
525
+ const owner = registration.activeOwner && !registration.activeOwner.released ? registration.activeOwner : latestLiveOwner(registration);
526
+ if (!owner) return;
527
+ registration.activeOwner = owner;
528
+ registration.lastPath = path;
529
+ owner.recorder(path);
530
+ }
531
+ function createWindowTrackerHub() {
532
+ const originalPushState = window.history.pushState;
533
+ const originalReplaceState = window.history.replaceState;
534
+ const hub = {
535
+ version: PAGE_VIEW_TRACKER_VERSION,
536
+ registrations: /* @__PURE__ */ new Map(),
537
+ originalPushState,
538
+ originalReplaceState
539
+ };
540
+ hub.recordAll = () => {
541
+ const path = window.location.pathname;
542
+ for (const registration of hub.registrations.values()) {
543
+ recordRegistration(registration, path);
544
+ }
545
+ };
546
+ hub.patchedPushState = function(...args) {
547
+ originalPushState.apply(this, args);
548
+ hub.recordAll();
549
+ };
550
+ hub.patchedReplaceState = function(...args) {
551
+ originalReplaceState.apply(this, args);
552
+ hub.recordAll();
553
+ };
554
+ hub.popstateListener = () => hub.recordAll();
555
+ window.history.pushState = hub.patchedPushState;
556
+ window.history.replaceState = hub.patchedReplaceState;
557
+ window.addEventListener("popstate", hub.popstateListener);
558
+ trackerHost()[PAGE_VIEW_TRACKER_KEY] = hub;
559
+ return hub;
560
+ }
561
+ function pageViewTrackerIdentity(client) {
562
+ return JSON.stringify([client.getBaseUrl(), client.getPublicKey().trim()]);
563
+ }
564
+ function acquireWindowPageViewTracker(identity, recorder) {
565
+ const hub = currentWindowTrackerHub() ?? createWindowTrackerHub();
566
+ let registration = hub.registrations.get(identity);
567
+ const isNewIdentity = !registration;
568
+ if (!registration) {
569
+ registration = { owners: /* @__PURE__ */ new Map(), activeOwner: null, lastPath: null };
570
+ hub.registrations.set(identity, registration);
571
+ }
572
+ const owner = {
573
+ token: Symbol(identity),
574
+ recorder,
575
+ released: false
576
+ };
577
+ registration.owners.set(owner.token, weakReference(owner));
578
+ registration.activeOwner = owner;
579
+ if (isNewIdentity) {
580
+ recordRegistration(registration, window.location.pathname);
581
+ }
582
+ let released = false;
583
+ return () => {
584
+ if (released) return;
585
+ released = true;
586
+ owner.released = true;
587
+ registration.owners.delete(owner.token);
588
+ if (registration.activeOwner === owner) {
589
+ registration.activeOwner = latestLiveOwner(registration);
590
+ }
591
+ if (registration.activeOwner) return;
592
+ if (hub.registrations.get(identity) === registration) {
593
+ hub.registrations.delete(identity);
594
+ }
595
+ if (hub.registrations.size !== 0) return;
596
+ window.removeEventListener("popstate", hub.popstateListener);
597
+ if (window.history.pushState === hub.patchedPushState) {
598
+ window.history.pushState = hub.originalPushState;
599
+ }
600
+ if (window.history.replaceState === hub.patchedReplaceState) {
601
+ window.history.replaceState = hub.originalReplaceState;
602
+ }
603
+ if (currentWindowTrackerHub() === hub) {
604
+ delete trackerHost()[PAGE_VIEW_TRACKER_KEY];
605
+ }
606
+ };
607
+ }
162
608
  var ActivityService = class {
163
609
  constructor(client) {
164
610
  this.client = client;
165
- this.sessions = new AnalyticsSessionCoordinator();
611
+ this.localGeneration = 0;
166
612
  this.bootstrapRequest = null;
613
+ this.sessions = this.createSessionCoordinator();
167
614
  }
168
615
  /**
169
616
  * Record session start (landing, referrer, UTM, device). Fire-and-forget,
@@ -173,7 +620,7 @@ var ActivityService = class {
173
620
  startSession() {
174
621
  if (typeof window === "undefined") return;
175
622
  const session = this.sessions.beginEvent();
176
- void this.bootstrapSession(session).catch(() => {
623
+ void this.bootstrapSession(session, false, this.captureGeneration()).catch(() => {
177
624
  });
178
625
  }
179
626
  /** Rebind an existing analytics session after the server authenticates a customer. */
@@ -181,13 +628,19 @@ var ActivityService = class {
181
628
  if (typeof window === "undefined") return;
182
629
  const session = this.sessions.current();
183
630
  if (!session) return;
184
- void this.bootstrapSession(session, true).catch(() => {
631
+ void this.bootstrapSession(session, true, this.captureGeneration()).catch(() => {
185
632
  });
186
633
  }
187
634
  /** A signed-out browser starts a fresh anonymous analytics session. */
188
635
  resetSession() {
636
+ this.invalidatePendingActivity();
189
637
  this.sessions.reset();
190
- this.bootstrapRequest = null;
638
+ }
639
+ /** Drop the old storefront's analytics state before binding this service to the new one. */
640
+ resetForStorefrontIdentityChange() {
641
+ this.invalidatePendingActivity();
642
+ this.sessions.reset();
643
+ this.sessions = this.createSessionCoordinator();
191
644
  }
192
645
  buildSessionPayload(session) {
193
646
  const params = new URLSearchParams(window.location.search);
@@ -264,7 +717,7 @@ var ActivityService = class {
264
717
  this.sendEvents([event]);
265
718
  }
266
719
  async getState() {
267
- return chunkIQFFSKE2_js.safe(this.client.get("/api/v1/activity/state"));
720
+ return chunkDQEXY542_js.safe(this.client.get("/api/v1/activity/state"));
268
721
  }
269
722
  async getRecommendations(options) {
270
723
  const params = new URLSearchParams();
@@ -272,10 +725,10 @@ var ActivityService = class {
272
725
  if (options?.limit) params.set("limit", String(options.limit));
273
726
  const query = params.toString();
274
727
  const path = query ? `/api/v1/activity/recommendations?${query}` : "/api/v1/activity/recommendations";
275
- return chunkIQFFSKE2_js.safe(this.client.get(path));
728
+ return chunkDQEXY542_js.safe(this.client.get(path));
276
729
  }
277
730
  async dismissMessage(code) {
278
- return chunkIQFFSKE2_js.safe(
731
+ return chunkDQEXY542_js.safe(
279
732
  this.client.post("/api/v1/activity/messages/dismiss", { code })
280
733
  );
281
734
  }
@@ -283,32 +736,12 @@ var ActivityService = class {
283
736
  autoTrackPageViews() {
284
737
  if (typeof window === "undefined") return () => {
285
738
  };
286
- let lastPath = null;
287
- const record = () => {
288
- const path = window.location.pathname;
289
- if (path === lastPath) return;
290
- lastPath = path;
739
+ return acquireWindowPageViewTracker(pageViewTrackerIdentity(this.client), (path) => {
291
740
  try {
292
741
  this.trackPageView({ pagePath: path });
293
742
  } catch {
294
743
  }
295
- };
296
- const { pushState, replaceState } = window.history;
297
- window.history.pushState = function(...args) {
298
- pushState.apply(this, args);
299
- record();
300
- };
301
- window.history.replaceState = function(...args) {
302
- replaceState.apply(this, args);
303
- record();
304
- };
305
- window.addEventListener("popstate", record);
306
- record();
307
- return () => {
308
- window.history.pushState = pushState;
309
- window.history.replaceState = replaceState;
310
- window.removeEventListener("popstate", record);
311
- };
744
+ });
312
745
  }
313
746
  sendEvents(events, session) {
314
747
  if (typeof window === "undefined") return;
@@ -316,29 +749,59 @@ var ActivityService = class {
316
749
  });
317
750
  }
318
751
  async postEvents(events, session) {
319
- await this.bootstrapSession(session);
320
- await this.client.post("/api/v1/activity/events", {
321
- analytics_session_id: session.id,
322
- occurred_at: session.occurredAt,
323
- events
324
- });
752
+ const generation = this.captureGeneration();
753
+ await this.bootstrapSession(session, false, generation);
754
+ if (!this.isCurrentGeneration(generation)) return;
755
+ await this.client.post(
756
+ "/api/v1/activity/events",
757
+ {
758
+ analytics_session_id: session.id,
759
+ occurred_at: session.occurredAt,
760
+ events
761
+ },
762
+ { retryPolicy: ACTIVITY_RETRY_POLICY }
763
+ );
325
764
  }
326
- bootstrapSession(session, force = false) {
765
+ bootstrapSession(session, force = false, generation = this.captureGeneration()) {
327
766
  if (!force && !session.requiresBootstrap) return Promise.resolve();
328
- if (!force && this.bootstrapRequest?.sessionId === session.id) {
767
+ if (!force && this.bootstrapRequest?.sessionId === session.id && sameActivityGeneration(this.bootstrapRequest.generation, generation)) {
329
768
  return this.bootstrapRequest.promise;
330
769
  }
331
- const promise = this.client.post("/api/v1/activity/session", this.buildSessionPayload(session)).then(() => {
332
- this.sessions.markBootstrapped(session.id);
770
+ const promise = this.client.post("/api/v1/activity/session", this.buildSessionPayload(session), {
771
+ retryPolicy: ACTIVITY_RETRY_POLICY
772
+ }).then(() => {
773
+ if (this.isCurrentGeneration(generation)) {
774
+ this.sessions.markBootstrapped(session.id);
775
+ }
333
776
  }).finally(() => {
334
777
  if (this.bootstrapRequest?.promise === promise) {
335
778
  this.bootstrapRequest = null;
336
779
  }
337
780
  });
338
- this.bootstrapRequest = { sessionId: session.id, promise };
781
+ this.bootstrapRequest = { sessionId: session.id, generation, promise };
339
782
  return promise;
340
783
  }
784
+ captureGeneration() {
785
+ return {
786
+ local: this.localGeneration,
787
+ publicKey: this.client.getPublicKeyEpoch(),
788
+ session: this.client.getSessionEpoch()
789
+ };
790
+ }
791
+ isCurrentGeneration(generation) {
792
+ return sameActivityGeneration(generation, this.captureGeneration());
793
+ }
794
+ invalidatePendingActivity() {
795
+ this.localGeneration += 1;
796
+ this.bootstrapRequest = null;
797
+ }
798
+ createSessionCoordinator() {
799
+ return new AnalyticsSessionCoordinator(pageViewTrackerIdentity(this.client));
800
+ }
341
801
  };
802
+ function sameActivityGeneration(left, right) {
803
+ return left.local === right.local && left.publicKey === right.publicKey && left.session === right.session;
804
+ }
342
805
  function currentPath() {
343
806
  if (typeof window !== "undefined") {
344
807
  return window.location.pathname;
@@ -371,16 +834,16 @@ var SubscriptionService = class {
371
834
  this.client = client;
372
835
  }
373
836
  async list() {
374
- return chunkIQFFSKE2_js.safe(this.client.get("/api/v1/subscriptions"));
837
+ return chunkDQEXY542_js.safe(this.client.get("/api/v1/subscriptions"));
375
838
  }
376
839
  async get(id) {
377
840
  const encodedId = encodeURIComponent(id);
378
- return chunkIQFFSKE2_js.safe(this.client.get(`/api/v1/subscriptions/${encodedId}`));
841
+ return chunkDQEXY542_js.safe(this.client.get(`/api/v1/subscriptions/${encodedId}`));
379
842
  }
380
843
  async cancel(id, reason, opts) {
381
844
  const encodedId = encodeURIComponent(id);
382
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
383
- return chunkIQFFSKE2_js.safe(
845
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
846
+ return chunkDQEXY542_js.safe(
384
847
  this.client.post(
385
848
  `/api/v1/subscriptions/${encodedId}/cancel`,
386
849
  { reason },
@@ -390,20 +853,20 @@ var SubscriptionService = class {
390
853
  }
391
854
  async pause(id) {
392
855
  const encodedId = encodeURIComponent(id);
393
- return chunkIQFFSKE2_js.safe(
856
+ return chunkDQEXY542_js.safe(
394
857
  this.client.post(`/api/v1/subscriptions/${encodedId}/pause`)
395
858
  );
396
859
  }
397
860
  async resume(id) {
398
861
  const encodedId = encodeURIComponent(id);
399
- return chunkIQFFSKE2_js.safe(
862
+ return chunkDQEXY542_js.safe(
400
863
  this.client.post(`/api/v1/subscriptions/${encodedId}/resume`)
401
864
  );
402
865
  }
403
866
  async skipNextRenewal(id, opts) {
404
867
  const encodedId = encodeURIComponent(id);
405
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
406
- return chunkIQFFSKE2_js.safe(
868
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
869
+ return chunkDQEXY542_js.safe(
407
870
  this.client.post(
408
871
  `/api/v1/subscriptions/${encodedId}/skip`,
409
872
  void 0,
@@ -419,8 +882,8 @@ var UploadService = class {
419
882
  this.client = client;
420
883
  }
421
884
  async init(filename, contentType2, sizeBytes, opts) {
422
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
423
- return chunkIQFFSKE2_js.safe(
885
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
886
+ return chunkDQEXY542_js.safe(
424
887
  this.client.post(
425
888
  "/api/v1/uploads/init",
426
889
  {
@@ -433,7 +896,7 @@ var UploadService = class {
433
896
  );
434
897
  }
435
898
  async confirm(uploadId) {
436
- return chunkIQFFSKE2_js.safe(
899
+ return chunkDQEXY542_js.safe(
437
900
  this.client.post("/api/v1/uploads/confirm", {
438
901
  upload_id: uploadId
439
902
  })
@@ -452,7 +915,7 @@ var UploadService = class {
452
915
  if (!uploadResponse.ok) {
453
916
  return {
454
917
  ok: false,
455
- error: new chunk4BKOKHE3_js.CimplifyError(
918
+ error: new chunkSFUJMS5E_js.CimplifyError(
456
919
  "UPLOAD_FAILED",
457
920
  `Upload failed with status ${uploadResponse.status}`,
458
921
  true
@@ -462,7 +925,7 @@ var UploadService = class {
462
925
  } catch (error) {
463
926
  return {
464
927
  ok: false,
465
- error: new chunk4BKOKHE3_js.CimplifyError(
928
+ error: new chunkSFUJMS5E_js.CimplifyError(
466
929
  "UPLOAD_FAILED",
467
930
  error instanceof Error ? error.message : "Upload failed",
468
931
  true
@@ -479,7 +942,7 @@ var PlacesService = class {
479
942
  this.client = client;
480
943
  }
481
944
  async autocomplete(input, sessionToken) {
482
- return chunkIQFFSKE2_js.safe(
945
+ return chunkDQEXY542_js.safe(
483
946
  this.client.post("/api/v1/places/autocomplete", {
484
947
  input,
485
948
  sessionToken
@@ -487,7 +950,7 @@ var PlacesService = class {
487
950
  );
488
951
  }
489
952
  async details(placeId, sessionToken) {
490
- return chunkIQFFSKE2_js.safe(
953
+ return chunkDQEXY542_js.safe(
491
954
  this.client.post("/api/v1/places/details", {
492
955
  place_id: placeId,
493
956
  sessionToken
@@ -506,7 +969,7 @@ var DeliveryService = class {
506
969
  params.set("dropoff_lat", String(dropoffLat));
507
970
  params.set("dropoff_lng", String(dropoffLng));
508
971
  if (country) params.set("country", country);
509
- return chunkIQFFSKE2_js.safe(this.client.get(`/api/v1/delivery/fee?${params.toString()}`));
972
+ return chunkDQEXY542_js.safe(this.client.get(`/api/v1/delivery/fee?${params.toString()}`));
510
973
  }
511
974
  async getOptions(queryOrLatitude, longitude, legacyOptions) {
512
975
  const query = typeof queryOrLatitude === "number" ? {
@@ -520,7 +983,7 @@ var DeliveryService = class {
520
983
  if (query.country) params.set("country", query.country);
521
984
  if (query.currency) params.set("currency", query.currency);
522
985
  if (query.orderValue != null) params.set("order_value", String(query.orderValue));
523
- return chunkIQFFSKE2_js.safe(
986
+ return chunkDQEXY542_js.safe(
524
987
  this.client.get(`/api/v1/delivery/options?${params.toString()}`)
525
988
  );
526
989
  }
@@ -692,7 +1155,7 @@ var SupportService = class {
692
1155
  async claimConversation() {
693
1156
  const accessToken = this.client.getAccessToken();
694
1157
  if (!accessToken) {
695
- return chunkIQFFSKE2_js.err(new chunk4BKOKHE3_js.CimplifyError("not_authenticated", "No access token to claim with"));
1158
+ return chunkDQEXY542_js.err(new chunkSFUJMS5E_js.CimplifyError("not_authenticated", "No access token to claim with"));
696
1159
  }
697
1160
  if (this.claimInFlight) {
698
1161
  if (this.claimInFlightToken === accessToken) return this.claimInFlight;
@@ -700,12 +1163,12 @@ var SupportService = class {
700
1163
  return this.claimConversation();
701
1164
  }
702
1165
  if (this.lastClaimedAccessToken === accessToken) {
703
- return chunkIQFFSKE2_js.err(new chunk4BKOKHE3_js.CimplifyError("already_claimed", "Session already claimed for this token"));
1166
+ return chunkDQEXY542_js.err(new chunkSFUJMS5E_js.CimplifyError("already_claimed", "Session already claimed for this token"));
704
1167
  }
705
1168
  const epoch = this.client.getSessionEpoch();
706
1169
  this.claimInFlightToken = accessToken;
707
1170
  this.claimInFlight = (async () => {
708
- const result = await chunkIQFFSKE2_js.safe(
1171
+ const result = await chunkDQEXY542_js.safe(
709
1172
  this.client.post(
710
1173
  "/api/v1/support/conversation/claim",
711
1174
  { access_token: accessToken },
@@ -714,8 +1177,8 @@ var SupportService = class {
714
1177
  );
715
1178
  if (result.ok) {
716
1179
  if (this.client.getSessionEpoch() !== epoch) {
717
- return chunkIQFFSKE2_js.err(
718
- new chunk4BKOKHE3_js.CimplifyError("session_cleared", "Session was cleared during the claim")
1180
+ return chunkDQEXY542_js.err(
1181
+ new chunkSFUJMS5E_js.CimplifyError("session_cleared", "Session was cleared during the claim")
719
1182
  );
720
1183
  }
721
1184
  this.lastClaimedAccessToken = accessToken;
@@ -745,9 +1208,9 @@ var SupportService = class {
745
1208
  */
746
1209
  async claimExternalChats() {
747
1210
  if (!this.client.getAccessToken()) {
748
- return chunkIQFFSKE2_js.err(new chunk4BKOKHE3_js.CimplifyError("not_authenticated", "No access token to claim with"));
1211
+ return chunkDQEXY542_js.err(new chunkSFUJMS5E_js.CimplifyError("not_authenticated", "No access token to claim with"));
749
1212
  }
750
- return chunkIQFFSKE2_js.safe(
1213
+ return chunkDQEXY542_js.safe(
751
1214
  (async () => {
752
1215
  const businessId = await this.client.resolveBusinessId();
753
1216
  return this.client.post("/v1/me/chats/external-claims", {
@@ -762,26 +1225,26 @@ var SupportService = class {
762
1225
  * the inbox with empty threads.
763
1226
  */
764
1227
  async peekConversation() {
765
- const result = await chunkIQFFSKE2_js.safe(
1228
+ const result = await chunkDQEXY542_js.safe(
766
1229
  this.client.get("/api/v1/support/conversation")
767
1230
  );
768
1231
  if (!result.ok) return result;
769
- if (!result.value.conversation) return chunkIQFFSKE2_js.ok(null);
770
- return chunkIQFFSKE2_js.ok({
1232
+ if (!result.value.conversation) return chunkDQEXY542_js.ok(null);
1233
+ return chunkDQEXY542_js.ok({
771
1234
  conversation: result.value.conversation,
772
1235
  messages: chatMessagesFromWire(result.value.messages)
773
1236
  });
774
1237
  }
775
1238
  /** Open (or resume) the customer's widget conversation. */
776
1239
  async openConversation(opts) {
777
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
778
- const result = await chunkIQFFSKE2_js.safe(
1240
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
1241
+ const result = await chunkDQEXY542_js.safe(
779
1242
  this.client.post("/api/v1/support/conversation", void 0, {
780
1243
  idempotencyKey
781
1244
  })
782
1245
  );
783
1246
  if (!result.ok) return result;
784
- return chunkIQFFSKE2_js.ok({
1247
+ return chunkDQEXY542_js.ok({
785
1248
  conversation: result.value.conversation,
786
1249
  messages: chatMessagesFromWire(result.value.messages)
787
1250
  });
@@ -795,8 +1258,8 @@ var SupportService = class {
795
1258
  * server resolves it thread-scoped and echoes the quote as `reply_to`.
796
1259
  */
797
1260
  async sendMessage(content, opts) {
798
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
799
- const result = await chunkIQFFSKE2_js.safe(
1261
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
1262
+ const result = await chunkDQEXY542_js.safe(
800
1263
  this.client.post(
801
1264
  "/api/v1/support/conversation/messages",
802
1265
  {
@@ -808,7 +1271,7 @@ var SupportService = class {
808
1271
  { idempotencyKey }
809
1272
  )
810
1273
  );
811
- return result.ok ? chunkIQFFSKE2_js.ok(chatMessageFromWire(result.value.message)) : result;
1274
+ return result.ok ? chunkDQEXY542_js.ok(chatMessageFromWire(result.value.message)) : result;
812
1275
  }
813
1276
  /**
814
1277
  * Poll for messages. `after` pages forward (live updates); `before` pages
@@ -823,25 +1286,25 @@ var SupportService = class {
823
1286
  if (options.limit) params.set("limit", String(options.limit));
824
1287
  const query = params.toString();
825
1288
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
826
- const result = await chunkIQFFSKE2_js.safe(this.client.get(path));
827
- return result.ok ? chunkIQFFSKE2_js.ok(chatMessagesFromWire(result.value)) : result;
1289
+ const result = await chunkDQEXY542_js.safe(this.client.get(path));
1290
+ return result.ok ? chunkDQEXY542_js.ok(chatMessagesFromWire(result.value)) : result;
828
1291
  }
829
1292
  /** React to a message in the active conversation by its `ChatMessage.id`. */
830
1293
  async reactToMessage(messageId, emoji) {
831
- const clientId = chunkIQFFSKE2_js.generateIdempotencyKey();
832
- const result = await chunkIQFFSKE2_js.safe(
1294
+ const clientId = chunkDQEXY542_js.generateIdempotencyKey();
1295
+ const result = await chunkDQEXY542_js.safe(
833
1296
  this.client.post(
834
1297
  `/api/v1/support/conversation/messages/${messageId}/reactions`,
835
1298
  { emoji, client_id: clientId },
836
1299
  { idempotencyKey: clientId }
837
1300
  )
838
1301
  );
839
- return result.ok ? chunkIQFFSKE2_js.ok(chatMessageFromWire(result.value.message)) : result;
1302
+ return result.ok ? chunkDQEXY542_js.ok(chatMessageFromWire(result.value.message)) : result;
840
1303
  }
841
1304
  /** Ask for a person: flags the thread for the merchant's inbox. */
842
1305
  async requestHuman(opts) {
843
- const idempotencyKey = opts?.idempotencyKey ?? chunkIQFFSKE2_js.generateIdempotencyKey();
844
- return chunkIQFFSKE2_js.safe(
1306
+ const idempotencyKey = opts?.idempotencyKey ?? chunkDQEXY542_js.generateIdempotencyKey();
1307
+ return chunkDQEXY542_js.safe(
845
1308
  this.client.post(
846
1309
  "/api/v1/support/conversation/handoff",
847
1310
  void 0,
@@ -851,459 +1314,108 @@ var SupportService = class {
851
1314
  }
852
1315
  };
853
1316
 
854
- // src/payment-authorization/providers/paystack.ts
855
- async function openPaystackPopup(options, signal) {
856
- if (typeof window === "undefined") {
857
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
858
- }
859
- let PaystackPop;
860
- try {
861
- const imported = await import('@paystack/inline-js');
862
- PaystackPop = imported.default;
863
- } catch {
864
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
865
- }
866
- return new Promise((resolve) => {
867
- let settled = false;
868
- let providerStarted = false;
869
- const resolveOnce = (result) => {
870
- if (settled) {
871
- return;
872
- }
873
- settled = true;
874
- if (signal) {
875
- signal.removeEventListener("abort", onAbort);
876
- }
877
- resolve(result);
878
- };
879
- const onAbort = () => {
880
- resolveOnce({
881
- success: false,
882
- // Once Paystack owns the transaction, cancellation is ambiguous. The
883
- // adapter converts this into submitted so Cimplify polling decides.
884
- error: providerStarted ? "SUBMISSION_UNKNOWN" : "CANCELLED"
885
- });
886
- };
887
- if (signal?.aborted) {
888
- resolveOnce({ success: false, error: "CANCELLED" });
889
- return;
890
- }
891
- if (signal) {
892
- signal.addEventListener("abort", onAbort, { once: true });
893
- }
894
- try {
895
- const popup = new PaystackPop();
896
- popup.newTransaction({
897
- key: options.key,
898
- email: options.email,
899
- amount: options.amount,
900
- currency: options.currency,
901
- reference: options.reference,
902
- accessCode: options.accessCode,
903
- onSuccess: (transaction) => {
904
- resolveOnce({
905
- success: true,
906
- reference: transaction.reference ?? options.reference
907
- });
908
- },
909
- onCancel: () => {
910
- resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
911
- },
912
- onError: (error) => {
913
- resolveOnce({
914
- success: false,
915
- error: error?.message || "PAYMENT_FAILED"
916
- });
917
- }
918
- });
919
- providerStarted = true;
920
- } catch {
921
- resolveOnce({ success: false, error: "POPUP_BLOCKED" });
922
- }
923
- });
1317
+ // src/internal/cross-tab-session.ts
1318
+ var CROSS_TAB_SESSION_HUB_KEY = /* @__PURE__ */ Symbol.for("@cimplify/sdk.cross-tab-session-hub");
1319
+ var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
1320
+ var MAX_RECENT_ENVELOPES = 64;
1321
+ function hubHost() {
1322
+ return window;
924
1323
  }
925
- var PaystackAuthorizationAdapter = class {
926
- constructor(openPopup = openPaystackPopup) {
927
- this.openPopup = openPopup;
928
- this.provider = "paystack";
929
- }
930
- async authorize(context) {
931
- const result = await this.openPopup(
932
- {
933
- key: context.action.public_key,
934
- email: context.email,
935
- accessCode: context.action.client_secret,
936
- reference: context.reference || context.action.client_secret,
937
- currency: context.currency
938
- },
939
- context.signal
940
- );
941
- if (result.success) {
942
- return { status: "submitted", reference: result.reference || context.reference };
943
- }
944
- if (result.error === "SUBMISSION_UNKNOWN") {
945
- return { status: "submitted", reference: context.reference };
946
- }
947
- if (!result.error || result.error === "CANCELLED" || result.error === "PAYMENT_CANCELLED") {
948
- return { status: "cancelled" };
949
- }
950
- if (result.error === "POPUP_BLOCKED") {
951
- return {
952
- status: "failed",
953
- code: "POPUP_BLOCKED",
954
- message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
955
- recoverable: true
956
- };
957
- }
958
- if (result.error === "PROVIDER_UNAVAILABLE") {
959
- return {
960
- status: "failed",
961
- code: "PROVIDER_UNAVAILABLE",
962
- message: "Paystack is unavailable in this environment.",
963
- recoverable: false
964
- };
965
- }
966
- return {
967
- status: "failed",
968
- code: "PAYMENT_FAILED",
969
- message: result.error || "Paystack payment could not be submitted.",
970
- recoverable: true
971
- };
1324
+ function currentHub() {
1325
+ const candidate = hubHost()[CROSS_TAB_SESSION_HUB_KEY];
1326
+ return candidate?.subscribers instanceof Map && candidate.recentEnvelopes instanceof Set && typeof candidate.storageListener === "function" && typeof candidate.dispatch === "function" ? candidate : null;
1327
+ }
1328
+ function subscriberReference(target) {
1329
+ const WeakReference = globalThis.WeakRef;
1330
+ if (WeakReference) return new WeakReference(target);
1331
+ return { deref: () => target };
1332
+ }
1333
+ function pruneSubscribers(hub) {
1334
+ for (const [token, reference] of hub.subscribers) {
1335
+ if (!reference.deref()) hub.subscribers.delete(token);
972
1336
  }
973
- };
974
-
975
- // src/payment-authorization/providers/stripe.ts
976
- async function loadStripeFromPeer(publicKey, options) {
1337
+ }
1338
+ function parseSessionSyncPayload(serialized) {
1339
+ if (!serialized) return null;
977
1340
  try {
978
- const imported = await import('@stripe/stripe-js');
979
- return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
1341
+ const payload = JSON.parse(serialized);
1342
+ return (payload.type === "claimed" || payload.type === "cleared") && typeof payload.token === "string" && payload.token.length > 0 && typeof payload.at === "number" && Number.isFinite(payload.at) && (payload.name === void 0 || payload.name === null || typeof payload.name === "string") ? payload : null;
980
1343
  } catch {
981
1344
  return null;
982
1345
  }
983
1346
  }
984
- function createStripeModal() {
985
- if (typeof document === "undefined" || !document.body) return null;
986
- const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
987
- const root = document.createElement("div");
988
- root.setAttribute("role", "dialog");
989
- root.setAttribute("aria-modal", "true");
990
- root.setAttribute("aria-label", "Secure card payment");
991
- Object.assign(root.style, {
992
- position: "fixed",
993
- inset: "0",
994
- zIndex: "2147483647",
995
- display: "grid",
996
- placeItems: "center",
997
- padding: "16px",
998
- background: "rgba(15, 23, 42, 0.58)"
999
- });
1000
- const form = document.createElement("form");
1001
- Object.assign(form.style, {
1002
- width: "min(100%, 480px)",
1003
- maxHeight: "calc(100vh - 32px)",
1004
- overflow: "auto",
1005
- borderRadius: "12px",
1006
- padding: "24px",
1007
- background: "#fff",
1008
- boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
1009
- });
1010
- const title = document.createElement("h2");
1011
- title.textContent = "Complete card payment";
1012
- Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
1013
- const paymentMount = document.createElement("div");
1014
- paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
1015
- const error = document.createElement("p");
1016
- error.setAttribute("role", "alert");
1017
- Object.assign(error.style, {
1018
- minHeight: "20px",
1019
- margin: "14px 0 0",
1020
- color: "#b91c1c",
1021
- font: "14px/1.4 system-ui"
1022
- });
1023
- const actions = document.createElement("div");
1024
- Object.assign(actions.style, {
1025
- display: "flex",
1026
- justifyContent: "flex-end",
1027
- gap: "10px",
1028
- marginTop: "18px"
1029
- });
1030
- const cancelButton = document.createElement("button");
1031
- cancelButton.type = "button";
1032
- cancelButton.textContent = "Cancel";
1033
- Object.assign(cancelButton.style, {
1034
- border: "1px solid #cbd5e1",
1035
- borderRadius: "8px",
1036
- padding: "10px 16px",
1037
- background: "#fff",
1038
- color: "#0f172a",
1039
- cursor: "pointer"
1040
- });
1041
- const submitButton = document.createElement("button");
1042
- submitButton.type = "submit";
1043
- submitButton.textContent = "Pay securely";
1044
- Object.assign(submitButton.style, {
1045
- border: "0",
1046
- borderRadius: "8px",
1047
- padding: "10px 16px",
1048
- background: "#0f172a",
1049
- color: "#fff",
1050
- cursor: "pointer"
1051
- });
1052
- actions.append(cancelButton, submitButton);
1053
- form.append(title, paymentMount, error, actions);
1054
- root.append(form);
1055
- document.body.append(root);
1056
- cancelButton.focus();
1057
- return { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
1347
+ function sessionSyncEnvelopeKey(payload) {
1348
+ const name = payload.name === void 0 ? ["missing"] : ["present", payload.name];
1349
+ return JSON.stringify([payload.type, payload.token, name, payload.at]);
1058
1350
  }
1059
- function stripeFailure(error) {
1060
- const message = error?.message || "Stripe could not authorize this payment.";
1061
- if (error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error") {
1062
- return {
1063
- status: "failed",
1064
- code: "AUTHORIZATION_FAILED",
1065
- message,
1066
- recoverable: true
1067
- };
1068
- }
1069
- return { status: "failed", code: "PAYMENT_FAILED", message, recoverable: true };
1351
+ function rememberEnvelope(hub, envelope) {
1352
+ if (hub.recentEnvelopes.has(envelope)) return false;
1353
+ hub.recentEnvelopes.add(envelope);
1354
+ if (hub.recentEnvelopes.size > MAX_RECENT_ENVELOPES) {
1355
+ const oldest = hub.recentEnvelopes.values().next().value;
1356
+ if (oldest) hub.recentEnvelopes.delete(oldest);
1357
+ }
1358
+ return true;
1070
1359
  }
1071
- var StripeAuthorizationAdapter = class {
1072
- constructor(loadStripe = loadStripeFromPeer) {
1073
- this.loadStripe = loadStripe;
1074
- this.provider = "stripe";
1075
- }
1076
- async authorize(context) {
1077
- if (typeof window === "undefined" || typeof document === "undefined" || context.signal?.aborted) {
1078
- return context.signal?.aborted ? { status: "cancelled" } : {
1079
- status: "failed",
1080
- code: "PROVIDER_UNAVAILABLE",
1081
- message: "Stripe Payment Element is unavailable in this environment.",
1082
- recoverable: false
1083
- };
1084
- }
1085
- let stripe;
1086
- try {
1087
- stripe = await this.loadStripe(
1088
- context.action.public_key,
1089
- context.action.provider_account_id ? { stripeAccount: context.action.provider_account_id } : void 0
1090
- );
1091
- } catch (error) {
1092
- return {
1093
- status: "failed",
1094
- code: "PROVIDER_UNAVAILABLE",
1095
- message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
1096
- recoverable: true
1097
- };
1098
- }
1099
- if (context.signal?.aborted) {
1100
- return { status: "cancelled" };
1101
- }
1102
- if (!stripe) {
1103
- return {
1104
- status: "failed",
1105
- code: "PROVIDER_UNAVAILABLE",
1106
- message: "Stripe.js could not be loaded.",
1107
- recoverable: false
1108
- };
1109
- }
1110
- const modal = createStripeModal();
1111
- if (!modal) {
1112
- return {
1113
- status: "failed",
1114
- code: "PROVIDER_UNAVAILABLE",
1115
- message: "Stripe Payment Element could not be mounted.",
1116
- recoverable: false
1117
- };
1118
- }
1119
- let paymentElement;
1120
- let elements;
1121
- try {
1122
- elements = stripe.elements({ clientSecret: context.action.client_secret });
1123
- paymentElement = elements.create("payment");
1124
- paymentElement.mount(modal.paymentMount);
1125
- } catch {
1126
- modal.root.remove();
1127
- modal.previousFocus?.focus();
1128
- return {
1129
- status: "failed",
1130
- code: "PROVIDER_UNAVAILABLE",
1131
- message: "Stripe Payment Element could not be initialized.",
1132
- recoverable: false
1133
- };
1360
+ function createHub() {
1361
+ const hub = {
1362
+ subscribers: /* @__PURE__ */ new Map(),
1363
+ recentEnvelopes: /* @__PURE__ */ new Set()
1364
+ };
1365
+ hub.dispatch = (payload) => {
1366
+ if (!rememberEnvelope(hub, sessionSyncEnvelopeKey(payload))) return;
1367
+ for (const [token, reference] of hub.subscribers) {
1368
+ const subscriber = reference.deref();
1369
+ if (!subscriber) {
1370
+ hub.subscribers.delete(token);
1371
+ continue;
1372
+ }
1373
+ try {
1374
+ subscriber.notify(payload);
1375
+ } catch {
1376
+ }
1134
1377
  }
1135
- if (context.signal?.aborted) {
1136
- if (paymentElement.destroy) paymentElement.destroy();
1137
- else paymentElement.unmount?.();
1138
- modal.root.remove();
1139
- modal.previousFocus?.focus();
1140
- return { status: "cancelled" };
1141
- }
1142
- return new Promise((resolve) => {
1143
- let settled = false;
1144
- let submitting = false;
1145
- let confirmationStarted = false;
1146
- const cleanup = () => {
1147
- context.signal?.removeEventListener("abort", onAbort);
1148
- modal.form.removeEventListener("submit", onSubmit);
1149
- modal.cancelButton.removeEventListener("click", onCancel);
1150
- if (paymentElement.destroy) paymentElement.destroy();
1151
- else paymentElement.unmount?.();
1152
- modal.root.remove();
1153
- modal.previousFocus?.focus();
1154
- };
1155
- const settle = (outcome) => {
1156
- if (settled) return;
1157
- settled = true;
1158
- cleanup();
1159
- resolve(outcome);
1160
- };
1161
- const onAbort = () => {
1162
- if (confirmationStarted) {
1163
- settle({ status: "submitted", reference: context.reference });
1164
- return;
1165
- }
1166
- settle({ status: "cancelled" });
1167
- };
1168
- const onCancel = () => {
1169
- if (!confirmationStarted) settle({ status: "cancelled" });
1170
- };
1171
- const onSubmit = async (event) => {
1172
- event.preventDefault();
1173
- if (submitting || settled) return;
1174
- submitting = true;
1175
- modal.submitButton.disabled = true;
1176
- modal.error.textContent = "";
1177
- try {
1178
- const validation = elements.submit ? await elements.submit() : {};
1179
- if (validation.error) {
1180
- modal.error.textContent = validation.error.message || "Check your payment details.";
1181
- submitting = false;
1182
- modal.submitButton.disabled = false;
1183
- return;
1184
- }
1185
- if (settled || context.signal?.aborted) {
1186
- settle({ status: "cancelled" });
1187
- return;
1188
- }
1189
- confirmationStarted = true;
1190
- modal.cancelButton.disabled = true;
1191
- const confirmation = await stripe.confirmPayment({
1192
- elements,
1193
- confirmParams: { return_url: context.returnUrl || window.location.href },
1194
- redirect: "if_required"
1195
- });
1196
- if (settled) return;
1197
- if (confirmation.error) {
1198
- settle(stripeFailure(confirmation.error));
1199
- return;
1200
- }
1201
- settle({
1202
- status: "submitted",
1203
- reference: confirmation.paymentIntent?.id || context.reference
1204
- });
1205
- } catch (error) {
1206
- if (confirmationStarted) {
1207
- settle({ status: "submitted", reference: context.reference });
1208
- return;
1209
- }
1210
- settle(
1211
- stripeFailure({
1212
- message: error instanceof Error ? error.message : "Stripe confirmation failed."
1213
- })
1214
- );
1215
- }
1216
- };
1217
- modal.form.addEventListener("submit", onSubmit);
1218
- modal.cancelButton.addEventListener("click", onCancel);
1219
- context.signal?.addEventListener("abort", onAbort, { once: true });
1220
- paymentElement.on?.("escape", onCancel);
1221
- paymentElement.on?.("loaderror", (event) => {
1222
- if (confirmationStarted) return;
1223
- settle({
1224
- status: "failed",
1225
- code: "PROVIDER_UNAVAILABLE",
1226
- message: event?.error?.message || "Stripe Payment Element failed to load.",
1227
- recoverable: true
1228
- });
1229
- });
1230
- });
1231
- }
1232
- };
1233
-
1234
- // src/payment-authorization/registry.ts
1235
- function normalizeProvider(provider) {
1236
- return typeof provider === "string" ? provider.trim().toLowerCase() : "";
1378
+ };
1379
+ hub.storageListener = (event) => {
1380
+ const storageEvent = event;
1381
+ if (storageEvent.key !== SESSION_SYNC_STORAGE_KEY) return;
1382
+ const payload = parseSessionSyncPayload(storageEvent.newValue);
1383
+ if (payload) hub.dispatch(payload);
1384
+ };
1385
+ window.addEventListener("storage", hub.storageListener);
1386
+ hubHost()[CROSS_TAB_SESSION_HUB_KEY] = hub;
1387
+ return hub;
1237
1388
  }
1238
- var PaymentAuthorizationAdapterRegistry = class {
1239
- constructor(adapters = []) {
1240
- this.adapters = /* @__PURE__ */ new Map();
1241
- for (const adapter of adapters) {
1242
- this.register(adapter);
1243
- }
1244
- }
1245
- register(adapter) {
1246
- const provider = normalizeProvider(adapter.provider);
1247
- if (!provider) {
1248
- throw new TypeError("Payment authorization adapter provider cannot be empty.");
1249
- }
1250
- this.adapters.set(provider, adapter);
1251
- return this;
1252
- }
1253
- unregister(provider) {
1254
- return this.adapters.delete(normalizeProvider(provider));
1255
- }
1256
- get(provider) {
1257
- return this.adapters.get(normalizeProvider(provider));
1258
- }
1259
- supports(provider) {
1260
- return this.adapters.has(normalizeProvider(provider));
1261
- }
1262
- providers() {
1263
- return [...this.adapters.keys()];
1264
- }
1265
- async authorize(action, options) {
1266
- const provider = normalizeProvider(action.provider);
1267
- if (!provider) {
1268
- return {
1269
- status: "failed",
1270
- code: "PROVIDER_UNAVAILABLE",
1271
- message: "Card authorization response did not identify a payment provider.",
1272
- recoverable: false
1273
- };
1274
- }
1275
- const adapter = this.adapters.get(provider);
1276
- if (!adapter) {
1277
- return {
1278
- status: "failed",
1279
- code: "PROVIDER_UNAVAILABLE",
1280
- message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
1281
- recoverable: false
1282
- };
1283
- }
1284
- try {
1285
- const normalizedAction = action.provider === provider ? action : { ...action, provider };
1286
- return await adapter.authorize({ ...options, action: normalizedAction });
1287
- } catch (error) {
1288
- return {
1289
- status: "failed",
1290
- code: "PAYMENT_FAILED",
1291
- message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
1292
- recoverable: true
1293
- };
1294
- }
1389
+ function publishLocalSessionSync(payload) {
1390
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
1391
+ (currentHub() ?? createHub()).dispatch(payload);
1392
+ }
1393
+ function subscribeCrossTabSession(notify) {
1394
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") {
1395
+ return () => {
1396
+ };
1295
1397
  }
1296
- };
1297
- function createDefaultPaymentAuthorizationAdapterRegistry() {
1298
- return new PaymentAuthorizationAdapterRegistry([
1299
- new PaystackAuthorizationAdapter(),
1300
- new StripeAuthorizationAdapter()
1301
- ]);
1398
+ const hub = currentHub() ?? createHub();
1399
+ pruneSubscribers(hub);
1400
+ const token = /* @__PURE__ */ Symbol("cross-tab-session-subscriber");
1401
+ const subscriber = { notify };
1402
+ hub.subscribers.set(token, subscriberReference(subscriber));
1403
+ let unsubscribed = false;
1404
+ return () => {
1405
+ if (unsubscribed) return;
1406
+ unsubscribed = true;
1407
+ subscriber.notify = () => {
1408
+ };
1409
+ hub.subscribers.delete(token);
1410
+ pruneSubscribers(hub);
1411
+ if (hub.subscribers.size !== 0) return;
1412
+ window.removeEventListener("storage", hub.storageListener);
1413
+ if (currentHub() === hub) delete hubHost()[CROSS_TAB_SESSION_HUB_KEY];
1414
+ };
1302
1415
  }
1303
1416
 
1304
1417
  // src/client.ts
1305
1418
  var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
1306
- var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
1307
1419
  var ORDER_TOKEN_PREFIX = "cimplify_ot_";
1308
1420
  var SESSION_TOKEN_HEADER = "x-session-token";
1309
1421
  var LOCATION_ID_QUERY_PARAMETER = "location_id";
@@ -1311,8 +1423,37 @@ var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
1311
1423
  var DEFAULT_TIMEOUT_MS = 5e3;
1312
1424
  var DEFAULT_MAX_RETRIES = 3;
1313
1425
  var DEFAULT_RETRY_DELAY_MS = 1e3;
1314
- function sleep(ms) {
1315
- return new Promise((resolve) => setTimeout(resolve, ms));
1426
+ var MAX_RETRY_AFTER_MS = 3e4;
1427
+ function sleep(ms, signal) {
1428
+ if (signal?.aborted) {
1429
+ return Promise.reject(new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.CANCELLED, "Request was cancelled.", true));
1430
+ }
1431
+ return new Promise((resolve, reject) => {
1432
+ const timer = setTimeout(() => {
1433
+ signal?.removeEventListener("abort", onAbort);
1434
+ resolve();
1435
+ }, ms);
1436
+ const onAbort = () => {
1437
+ clearTimeout(timer);
1438
+ reject(new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.CANCELLED, "Request was cancelled.", true));
1439
+ };
1440
+ signal?.addEventListener("abort", onAbort, { once: true });
1441
+ });
1442
+ }
1443
+ function parseRetryAfterMs(value) {
1444
+ if (!value) return null;
1445
+ const seconds = Number(value);
1446
+ if (Number.isFinite(seconds) && seconds >= 0) {
1447
+ return Math.min(seconds * 1e3, MAX_RETRY_AFTER_MS);
1448
+ }
1449
+ const retryAt = Date.parse(value);
1450
+ if (!Number.isFinite(retryAt)) return null;
1451
+ return Math.min(Math.max(0, retryAt - Date.now()), MAX_RETRY_AFTER_MS);
1452
+ }
1453
+ function withPositiveJitter(delayMs, jitterRatio = 0) {
1454
+ const boundedRatio = Math.min(Math.max(jitterRatio, 0), 1);
1455
+ if (boundedRatio === 0 || delayMs === 0) return delayMs;
1456
+ return Math.round(delayMs + delayMs * boundedRatio * Math.random());
1316
1457
  }
1317
1458
  function nextInit(cacheOptions) {
1318
1459
  if (!cacheOptions) return {};
@@ -1352,16 +1493,16 @@ function isRetryable(error) {
1352
1493
  if (error instanceof DOMException && error.name === "AbortError") {
1353
1494
  return true;
1354
1495
  }
1355
- if (error instanceof chunk4BKOKHE3_js.CimplifyError) {
1496
+ if (error instanceof chunkSFUJMS5E_js.CimplifyError) {
1356
1497
  return error.retryable;
1357
1498
  }
1358
1499
  return false;
1359
1500
  }
1360
1501
  function toNetworkError(error, isTestMode) {
1361
1502
  if (error instanceof DOMException && error.name === "AbortError") {
1362
- return chunk4BKOKHE3_js.enrichError(
1363
- new chunk4BKOKHE3_js.CimplifyError(
1364
- chunk4BKOKHE3_js.ErrorCode.TIMEOUT,
1503
+ return chunkSFUJMS5E_js.enrichError(
1504
+ new chunkSFUJMS5E_js.CimplifyError(
1505
+ chunkSFUJMS5E_js.ErrorCode.TIMEOUT,
1365
1506
  "Request timed out. Please check your connection and try again.",
1366
1507
  true
1367
1508
  ),
@@ -1369,21 +1510,21 @@ function toNetworkError(error, isTestMode) {
1369
1510
  );
1370
1511
  }
1371
1512
  if (error instanceof TypeError && error.message.includes("fetch")) {
1372
- return chunk4BKOKHE3_js.enrichError(
1373
- new chunk4BKOKHE3_js.CimplifyError(
1374
- chunk4BKOKHE3_js.ErrorCode.NETWORK_ERROR,
1513
+ return chunkSFUJMS5E_js.enrichError(
1514
+ new chunkSFUJMS5E_js.CimplifyError(
1515
+ chunkSFUJMS5E_js.ErrorCode.NETWORK_ERROR,
1375
1516
  "Network error. Please check your internet connection.",
1376
1517
  true
1377
1518
  ),
1378
1519
  { isTestMode }
1379
1520
  );
1380
1521
  }
1381
- if (error instanceof chunk4BKOKHE3_js.CimplifyError) {
1382
- return chunk4BKOKHE3_js.enrichError(error, { isTestMode });
1522
+ if (error instanceof chunkSFUJMS5E_js.CimplifyError) {
1523
+ return chunkSFUJMS5E_js.enrichError(error, { isTestMode });
1383
1524
  }
1384
- return chunk4BKOKHE3_js.enrichError(
1385
- new chunk4BKOKHE3_js.CimplifyError(
1386
- chunk4BKOKHE3_js.ErrorCode.UNKNOWN_ERROR,
1525
+ return chunkSFUJMS5E_js.enrichError(
1526
+ new chunkSFUJMS5E_js.CimplifyError(
1527
+ chunkSFUJMS5E_js.ErrorCode.UNKNOWN_ERROR,
1387
1528
  error instanceof Error ? error.message : "An unknown error occurred",
1388
1529
  false
1389
1530
  ),
@@ -1426,6 +1567,9 @@ var CimplifyClient = class {
1426
1567
  this.businessId = null;
1427
1568
  this.businessIdResolvePromise = null;
1428
1569
  this.publicKeyEpoch = 0;
1570
+ this.stopCrossTabSessionWatch = null;
1571
+ this.latestSessionSyncAt = Number.NEGATIVE_INFINITY;
1572
+ this.latestSessionSyncOrderKey = null;
1429
1573
  this.inflightRequests = /* @__PURE__ */ new Map();
1430
1574
  /**
1431
1575
  * App-level event channel. Subscribe to surface mutation rollbacks, outbox
@@ -1444,10 +1588,14 @@ var CimplifyClient = class {
1444
1588
  this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
1445
1589
  this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
1446
1590
  this.hooks = config.hooks ?? {};
1447
- this.authorizationAdapters = config.authorizationAdapterRegistry ?? createDefaultPaymentAuthorizationAdapterRegistry();
1591
+ this.authorizationAdapters = config.authorizationAdapterRegistry ?? chunkDQEXY542_js.createDefaultPaymentAuthorizationAdapterRegistry();
1448
1592
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
1449
1593
  this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
1450
- this.watchCrossTabSession();
1594
+ const persistedSessionSync = this.loadSessionSyncPayload();
1595
+ if (persistedSessionSync) this.observeSessionSync(persistedSessionSync);
1596
+ this.stopCrossTabSessionWatch = subscribeCrossTabSession((payload) => {
1597
+ this.applyCrossTabSession(payload);
1598
+ });
1451
1599
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
1452
1600
  console.warn(
1453
1601
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -1474,6 +1622,12 @@ var CimplifyClient = class {
1474
1622
  this.stopPageViewTracking?.();
1475
1623
  this.stopPageViewTracking = null;
1476
1624
  }
1625
+ /** Release window-level subscriptions and automatic tracking owned by this client. */
1626
+ destroy() {
1627
+ this.stopTrackingPageViews();
1628
+ this.stopCrossTabSessionWatch?.();
1629
+ this.stopCrossTabSessionWatch = null;
1630
+ }
1477
1631
  getAccessToken() {
1478
1632
  return this.accessToken;
1479
1633
  }
@@ -1501,7 +1655,7 @@ var CimplifyClient = class {
1501
1655
  this.hooks.onSessionChange?.({
1502
1656
  previousToken: previous,
1503
1657
  newToken: token,
1504
- source: "manual"
1658
+ source: SESSION_CHANGE_SOURCE.MANUAL
1505
1659
  });
1506
1660
  this.events.emit(AUTH_TOKEN_CHANGED, { token });
1507
1661
  }
@@ -1545,7 +1699,7 @@ var CimplifyClient = class {
1545
1699
  this.hooks.onSessionChange?.({
1546
1700
  previousToken: previous,
1547
1701
  newToken: null,
1548
- source: "clear"
1702
+ source: SESSION_CHANGE_SOURCE.CLEAR
1549
1703
  });
1550
1704
  this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
1551
1705
  this.events.emit(SESSION_CLEARED, {});
@@ -1567,9 +1721,10 @@ var CimplifyClient = class {
1567
1721
  hasClaimedSessionAuthority() {
1568
1722
  if (!this.sessionToken) return false;
1569
1723
  try {
1570
- const raw = this.safeStorage()?.getItem(SESSION_SYNC_STORAGE_KEY);
1571
- if (!raw) return false;
1572
- const payload = JSON.parse(raw);
1724
+ const payload = parseSessionSyncPayload(
1725
+ this.safeStorage()?.getItem(SESSION_SYNC_STORAGE_KEY) ?? null
1726
+ );
1727
+ if (!payload) return false;
1573
1728
  return payload.type === "claimed" && payload.token === this.sessionToken;
1574
1729
  } catch {
1575
1730
  return false;
@@ -1584,41 +1739,49 @@ var CimplifyClient = class {
1584
1739
  });
1585
1740
  }
1586
1741
  broadcastSessionSync(payload) {
1742
+ const envelope = {
1743
+ ...payload,
1744
+ at: this.nextSessionSyncTimestamp()
1745
+ };
1587
1746
  try {
1588
- this.safeStorage()?.setItem(
1589
- SESSION_SYNC_STORAGE_KEY,
1590
- JSON.stringify({ ...payload, at: Date.now() })
1591
- );
1747
+ this.safeStorage()?.setItem(SESSION_SYNC_STORAGE_KEY, JSON.stringify(envelope));
1592
1748
  } catch {
1593
1749
  }
1750
+ publishLocalSessionSync(envelope);
1594
1751
  }
1595
- watchCrossTabSession() {
1596
- if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
1597
- window.addEventListener("storage", (event) => {
1598
- if (event.key !== SESSION_SYNC_STORAGE_KEY || !event.newValue) return;
1599
- let payload;
1600
- try {
1601
- payload = JSON.parse(event.newValue);
1602
- } catch {
1603
- return;
1604
- }
1605
- if (!payload?.token || payload.token === this.sessionToken) return;
1606
- if (payload.type === "claimed") {
1607
- this.sessionToken = payload.token;
1608
- this.sessionEpoch++;
1609
- this.events.emit(SESSION_CLAIMED, {
1610
- sessionToken: payload.token,
1611
- threadId: null,
1612
- customerName: payload.name ?? ""
1613
- });
1614
- } else if (payload.type === "cleared") {
1615
- this.accessToken = null;
1616
- this.sessionToken = payload.token;
1617
- this.sessionEpoch++;
1618
- this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
1619
- this.events.emit(SESSION_CLEARED, {});
1620
- }
1621
- });
1752
+ applyCrossTabSession(payload) {
1753
+ if (!this.observeSessionSync(payload)) return;
1754
+ if (payload.token === this.sessionToken) return;
1755
+ if (payload.type === "claimed") {
1756
+ this.sessionToken = payload.token;
1757
+ this.sessionEpoch++;
1758
+ this.events.emit(SESSION_CLAIMED, {
1759
+ sessionToken: payload.token,
1760
+ threadId: null,
1761
+ customerName: payload.name ?? ""
1762
+ });
1763
+ } else {
1764
+ this.accessToken = null;
1765
+ this._activity?.resetSession();
1766
+ this.sessionToken = payload.token;
1767
+ this.sessionEpoch++;
1768
+ this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
1769
+ this.events.emit(SESSION_CLEARED, {});
1770
+ }
1771
+ }
1772
+ observeSessionSync(payload) {
1773
+ if (payload.at < this.latestSessionSyncAt) return false;
1774
+ const envelope = sessionSyncEnvelopeKey(payload);
1775
+ if (payload.at === this.latestSessionSyncAt && this.latestSessionSyncOrderKey !== null && envelope <= this.latestSessionSyncOrderKey) {
1776
+ return false;
1777
+ }
1778
+ this.latestSessionSyncAt = payload.at;
1779
+ this.latestSessionSyncOrderKey = envelope;
1780
+ return true;
1781
+ }
1782
+ nextSessionSyncTimestamp() {
1783
+ const now = Date.now();
1784
+ return Number.isFinite(this.latestSessionSyncAt) ? Math.max(now, this.latestSessionSyncAt + 1) : now;
1622
1785
  }
1623
1786
  setOrderToken(orderId, token) {
1624
1787
  try {
@@ -1682,17 +1845,24 @@ var CimplifyClient = class {
1682
1845
  setPublicKey(publicKey) {
1683
1846
  const normalized = publicKey.trim();
1684
1847
  if (normalized === this.publicKey) return;
1848
+ const restartPageViewTracking = this.stopPageViewTracking !== null;
1849
+ if (restartPageViewTracking) {
1850
+ this.stopTrackingPageViews();
1851
+ }
1685
1852
  this.publicKey = normalized;
1686
1853
  this.publicKeyEpoch += 1;
1687
1854
  this.businessId = null;
1688
1855
  this.businessIdResolvePromise = null;
1689
1856
  this.inflightRequests.clear();
1690
- this._activity?.resetSession();
1857
+ this._activity?.resetForStorefrontIdentityChange();
1691
1858
  delete this.context.location_id;
1692
1859
  if (this.accessToken !== null) {
1693
1860
  this.setAccessToken(null);
1694
1861
  }
1695
1862
  this.events.emit(SESSION_CLEARED, {});
1863
+ if (restartPageViewTracking) {
1864
+ this.stopPageViewTracking = this.activity.autoTrackPageViews();
1865
+ }
1696
1866
  }
1697
1867
  getBusinessId() {
1698
1868
  return this.businessId;
@@ -1708,15 +1878,15 @@ var CimplifyClient = class {
1708
1878
  const resolution = (async () => {
1709
1879
  const result = await this.business.getInfo();
1710
1880
  if (!result.ok || !result.value?.id) {
1711
- throw new chunk4BKOKHE3_js.CimplifyError(
1712
- chunk4BKOKHE3_js.ErrorCode.NOT_FOUND,
1881
+ throw new chunkSFUJMS5E_js.CimplifyError(
1882
+ chunkSFUJMS5E_js.ErrorCode.NOT_FOUND,
1713
1883
  "Unable to resolve business ID from the current public key.",
1714
1884
  true
1715
1885
  );
1716
1886
  }
1717
1887
  if (this.publicKeyEpoch !== publicKeyEpoch) {
1718
- throw new chunk4BKOKHE3_js.CimplifyError(
1719
- chunk4BKOKHE3_js.ErrorCode.TENANT_CONTEXT_CHANGED,
1888
+ throw new chunkSFUJMS5E_js.CimplifyError(
1889
+ chunkSFUJMS5E_js.ErrorCode.TENANT_CONTEXT_CHANGED,
1720
1890
  "The storefront tenant changed while resolving its business identity.",
1721
1891
  true
1722
1892
  );
@@ -1733,8 +1903,8 @@ var CimplifyClient = class {
1733
1903
  }
1734
1904
  }
1735
1905
  }
1736
- async authedFetch(url, options, timeoutMs) {
1737
- return this.resilientFetch(url, options, timeoutMs);
1906
+ async authedFetch(url, options, timeoutMs, retryPolicy, signal) {
1907
+ return this.resilientFetch(url, options, timeoutMs, retryPolicy, signal);
1738
1908
  }
1739
1909
  // Storage guards: even the `window.localStorage` property access throws in
1740
1910
  // some sandboxed iframes and strict private-browsing modes. These run in the
@@ -1756,6 +1926,13 @@ var CimplifyClient = class {
1756
1926
  return null;
1757
1927
  }
1758
1928
  }
1929
+ loadSessionSyncPayload() {
1930
+ try {
1931
+ return parseSessionSyncPayload(this.safeStorage()?.getItem(SESSION_SYNC_STORAGE_KEY) ?? null);
1932
+ } catch {
1933
+ return null;
1934
+ }
1935
+ }
1759
1936
  /**
1760
1937
  * Mint the session token client-side so the very first request already
1761
1938
  * carries it. Without this, parallel first-load requests each get a
@@ -1811,7 +1988,7 @@ var CimplifyClient = class {
1811
1988
  }
1812
1989
  return headers;
1813
1990
  }
1814
- async resilientFetch(url, options, timeoutMs) {
1991
+ async resilientFetch(url, options, timeoutMs, retryPolicy, signal) {
1815
1992
  const method = options.method || "GET";
1816
1993
  const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
1817
1994
  const startTime = Date.now();
@@ -1825,15 +2002,31 @@ var CimplifyClient = class {
1825
2002
  };
1826
2003
  this.hooks.onRequestStart?.(context);
1827
2004
  let lastError;
1828
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
2005
+ const configuredMaxRetries = Math.max(0, Math.floor(this.maxRetries));
2006
+ const maxRetries = Math.min(
2007
+ configuredMaxRetries,
2008
+ Math.max(0, Math.floor(retryPolicy?.maxRetries ?? configuredMaxRetries))
2009
+ );
2010
+ const jitterRatio = retryPolicy?.jitterRatio ?? 0;
2011
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1829
2012
  try {
2013
+ if (signal?.aborted) {
2014
+ throw new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.CANCELLED, "Request was cancelled.", true);
2015
+ }
1830
2016
  const controller = new AbortController();
1831
2017
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs ?? this.timeout);
1832
- const response = await this.fetchImpl(url, {
1833
- ...options,
1834
- signal: controller.signal
1835
- });
1836
- clearTimeout(timeoutId);
2018
+ const onAbort = () => controller.abort();
2019
+ signal?.addEventListener("abort", onAbort, { once: true });
2020
+ let response;
2021
+ try {
2022
+ response = await this.fetchImpl(url, {
2023
+ ...options,
2024
+ signal: controller.signal
2025
+ });
2026
+ } finally {
2027
+ clearTimeout(timeoutId);
2028
+ signal?.removeEventListener("abort", onAbort);
2029
+ }
1837
2030
  this.captureSessionToken(response);
1838
2031
  if (response.ok) {
1839
2032
  this.hooks.onRequestSuccess?.({
@@ -1843,23 +2036,25 @@ var CimplifyClient = class {
1843
2036
  });
1844
2037
  return response;
1845
2038
  }
1846
- if ((response.status === 429 || response.status === 503) && attempt < this.maxRetries) {
2039
+ if ((response.status === 429 || response.status === 503) && attempt < maxRetries) {
1847
2040
  retryCount++;
1848
- const retryAfter = response.headers.get("Retry-After");
1849
- const delay = retryAfter ? Math.min(parseInt(retryAfter, 10) * 1e3, 3e4) || this.retryDelay * Math.pow(2, attempt) : this.retryDelay * Math.pow(2, attempt);
2041
+ const retryAfterMs = parseRetryAfterMs(response.headers.get("Retry-After"));
2042
+ const retryBaseMs = retryAfterMs ?? this.retryDelay * Math.pow(2, attempt);
2043
+ const jitteredDelayMs = withPositiveJitter(retryBaseMs, jitterRatio);
2044
+ const delay = retryAfterMs === null ? jitteredDelayMs : Math.min(jitteredDelayMs, MAX_RETRY_AFTER_MS);
1850
2045
  this.hooks.onRetry?.({
1851
2046
  ...context,
1852
2047
  attempt: retryCount,
1853
2048
  delayMs: delay,
1854
2049
  error: new Error(`Retryable: ${response.status}`)
1855
2050
  });
1856
- await sleep(delay);
2051
+ await sleep(delay, signal);
1857
2052
  continue;
1858
2053
  }
1859
2054
  if (response.status >= 400 && response.status < 500) {
1860
2055
  this.hooks.onRequestError?.({
1861
2056
  ...context,
1862
- error: new chunk4BKOKHE3_js.CimplifyError(
2057
+ error: new chunkSFUJMS5E_js.CimplifyError(
1863
2058
  `HTTP_${response.status}`,
1864
2059
  `Request failed with status ${response.status}`,
1865
2060
  false
@@ -1871,22 +2066,22 @@ var CimplifyClient = class {
1871
2066
  });
1872
2067
  return response;
1873
2068
  }
1874
- if (response.status >= 500 && attempt < this.maxRetries) {
2069
+ if (response.status >= 500 && attempt < maxRetries) {
1875
2070
  retryCount++;
1876
- const delay = this.retryDelay * Math.pow(2, attempt);
2071
+ const delay = withPositiveJitter(this.retryDelay * Math.pow(2, attempt), jitterRatio);
1877
2072
  this.hooks.onRetry?.({
1878
2073
  ...context,
1879
2074
  attempt: retryCount,
1880
2075
  delayMs: delay,
1881
2076
  error: new Error(`Server error: ${response.status}`)
1882
2077
  });
1883
- await sleep(delay);
2078
+ await sleep(delay, signal);
1884
2079
  continue;
1885
2080
  }
1886
2081
  this.hooks.onRequestError?.({
1887
2082
  ...context,
1888
- error: new chunk4BKOKHE3_js.CimplifyError(
1889
- "SERVER_ERROR",
2083
+ error: new chunkSFUJMS5E_js.CimplifyError(
2084
+ chunkSFUJMS5E_js.ErrorCode.SERVER_ERROR,
1890
2085
  `Server error ${response.status} after ${retryCount} retries`,
1891
2086
  false
1892
2087
  ),
@@ -1898,9 +2093,12 @@ var CimplifyClient = class {
1898
2093
  return response;
1899
2094
  } catch (error) {
1900
2095
  lastError = error;
2096
+ if (signal?.aborted) {
2097
+ throw new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.CANCELLED, "Request was cancelled.", true);
2098
+ }
1901
2099
  const networkError = toNetworkError(error, this.isTestMode());
1902
2100
  const errorRetryable = isRetryable(error);
1903
- if (!errorRetryable || attempt >= this.maxRetries) {
2101
+ if (!errorRetryable || attempt >= maxRetries) {
1904
2102
  this.hooks.onRequestError?.({
1905
2103
  ...context,
1906
2104
  error: networkError,
@@ -1911,14 +2109,14 @@ var CimplifyClient = class {
1911
2109
  throw networkError;
1912
2110
  }
1913
2111
  retryCount++;
1914
- const delay = this.retryDelay * Math.pow(2, attempt);
2112
+ const delay = withPositiveJitter(this.retryDelay * Math.pow(2, attempt), jitterRatio);
1915
2113
  this.hooks.onRetry?.({
1916
2114
  ...context,
1917
2115
  attempt: retryCount,
1918
2116
  delayMs: delay,
1919
2117
  error: networkError
1920
2118
  });
1921
- await sleep(delay);
2119
+ await sleep(delay, signal);
1922
2120
  }
1923
2121
  }
1924
2122
  const finalError = toNetworkError(lastError, this.isTestMode());
@@ -1955,16 +2153,24 @@ var CimplifyClient = class {
1955
2153
  return request;
1956
2154
  }
1957
2155
  async get(path, opts) {
1958
- const key = this.getDedupeKey("get", path, opts?.cacheOptions);
1959
- return this.deduplicatedRequest(key, async () => {
1960
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
1961
- method: "GET",
1962
- credentials: this.credentials,
1963
- headers: this.getHeaders(),
1964
- ...nextInit(opts?.cacheOptions)
1965
- });
2156
+ const request = async () => {
2157
+ const response = await this.authedFetch(
2158
+ this.buildUrl(this.baseUrl, path),
2159
+ {
2160
+ method: "GET",
2161
+ credentials: this.credentials,
2162
+ headers: this.getHeaders(),
2163
+ ...nextInit(opts?.cacheOptions)
2164
+ },
2165
+ opts?.timeoutMs,
2166
+ opts?.retryPolicy,
2167
+ opts?.signal
2168
+ );
1966
2169
  return this.handleRestResponse(response);
1967
- });
2170
+ };
2171
+ if (opts?.signal) return request();
2172
+ const key = this.getDedupeKey("get", path, opts?.cacheOptions);
2173
+ return this.deduplicatedRequest(key, request);
1968
2174
  }
1969
2175
  async post(path, body, opts) {
1970
2176
  const response = await this.authedFetch(
@@ -1975,7 +2181,9 @@ var CimplifyClient = class {
1975
2181
  headers: mergeOptionHeaders(this.getHeaders(), opts),
1976
2182
  body: body ? JSON.stringify(body) : void 0
1977
2183
  },
1978
- opts?.timeoutMs
2184
+ opts?.timeoutMs,
2185
+ opts?.retryPolicy,
2186
+ opts?.signal
1979
2187
  );
1980
2188
  return this.handleRestResponse(response);
1981
2189
  }
@@ -1988,7 +2196,9 @@ var CimplifyClient = class {
1988
2196
  headers: mergeOptionHeaders(this.getHeaders(), opts),
1989
2197
  body: body ? JSON.stringify(body) : void 0
1990
2198
  },
1991
- opts?.timeoutMs
2199
+ opts?.timeoutMs,
2200
+ opts?.retryPolicy,
2201
+ opts?.signal
1992
2202
  );
1993
2203
  return this.handleRestResponse(response);
1994
2204
  }
@@ -2000,21 +2210,31 @@ var CimplifyClient = class {
2000
2210
  credentials: this.credentials,
2001
2211
  headers: mergeOptionHeaders(this.getHeaders(), opts)
2002
2212
  },
2003
- opts?.timeoutMs
2213
+ opts?.timeoutMs,
2214
+ opts?.retryPolicy,
2215
+ opts?.signal
2004
2216
  );
2005
2217
  return this.handleRestResponse(response);
2006
2218
  }
2007
2219
  async linkGet(path, opts) {
2008
- const key = this.getDedupeKey("linkGet", path, opts?.cacheOptions);
2009
- return this.deduplicatedRequest(key, async () => {
2010
- const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
2011
- method: "GET",
2012
- credentials: this.credentials,
2013
- headers: this.getHeaders(),
2014
- ...nextInit(opts?.cacheOptions)
2015
- });
2220
+ const request = async () => {
2221
+ const response = await this.authedFetch(
2222
+ `${this.linkApiUrl}${path}`,
2223
+ {
2224
+ method: "GET",
2225
+ credentials: this.credentials,
2226
+ headers: this.getHeaders(),
2227
+ ...nextInit(opts?.cacheOptions)
2228
+ },
2229
+ opts?.timeoutMs,
2230
+ opts?.retryPolicy,
2231
+ opts?.signal
2232
+ );
2016
2233
  return this.handleRestResponse(response);
2017
- });
2234
+ };
2235
+ if (opts?.signal) return request();
2236
+ const key = this.getDedupeKey("linkGet", path, opts?.cacheOptions);
2237
+ return this.deduplicatedRequest(key, request);
2018
2238
  }
2019
2239
  async linkPost(path, body, opts) {
2020
2240
  const response = await this.authedFetch(
@@ -2025,32 +2245,40 @@ var CimplifyClient = class {
2025
2245
  headers: mergeOptionHeaders(this.getHeaders(), opts),
2026
2246
  body: body ? JSON.stringify(body) : void 0
2027
2247
  },
2028
- opts?.timeoutMs
2248
+ opts?.timeoutMs,
2249
+ opts?.retryPolicy,
2250
+ opts?.signal
2029
2251
  );
2030
2252
  return this.handleRestResponse(response);
2031
2253
  }
2032
2254
  async linkDelete(path, opts) {
2033
- const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
2034
- method: "DELETE",
2035
- credentials: this.credentials,
2036
- headers: mergeOptionHeaders(this.getHeaders(), opts)
2037
- });
2255
+ const response = await this.authedFetch(
2256
+ `${this.linkApiUrl}${path}`,
2257
+ {
2258
+ method: "DELETE",
2259
+ credentials: this.credentials,
2260
+ headers: mergeOptionHeaders(this.getHeaders(), opts)
2261
+ },
2262
+ opts?.timeoutMs,
2263
+ opts?.retryPolicy,
2264
+ opts?.signal
2265
+ );
2038
2266
  return this.handleRestResponse(response);
2039
2267
  }
2040
2268
  async handleRestResponse(response) {
2041
2269
  const json = await response.json();
2042
2270
  if (!response.ok) {
2043
- const errorCode = typeof json.error === "object" && json.error?.error_code || typeof json.error === "object" && json.error?.code || "API_ERROR";
2271
+ const errorCode = typeof json.error === "object" && json.error?.error_code || typeof json.error === "object" && json.error?.code || chunkSFUJMS5E_js.ErrorCode.API_ERROR;
2044
2272
  const errorMessage = typeof json.error === "object" && json.error?.error_message || typeof json.error === "object" && json.error?.message || typeof json.error === "string" && json.error || typeof json.message === "string" && json.message || "An error occurred";
2045
2273
  const retryable = typeof json.error === "object" && typeof json.error?.retryable === "boolean" ? json.error.retryable : false;
2046
- if (errorCode === "IDEMPOTENCY_MISMATCH") {
2274
+ if (errorCode === chunkSFUJMS5E_js.ErrorCode.IDEMPOTENCY_MISMATCH) {
2047
2275
  const originalCreatedAt = typeof json.error === "object" && json.error?.original_created_at || "";
2048
- throw new chunk4BKOKHE3_js.IdempotencyMismatchError(errorMessage, originalCreatedAt);
2276
+ throw new chunkSFUJMS5E_js.IdempotencyMismatchError(errorMessage, originalCreatedAt);
2049
2277
  }
2050
- const error = chunk4BKOKHE3_js.enrichError(new chunk4BKOKHE3_js.CimplifyError(errorCode, errorMessage, retryable), {
2278
+ const error = chunkSFUJMS5E_js.enrichError(new chunkSFUJMS5E_js.CimplifyError(errorCode, errorMessage, retryable), {
2051
2279
  isTestMode: this.isTestMode()
2052
2280
  });
2053
- if ((response.status === 401 || error.code === chunk4BKOKHE3_js.ErrorCode.UNAUTHORIZED) && this.accessToken) {
2281
+ if ((response.status === 401 || error.code === chunkSFUJMS5E_js.ErrorCode.UNAUTHORIZED) && this.accessToken) {
2054
2282
  console.warn(
2055
2283
  "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
2056
2284
  );
@@ -2058,9 +2286,9 @@ var CimplifyClient = class {
2058
2286
  throw error;
2059
2287
  }
2060
2288
  if (json?.success === false || json?.error?.code || json?.error?.message) {
2061
- const error = chunk4BKOKHE3_js.enrichError(
2062
- new chunk4BKOKHE3_js.CimplifyError(
2063
- json.error?.code || "API_ERROR",
2289
+ const error = chunkSFUJMS5E_js.enrichError(
2290
+ new chunkSFUJMS5E_js.CimplifyError(
2291
+ json.error?.code || chunkSFUJMS5E_js.ErrorCode.API_ERROR,
2064
2292
  json.error?.message || "An error occurred",
2065
2293
  json.error?.retryable || false
2066
2294
  ),
@@ -2075,25 +2303,31 @@ var CimplifyClient = class {
2075
2303
  }
2076
2304
  get catalogue() {
2077
2305
  if (!this._catalogue) {
2078
- this._catalogue = new chunkIQFFSKE2_js.CatalogueQueries(this);
2306
+ this._catalogue = new chunkDQEXY542_js.CatalogueQueries(this);
2079
2307
  }
2080
2308
  return this._catalogue;
2081
2309
  }
2082
2310
  get cart() {
2083
2311
  if (!this._cart) {
2084
- this._cart = new chunkIQFFSKE2_js.CartOperations(this);
2312
+ this._cart = new chunkDQEXY542_js.CartOperations(this);
2085
2313
  }
2086
2314
  return this._cart;
2087
2315
  }
2088
2316
  get checkout() {
2089
2317
  if (!this._checkout) {
2090
- this._checkout = new chunkIQFFSKE2_js.CheckoutService(this);
2318
+ this._checkout = new chunkDQEXY542_js.CheckoutService(this);
2091
2319
  }
2092
2320
  return this._checkout;
2093
2321
  }
2322
+ get purchaseIntents() {
2323
+ if (!this._purchaseIntents) {
2324
+ this._purchaseIntents = new PurchaseIntentService(this);
2325
+ }
2326
+ return this._purchaseIntents;
2327
+ }
2094
2328
  get orders() {
2095
2329
  if (!this._orders) {
2096
- this._orders = new chunkIQFFSKE2_js.OrderQueries(this);
2330
+ this._orders = new chunkDQEXY542_js.OrderQueries(this);
2097
2331
  }
2098
2332
  return this._orders;
2099
2333
  }
@@ -2123,43 +2357,43 @@ var CimplifyClient = class {
2123
2357
  }
2124
2358
  get link() {
2125
2359
  if (!this._link) {
2126
- this._link = new chunkIQFFSKE2_js.LinkService(this);
2360
+ this._link = new chunkDQEXY542_js.LinkService(this);
2127
2361
  }
2128
2362
  return this._link;
2129
2363
  }
2130
2364
  get auth() {
2131
2365
  if (!this._auth) {
2132
- this._auth = new chunkIQFFSKE2_js.AuthService(this);
2366
+ this._auth = new chunkDQEXY542_js.AuthService(this);
2133
2367
  }
2134
2368
  return this._auth;
2135
2369
  }
2136
2370
  get business() {
2137
2371
  if (!this._business) {
2138
- this._business = new chunkIQFFSKE2_js.BusinessService(this);
2372
+ this._business = new chunkDQEXY542_js.BusinessService(this);
2139
2373
  }
2140
2374
  return this._business;
2141
2375
  }
2142
2376
  get inventory() {
2143
2377
  if (!this._inventory) {
2144
- this._inventory = new chunkIQFFSKE2_js.InventoryService(this);
2378
+ this._inventory = new chunkDQEXY542_js.InventoryService(this);
2145
2379
  }
2146
2380
  return this._inventory;
2147
2381
  }
2148
2382
  get scheduling() {
2149
2383
  if (!this._scheduling) {
2150
- this._scheduling = new chunkIQFFSKE2_js.SchedulingService(this);
2384
+ this._scheduling = new chunkDQEXY542_js.SchedulingService(this);
2151
2385
  }
2152
2386
  return this._scheduling;
2153
2387
  }
2154
2388
  get lite() {
2155
2389
  if (!this._lite) {
2156
- this._lite = new chunkIQFFSKE2_js.LiteService(this);
2390
+ this._lite = new chunkDQEXY542_js.LiteService(this);
2157
2391
  }
2158
2392
  return this._lite;
2159
2393
  }
2160
2394
  get fx() {
2161
2395
  if (!this._fx) {
2162
- this._fx = new chunkIQFFSKE2_js.FxService(this);
2396
+ this._fx = new chunkDQEXY542_js.FxService(this);
2163
2397
  }
2164
2398
  return this._fx;
2165
2399
  }
@@ -2194,7 +2428,7 @@ var CimplifyClient = class {
2194
2428
  if (businessId) {
2195
2429
  this.setBusinessId(businessId);
2196
2430
  }
2197
- return chunkIQFFSKE2_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
2431
+ return chunkDQEXY542_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
2198
2432
  }
2199
2433
  };
2200
2434
  function createCimplifyClient(config = {}) {
@@ -2205,17 +2439,18 @@ exports.AUTH_TOKEN_CHANGED = AUTH_TOKEN_CHANGED;
2205
2439
  exports.ActivityService = ActivityService;
2206
2440
  exports.CimplifyClient = CimplifyClient;
2207
2441
  exports.DeliveryService = DeliveryService;
2442
+ exports.HostedPurchaseIntentService = HostedPurchaseIntentService;
2208
2443
  exports.MUTATION_ERROR = MUTATION_ERROR;
2209
- exports.PaymentAuthorizationAdapterRegistry = PaymentAuthorizationAdapterRegistry;
2210
- exports.PaystackAuthorizationAdapter = PaystackAuthorizationAdapter;
2444
+ exports.PURCHASE_INTENT_ROUTE = PURCHASE_INTENT_ROUTE;
2211
2445
  exports.PlacesService = PlacesService;
2446
+ exports.PurchaseIntentResolver = PurchaseIntentResolver;
2447
+ exports.PurchaseIntentService = PurchaseIntentService;
2448
+ exports.SESSION_CHANGE_SOURCE = SESSION_CHANGE_SOURCE;
2212
2449
  exports.SESSION_CLAIMED = SESSION_CLAIMED;
2213
2450
  exports.SESSION_CLEARED = SESSION_CLEARED;
2214
2451
  exports.StoreCreditQueries = StoreCreditQueries;
2215
- exports.StripeAuthorizationAdapter = StripeAuthorizationAdapter;
2216
2452
  exports.SubscriptionService = SubscriptionService;
2217
2453
  exports.SupportService = SupportService;
2218
2454
  exports.UploadService = UploadService;
2219
2455
  exports.chatRealtimeUpdateFromWire = chatRealtimeUpdateFromWire;
2220
2456
  exports.createCimplifyClient = createCimplifyClient;
2221
- exports.createDefaultPaymentAuthorizationAdapterRegistry = createDefaultPaymentAuthorizationAdapterRegistry;