@cimplify/sdk 0.92.0 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/advanced.d.mts +3 -3
  2. package/dist/advanced.d.ts +3 -3
  3. package/dist/advanced.js +20 -20
  4. package/dist/advanced.mjs +1 -1
  5. package/dist/{chunk-OAHSF542.js → chunk-6Y7KC5YZ.js} +11 -0
  6. package/dist/{chunk-3MBMIEWT.js → chunk-AWNWP5J3.js} +4 -4
  7. package/dist/{chunk-3XD2FVP4.mjs → chunk-FKARGZK3.mjs} +195 -60
  8. package/dist/{chunk-DCRN67NO.js → chunk-QLGZIBRO.js} +237 -102
  9. package/dist/{chunk-54H2YYIW.mjs → chunk-QXWX7CD2.mjs} +2 -2
  10. package/dist/{chunk-IVJEUGWF.js → chunk-VEOAMBEX.js} +1 -3
  11. package/dist/{chunk-T7LDBZZZ.mjs → chunk-VUSHG3HA.mjs} +1 -3
  12. package/dist/{chunk-PYBFTMHI.mjs → chunk-X36FZZT6.mjs} +11 -0
  13. package/dist/{client-CeW3acve.d.ts → client-BTL9d_nN.d.mts} +29 -2
  14. package/dist/{client-BQbSKlHS.d.mts → client-BX30FAWZ.d.ts} +29 -2
  15. package/dist/{client-Bw4HtLP1.d.mts → client-Bhe2TnFW.d.mts} +2 -2
  16. package/dist/{client-Otzv_rgP.d.ts → client-DrkuEK_I.d.ts} +2 -2
  17. package/dist/{index-CmIboQjl.d.mts → index-BuNjyfaV.d.mts} +3 -3
  18. package/dist/{index-DgoRwz8l.d.ts → index-D-w5h82t.d.ts} +3 -3
  19. package/dist/index.d.mts +7 -7
  20. package/dist/index.d.ts +7 -7
  21. package/dist/index.js +69 -69
  22. package/dist/index.mjs +3 -3
  23. package/dist/mock/cli.mjs +11 -0
  24. package/dist/mock/library.js +11 -0
  25. package/dist/mock/library.mjs +11 -0
  26. package/dist/mock/msw.js +11 -0
  27. package/dist/mock/msw.mjs +11 -0
  28. package/dist/{payment-Cq8FT1B6.d.ts → payment-By0JidTe.d.ts} +1 -1
  29. package/dist/{payment-BFtLqiG2.d.mts → payment-pKPpaORI.d.mts} +1 -1
  30. package/dist/{price-DaFXT-Lr.d.ts → price-23RNXftz.d.ts} +1 -1
  31. package/dist/{price-DleDWk_s.d.mts → price-BvRtp6ak.d.mts} +1 -1
  32. package/dist/{product-bZ8G5Z8D.d.mts → product-O8-wcHSe.d.mts} +11 -0
  33. package/dist/{product-bZ8G5Z8D.d.ts → product-O8-wcHSe.d.ts} +11 -0
  34. package/dist/react.d.mts +20 -6
  35. package/dist/react.d.ts +20 -6
  36. package/dist/react.js +208 -76
  37. package/dist/react.mjs +190 -59
  38. package/dist/{server-D-iK-bNt.d.mts → server-BN9ZCAKT.d.mts} +5 -1
  39. package/dist/{server-DwsY9hlX.d.ts → server-DDGbfW_S.d.ts} +5 -1
  40. package/dist/server.d.mts +4 -4
  41. package/dist/server.d.ts +4 -4
  42. package/dist/server.js +7 -7
  43. package/dist/server.mjs +2 -2
  44. package/dist/testing/msw.d.mts +2 -2
  45. package/dist/testing/msw.d.ts +2 -2
  46. package/dist/testing/msw.js +2 -2
  47. package/dist/testing/msw.mjs +1 -1
  48. package/dist/testing/suite.d.mts +6 -6
  49. package/dist/testing/suite.d.ts +6 -6
  50. package/dist/testing/suite.js +23 -23
  51. package/dist/testing/suite.mjs +4 -4
  52. package/dist/testing.d.mts +5 -5
  53. package/dist/testing.d.ts +5 -5
  54. package/dist/testing.js +79 -79
  55. package/dist/testing.mjs +5 -5
  56. package/dist/utils.d.mts +4 -4
  57. package/dist/utils.d.ts +4 -4
  58. package/package.json +1 -1
  59. package/registry/chat-widget.json +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkIVJEUGWF_js = require('./chunk-IVJEUGWF.js');
3
+ var chunkVEOAMBEX_js = require('./chunk-VEOAMBEX.js');
4
4
  var chunkAETVRBKI_js = require('./chunk-AETVRBKI.js');
5
5
 
6
6
  // src/store-credit.ts
@@ -13,7 +13,7 @@ var StoreCreditQueries = class {
13
13
  * currency. Requires a signed-in customer; returns an error otherwise.
14
14
  */
15
15
  async balance() {
16
- return chunkIVJEUGWF_js.safe(this.client.get("/api/v1/store-credit/balance"));
16
+ return chunkVEOAMBEX_js.safe(this.client.get("/api/v1/store-credit/balance"));
17
17
  }
18
18
  };
19
19
 
@@ -74,6 +74,21 @@ var ActivityService = class {
74
74
  is_new_visitor: isNewVisitor
75
75
  };
76
76
  }
77
+ /**
78
+ * Record a page the visitor landed on. Product and category views already
79
+ * imply one, so call this for everything else — home, listings, booking,
80
+ * checkout — or entry pages, exits and bounce rate are computed from
81
+ * product pages alone.
82
+ */
83
+ trackPageView(options = {}) {
84
+ this.sendEvents([
85
+ {
86
+ type: "page_view",
87
+ page_path: options.pagePath ?? currentPath(),
88
+ page_title: options.pageTitle ?? currentTitle()
89
+ }
90
+ ]);
91
+ }
77
92
  trackProductView(productId, options = {}) {
78
93
  const event = {
79
94
  type: "product_view",
@@ -95,7 +110,7 @@ var ActivityService = class {
95
110
  this.sendEvents([event]);
96
111
  }
97
112
  async getState() {
98
- return chunkIVJEUGWF_js.safe(this.client.get("/api/v1/activity/state"));
113
+ return chunkVEOAMBEX_js.safe(this.client.get("/api/v1/activity/state"));
99
114
  }
100
115
  async getRecommendations(options) {
101
116
  const params = new URLSearchParams();
@@ -103,10 +118,10 @@ var ActivityService = class {
103
118
  if (options?.limit) params.set("limit", String(options.limit));
104
119
  const query = params.toString();
105
120
  const path = query ? `/api/v1/activity/recommendations?${query}` : "/api/v1/activity/recommendations";
106
- return chunkIVJEUGWF_js.safe(this.client.get(path));
121
+ return chunkVEOAMBEX_js.safe(this.client.get(path));
107
122
  }
108
123
  async dismissMessage(code) {
109
- return chunkIVJEUGWF_js.safe(
124
+ return chunkVEOAMBEX_js.safe(
110
125
  this.client.post("/api/v1/activity/messages/dismiss", { code })
111
126
  );
112
127
  }
@@ -122,6 +137,12 @@ function currentPath() {
122
137
  }
123
138
  return void 0;
124
139
  }
140
+ function currentTitle() {
141
+ if (typeof document !== "undefined" && document.title) {
142
+ return document.title;
143
+ }
144
+ return void 0;
145
+ }
125
146
  function resolveVisitor() {
126
147
  try {
127
148
  const existing = localStorage.getItem(VISITOR_ID_STORAGE_KEY);
@@ -142,16 +163,16 @@ var SubscriptionService = class {
142
163
  this.client = client;
143
164
  }
144
165
  async list() {
145
- return chunkIVJEUGWF_js.safe(this.client.get("/api/v1/subscriptions"));
166
+ return chunkVEOAMBEX_js.safe(this.client.get("/api/v1/subscriptions"));
146
167
  }
147
168
  async get(id) {
148
169
  const encodedId = encodeURIComponent(id);
149
- return chunkIVJEUGWF_js.safe(this.client.get(`/api/v1/subscriptions/${encodedId}`));
170
+ return chunkVEOAMBEX_js.safe(this.client.get(`/api/v1/subscriptions/${encodedId}`));
150
171
  }
151
172
  async cancel(id, reason, opts) {
152
173
  const encodedId = encodeURIComponent(id);
153
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
154
- return chunkIVJEUGWF_js.safe(
174
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
175
+ return chunkVEOAMBEX_js.safe(
155
176
  this.client.post(
156
177
  `/api/v1/subscriptions/${encodedId}/cancel`,
157
178
  { reason },
@@ -161,20 +182,20 @@ var SubscriptionService = class {
161
182
  }
162
183
  async pause(id) {
163
184
  const encodedId = encodeURIComponent(id);
164
- return chunkIVJEUGWF_js.safe(
185
+ return chunkVEOAMBEX_js.safe(
165
186
  this.client.post(`/api/v1/subscriptions/${encodedId}/pause`)
166
187
  );
167
188
  }
168
189
  async resume(id) {
169
190
  const encodedId = encodeURIComponent(id);
170
- return chunkIVJEUGWF_js.safe(
191
+ return chunkVEOAMBEX_js.safe(
171
192
  this.client.post(`/api/v1/subscriptions/${encodedId}/resume`)
172
193
  );
173
194
  }
174
195
  async skipNextRenewal(id, opts) {
175
196
  const encodedId = encodeURIComponent(id);
176
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
177
- return chunkIVJEUGWF_js.safe(
197
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
198
+ return chunkVEOAMBEX_js.safe(
178
199
  this.client.post(
179
200
  `/api/v1/subscriptions/${encodedId}/skip`,
180
201
  void 0,
@@ -190,8 +211,8 @@ var UploadService = class {
190
211
  this.client = client;
191
212
  }
192
213
  async init(filename, contentType, sizeBytes, opts) {
193
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
194
- return chunkIVJEUGWF_js.safe(
214
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
215
+ return chunkVEOAMBEX_js.safe(
195
216
  this.client.post(
196
217
  "/api/v1/uploads/init",
197
218
  {
@@ -204,7 +225,7 @@ var UploadService = class {
204
225
  );
205
226
  }
206
227
  async confirm(uploadId) {
207
- return chunkIVJEUGWF_js.safe(
228
+ return chunkVEOAMBEX_js.safe(
208
229
  this.client.post("/api/v1/uploads/confirm", {
209
230
  upload_id: uploadId
210
231
  })
@@ -250,7 +271,7 @@ var PlacesService = class {
250
271
  this.client = client;
251
272
  }
252
273
  async autocomplete(input, sessionToken) {
253
- return chunkIVJEUGWF_js.safe(
274
+ return chunkVEOAMBEX_js.safe(
254
275
  this.client.post("/api/v1/places/autocomplete", {
255
276
  input,
256
277
  sessionToken
@@ -258,7 +279,7 @@ var PlacesService = class {
258
279
  );
259
280
  }
260
281
  async details(placeId, sessionToken) {
261
- return chunkIVJEUGWF_js.safe(
282
+ return chunkVEOAMBEX_js.safe(
262
283
  this.client.post("/api/v1/places/details", {
263
284
  place_id: placeId,
264
285
  sessionToken
@@ -277,7 +298,7 @@ var DeliveryService = class {
277
298
  params.set("dropoff_lat", String(dropoffLat));
278
299
  params.set("dropoff_lng", String(dropoffLng));
279
300
  if (country) params.set("country", country);
280
- return chunkIVJEUGWF_js.safe(
301
+ return chunkVEOAMBEX_js.safe(
281
302
  this.client.get(`/api/v1/delivery/fee?${params.toString()}`)
282
303
  );
283
304
  }
@@ -289,7 +310,7 @@ var DeliveryService = class {
289
310
  params.set("dropoff_lng", String(dropoffLng));
290
311
  if (opts?.country) params.set("country", opts.country);
291
312
  if (opts?.orderValue != null) params.set("order_value", String(opts.orderValue));
292
- return chunkIVJEUGWF_js.safe(
313
+ return chunkVEOAMBEX_js.safe(
293
314
  this.client.get(`/api/v1/delivery/options?${params.toString()}`)
294
315
  );
295
316
  }
@@ -333,16 +354,21 @@ function createClientEvents() {
333
354
  }
334
355
 
335
356
  // src/support.ts
357
+ var CLAIM_TIMEOUT_MS = 15e3;
336
358
  var SupportService = class {
337
359
  constructor(client) {
338
360
  this.client = client;
339
361
  this.claimInFlight = null;
362
+ this.claimInFlightToken = null;
340
363
  this.lastClaimedAccessToken = null;
341
364
  this.claimedName = null;
342
365
  this.client.events.on(SESSION_CLEARED, () => {
343
366
  this.lastClaimedAccessToken = null;
344
367
  this.claimedName = null;
345
368
  });
369
+ this.client.events.on(SESSION_CLAIMED, (event) => {
370
+ if (event.customerName) this.claimedName = event.customerName;
371
+ });
346
372
  }
347
373
  /** The verified customer this session's conversation was claimed for, null while anonymous. */
348
374
  get claimedCustomerName() {
@@ -361,22 +387,36 @@ var SupportService = class {
361
387
  async claimConversation() {
362
388
  const accessToken = this.client.getAccessToken();
363
389
  if (!accessToken) {
364
- return chunkIVJEUGWF_js.err(new chunkAETVRBKI_js.CimplifyError("not_authenticated", "No access token to claim with"));
390
+ return chunkVEOAMBEX_js.err(new chunkAETVRBKI_js.CimplifyError("not_authenticated", "No access token to claim with"));
391
+ }
392
+ if (this.claimInFlight) {
393
+ if (this.claimInFlightToken === accessToken) return this.claimInFlight;
394
+ await this.claimInFlight;
395
+ return this.claimConversation();
365
396
  }
366
- if (this.claimInFlight) return this.claimInFlight;
367
397
  if (this.lastClaimedAccessToken === accessToken) {
368
- return chunkIVJEUGWF_js.err(new chunkAETVRBKI_js.CimplifyError("already_claimed", "Session already claimed for this token"));
398
+ return chunkVEOAMBEX_js.err(new chunkAETVRBKI_js.CimplifyError("already_claimed", "Session already claimed for this token"));
369
399
  }
400
+ const epoch = this.client.getSessionEpoch();
401
+ this.claimInFlightToken = accessToken;
370
402
  this.claimInFlight = (async () => {
371
- const result = await chunkIVJEUGWF_js.safe(
372
- this.client.post("/api/v1/support/conversation/claim", {
373
- access_token: accessToken
374
- })
403
+ const result = await chunkVEOAMBEX_js.safe(
404
+ this.client.post(
405
+ "/api/v1/support/conversation/claim",
406
+ { access_token: accessToken },
407
+ { timeoutMs: CLAIM_TIMEOUT_MS }
408
+ )
375
409
  );
376
410
  if (result.ok) {
411
+ if (this.client.getSessionEpoch() !== epoch) {
412
+ return chunkVEOAMBEX_js.err(
413
+ new chunkAETVRBKI_js.CimplifyError("session_cleared", "Session was cleared during the claim")
414
+ );
415
+ }
377
416
  this.lastClaimedAccessToken = accessToken;
378
417
  this.claimedName = result.value.customer_name || null;
379
418
  this.client.adoptSessionToken(result.value.session_token);
419
+ this.client.publishSessionClaimed(this.claimedName);
380
420
  this.client.events.emit(SESSION_CLAIMED, {
381
421
  sessionToken: result.value.session_token,
382
422
  threadId: result.value.thread_id ?? null,
@@ -389,12 +429,29 @@ var SupportService = class {
389
429
  return await this.claimInFlight;
390
430
  } finally {
391
431
  this.claimInFlight = null;
432
+ this.claimInFlightToken = null;
392
433
  }
393
434
  }
435
+ /**
436
+ * Peek at the conversation without creating one: resolves the existing
437
+ * thread (or null) so a page load can hydrate history without littering
438
+ * the inbox with empty threads.
439
+ */
440
+ async peekConversation() {
441
+ const result = await chunkVEOAMBEX_js.safe(
442
+ this.client.get("/api/v1/support/conversation")
443
+ );
444
+ if (!result.ok) return result;
445
+ if (!result.value.conversation) return chunkVEOAMBEX_js.ok(null);
446
+ return chunkVEOAMBEX_js.ok({
447
+ conversation: result.value.conversation,
448
+ messages: result.value.messages
449
+ });
450
+ }
394
451
  /** Open (or resume) the customer's widget conversation. */
395
452
  async openConversation(opts) {
396
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
397
- return chunkIVJEUGWF_js.safe(
453
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
454
+ return chunkVEOAMBEX_js.safe(
398
455
  this.client.post("/api/v1/support/conversation", void 0, {
399
456
  idempotencyKey
400
457
  })
@@ -409,8 +466,8 @@ var SupportService = class {
409
466
  * server resolves it thread-scoped and echoes the quote as `reply_to`.
410
467
  */
411
468
  async sendMessage(content, opts) {
412
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
413
- return chunkIVJEUGWF_js.safe(
469
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
470
+ return chunkVEOAMBEX_js.safe(
414
471
  this.client.post(
415
472
  "/api/v1/support/conversation/messages",
416
473
  {
@@ -434,11 +491,11 @@ var SupportService = class {
434
491
  if (options.limit) params.set("limit", String(options.limit));
435
492
  const query = params.toString();
436
493
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
437
- return chunkIVJEUGWF_js.safe(this.client.get(path));
494
+ return chunkVEOAMBEX_js.safe(this.client.get(path));
438
495
  }
439
496
  /** React to a message in the active conversation by its `ChatMessage.id`. */
440
497
  async reactToMessage(messageId, emoji) {
441
- return chunkIVJEUGWF_js.safe(
498
+ return chunkVEOAMBEX_js.safe(
442
499
  this.client.post(
443
500
  `/api/v1/support/conversation/messages/${messageId}/reactions`,
444
501
  { emoji }
@@ -447,8 +504,8 @@ var SupportService = class {
447
504
  }
448
505
  /** Ask for a person: flags the thread for the merchant's inbox. */
449
506
  async requestHuman(opts) {
450
- const idempotencyKey = opts?.idempotencyKey ?? chunkIVJEUGWF_js.generateIdempotencyKey();
451
- return chunkIVJEUGWF_js.safe(
507
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
508
+ return chunkVEOAMBEX_js.safe(
452
509
  this.client.post(
453
510
  "/api/v1/support/conversation/handoff",
454
511
  void 0,
@@ -460,6 +517,7 @@ var SupportService = class {
460
517
 
461
518
  // src/client.ts
462
519
  var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
520
+ var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
463
521
  var ORDER_TOKEN_PREFIX = "cimplify_ot_";
464
522
  var SESSION_TOKEN_HEADER = "x-session-token";
465
523
  var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -576,6 +634,7 @@ var CimplifyClient = class {
576
634
  constructor(config = {}) {
577
635
  this.accessToken = null;
578
636
  this.sessionToken = null;
637
+ this.sessionEpoch = 0;
579
638
  this.context = {};
580
639
  this.businessId = null;
581
640
  this.businessIdResolvePromise = null;
@@ -598,6 +657,7 @@ var CimplifyClient = class {
598
657
  this.hooks = config.hooks ?? {};
599
658
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
600
659
  this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
660
+ this.watchCrossTabSession();
601
661
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
602
662
  console.warn(
603
663
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -664,10 +724,15 @@ var CimplifyClient = class {
664
724
  const previous = this.accessToken;
665
725
  this.accessToken = null;
666
726
  this.sessionToken = null;
667
- if (typeof window !== "undefined" && window.localStorage) {
668
- localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
727
+ this.sessionEpoch++;
728
+ try {
729
+ this.safeStorage()?.removeItem(SESSION_TOKEN_STORAGE_KEY);
730
+ } catch {
669
731
  }
670
732
  this.sessionToken = this.mintSessionToken();
733
+ if (this.sessionToken) {
734
+ this.broadcastSessionSync({ type: "cleared", token: this.sessionToken });
735
+ }
671
736
  this.hooks.onSessionChange?.({
672
737
  previousToken: previous,
673
738
  newToken: null,
@@ -676,42 +741,89 @@ var CimplifyClient = class {
676
741
  this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
677
742
  this.events.emit(SESSION_CLEARED, {});
678
743
  }
679
- setOrderToken(orderId, token) {
680
- if (typeof window !== "undefined" && window.localStorage) {
744
+ getSessionEpoch() {
745
+ return this.sessionEpoch;
746
+ }
747
+ publishSessionClaimed(customerName) {
748
+ if (!this.sessionToken) return;
749
+ this.broadcastSessionSync({
750
+ type: "claimed",
751
+ token: this.sessionToken,
752
+ name: customerName
753
+ });
754
+ }
755
+ broadcastSessionSync(payload) {
756
+ try {
757
+ this.safeStorage()?.setItem(
758
+ SESSION_SYNC_STORAGE_KEY,
759
+ JSON.stringify({ ...payload, at: Date.now() })
760
+ );
761
+ } catch {
762
+ }
763
+ }
764
+ watchCrossTabSession() {
765
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
766
+ window.addEventListener("storage", (event) => {
767
+ if (event.key !== SESSION_SYNC_STORAGE_KEY || !event.newValue) return;
768
+ let payload;
681
769
  try {
682
- const entry = JSON.stringify({ token, storedAt: Date.now() });
683
- localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
770
+ payload = JSON.parse(event.newValue);
684
771
  } catch {
772
+ return;
773
+ }
774
+ if (!payload?.token || payload.token === this.sessionToken) return;
775
+ if (payload.type === "claimed") {
776
+ this.sessionToken = payload.token;
777
+ this.events.emit(SESSION_CLAIMED, {
778
+ sessionToken: payload.token,
779
+ threadId: null,
780
+ customerName: payload.name ?? ""
781
+ });
782
+ } else if (payload.type === "cleared") {
783
+ this.accessToken = null;
784
+ this.sessionToken = payload.token;
785
+ this.sessionEpoch++;
786
+ this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
787
+ this.events.emit(SESSION_CLEARED, {});
685
788
  }
789
+ });
790
+ }
791
+ setOrderToken(orderId, token) {
792
+ try {
793
+ const entry = JSON.stringify({ token, storedAt: Date.now() });
794
+ this.safeStorage()?.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
795
+ } catch {
686
796
  }
687
797
  }
688
798
  getOrderToken(orderId) {
689
- if (typeof window !== "undefined" && window.localStorage) {
690
- try {
691
- const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
692
- if (!raw) return null;
693
- const entry = JSON.parse(raw);
694
- if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
695
- localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
696
- return null;
697
- }
698
- return entry.token;
699
- } catch {
799
+ try {
800
+ const storage = this.safeStorage();
801
+ if (!storage) return null;
802
+ const raw = storage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
803
+ if (!raw) return null;
804
+ const entry = JSON.parse(raw);
805
+ if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
806
+ storage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
700
807
  return null;
701
808
  }
809
+ return entry.token;
810
+ } catch {
811
+ return null;
702
812
  }
703
- return null;
704
813
  }
705
814
  clearOrderTokens() {
706
- if (typeof window !== "undefined" && window.localStorage) {
815
+ try {
816
+ const storage = this.safeStorage();
817
+ if (!storage) return;
707
818
  const keysToRemove = [];
708
- for (let i = 0; i < localStorage.length; i++) {
709
- const key = localStorage.key(i);
819
+ for (let i = 0; i < storage.length; i++) {
820
+ const key = storage.key(i);
710
821
  if (key?.startsWith(ORDER_TOKEN_PREFIX)) {
711
822
  keysToRemove.push(key);
712
823
  }
713
824
  }
714
- keysToRemove.forEach((k) => localStorage.removeItem(k));
825
+ keysToRemove.forEach((k) => storage.removeItem(k));
826
+ } catch {
715
827
  }
716
828
  }
717
829
  setLocationId(locationId) {
@@ -770,22 +882,29 @@ var CimplifyClient = class {
770
882
  this.businessIdResolvePromise = null;
771
883
  }
772
884
  }
773
- async authedFetch(url, options) {
774
- return this.resilientFetch(url, options);
885
+ async authedFetch(url, options, timeoutMs) {
886
+ return this.resilientFetch(url, options, timeoutMs);
775
887
  }
776
888
  // Storage guards: even the `window.localStorage` property access throws in
777
889
  // some sandboxed iframes and strict private-browsing modes. These run in the
778
890
  // constructor at module load, so a throw would white-screen the whole app —
779
891
  // fall back to an in-memory session token instead.
780
- loadSessionToken() {
892
+ safeStorage() {
781
893
  try {
782
894
  if (typeof window !== "undefined" && window.localStorage) {
783
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
895
+ return window.localStorage;
784
896
  }
785
897
  } catch {
786
898
  }
787
899
  return null;
788
900
  }
901
+ loadSessionToken() {
902
+ try {
903
+ return this.safeStorage()?.getItem(SESSION_TOKEN_STORAGE_KEY) ?? null;
904
+ } catch {
905
+ return null;
906
+ }
907
+ }
789
908
  /**
790
909
  * Mint the session token client-side so the very first request already
791
910
  * carries it. Without this, parallel first-load requests each get a
@@ -805,15 +924,15 @@ var CimplifyClient = class {
805
924
  }
806
925
  saveSessionToken(token) {
807
926
  try {
808
- if (typeof window !== "undefined" && window.localStorage) {
809
- localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
810
- }
927
+ this.safeStorage()?.setItem(SESSION_TOKEN_STORAGE_KEY, token);
811
928
  } catch {
812
929
  }
813
930
  }
814
931
  captureSessionToken(response) {
932
+ if (typeof window === "undefined") return;
933
+ if (this.sessionToken) return;
815
934
  const token = response.headers.get(SESSION_TOKEN_HEADER);
816
- if (token && token !== this.sessionToken) {
935
+ if (token) {
817
936
  this.sessionToken = token;
818
937
  this.saveSessionToken(token);
819
938
  }
@@ -841,7 +960,7 @@ var CimplifyClient = class {
841
960
  }
842
961
  return headers;
843
962
  }
844
- async resilientFetch(url, options) {
963
+ async resilientFetch(url, options, timeoutMs) {
845
964
  const method = options.method || "GET";
846
965
  const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
847
966
  const startTime = Date.now();
@@ -858,7 +977,7 @@ var CimplifyClient = class {
858
977
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
859
978
  try {
860
979
  const controller = new AbortController();
861
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
980
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs ?? this.timeout);
862
981
  const response = await this.fetchImpl(url, {
863
982
  ...options,
864
983
  signal: controller.signal
@@ -989,29 +1108,41 @@ var CimplifyClient = class {
989
1108
  });
990
1109
  }
991
1110
  async post(path, body, opts) {
992
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
993
- method: "POST",
994
- credentials: this.credentials,
995
- headers: mergeOptionHeaders(this.getHeaders(), opts),
996
- body: body ? JSON.stringify(body) : void 0
997
- });
1111
+ const response = await this.authedFetch(
1112
+ this.buildUrl(this.baseUrl, path),
1113
+ {
1114
+ method: "POST",
1115
+ credentials: this.credentials,
1116
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1117
+ body: body ? JSON.stringify(body) : void 0
1118
+ },
1119
+ opts?.timeoutMs
1120
+ );
998
1121
  return this.handleRestResponse(response);
999
1122
  }
1000
1123
  async patch(path, body, opts) {
1001
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
1002
- method: "PATCH",
1003
- credentials: this.credentials,
1004
- headers: mergeOptionHeaders(this.getHeaders(), opts),
1005
- body: body ? JSON.stringify(body) : void 0
1006
- });
1124
+ const response = await this.authedFetch(
1125
+ this.buildUrl(this.baseUrl, path),
1126
+ {
1127
+ method: "PATCH",
1128
+ credentials: this.credentials,
1129
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1130
+ body: body ? JSON.stringify(body) : void 0
1131
+ },
1132
+ opts?.timeoutMs
1133
+ );
1007
1134
  return this.handleRestResponse(response);
1008
1135
  }
1009
1136
  async delete(path, opts) {
1010
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
1011
- method: "DELETE",
1012
- credentials: this.credentials,
1013
- headers: mergeOptionHeaders(this.getHeaders(), opts)
1014
- });
1137
+ const response = await this.authedFetch(
1138
+ this.buildUrl(this.baseUrl, path),
1139
+ {
1140
+ method: "DELETE",
1141
+ credentials: this.credentials,
1142
+ headers: mergeOptionHeaders(this.getHeaders(), opts)
1143
+ },
1144
+ opts?.timeoutMs
1145
+ );
1015
1146
  return this.handleRestResponse(response);
1016
1147
  }
1017
1148
  async linkGet(path, opts) {
@@ -1027,12 +1158,16 @@ var CimplifyClient = class {
1027
1158
  });
1028
1159
  }
1029
1160
  async linkPost(path, body, opts) {
1030
- const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
1031
- method: "POST",
1032
- credentials: this.credentials,
1033
- headers: mergeOptionHeaders(this.getHeaders(), opts),
1034
- body: body ? JSON.stringify(body) : void 0
1035
- });
1161
+ const response = await this.authedFetch(
1162
+ `${this.linkApiUrl}${path}`,
1163
+ {
1164
+ method: "POST",
1165
+ credentials: this.credentials,
1166
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1167
+ body: body ? JSON.stringify(body) : void 0
1168
+ },
1169
+ opts?.timeoutMs
1170
+ );
1036
1171
  return this.handleRestResponse(response);
1037
1172
  }
1038
1173
  async linkDelete(path, opts) {
@@ -1081,25 +1216,25 @@ var CimplifyClient = class {
1081
1216
  }
1082
1217
  get catalogue() {
1083
1218
  if (!this._catalogue) {
1084
- this._catalogue = new chunkIVJEUGWF_js.CatalogueQueries(this);
1219
+ this._catalogue = new chunkVEOAMBEX_js.CatalogueQueries(this);
1085
1220
  }
1086
1221
  return this._catalogue;
1087
1222
  }
1088
1223
  get cart() {
1089
1224
  if (!this._cart) {
1090
- this._cart = new chunkIVJEUGWF_js.CartOperations(this);
1225
+ this._cart = new chunkVEOAMBEX_js.CartOperations(this);
1091
1226
  }
1092
1227
  return this._cart;
1093
1228
  }
1094
1229
  get checkout() {
1095
1230
  if (!this._checkout) {
1096
- this._checkout = new chunkIVJEUGWF_js.CheckoutService(this);
1231
+ this._checkout = new chunkVEOAMBEX_js.CheckoutService(this);
1097
1232
  }
1098
1233
  return this._checkout;
1099
1234
  }
1100
1235
  get orders() {
1101
1236
  if (!this._orders) {
1102
- this._orders = new chunkIVJEUGWF_js.OrderQueries(this);
1237
+ this._orders = new chunkVEOAMBEX_js.OrderQueries(this);
1103
1238
  }
1104
1239
  return this._orders;
1105
1240
  }
@@ -1129,43 +1264,43 @@ var CimplifyClient = class {
1129
1264
  }
1130
1265
  get link() {
1131
1266
  if (!this._link) {
1132
- this._link = new chunkIVJEUGWF_js.LinkService(this);
1267
+ this._link = new chunkVEOAMBEX_js.LinkService(this);
1133
1268
  }
1134
1269
  return this._link;
1135
1270
  }
1136
1271
  get auth() {
1137
1272
  if (!this._auth) {
1138
- this._auth = new chunkIVJEUGWF_js.AuthService(this);
1273
+ this._auth = new chunkVEOAMBEX_js.AuthService(this);
1139
1274
  }
1140
1275
  return this._auth;
1141
1276
  }
1142
1277
  get business() {
1143
1278
  if (!this._business) {
1144
- this._business = new chunkIVJEUGWF_js.BusinessService(this);
1279
+ this._business = new chunkVEOAMBEX_js.BusinessService(this);
1145
1280
  }
1146
1281
  return this._business;
1147
1282
  }
1148
1283
  get inventory() {
1149
1284
  if (!this._inventory) {
1150
- this._inventory = new chunkIVJEUGWF_js.InventoryService(this);
1285
+ this._inventory = new chunkVEOAMBEX_js.InventoryService(this);
1151
1286
  }
1152
1287
  return this._inventory;
1153
1288
  }
1154
1289
  get scheduling() {
1155
1290
  if (!this._scheduling) {
1156
- this._scheduling = new chunkIVJEUGWF_js.SchedulingService(this);
1291
+ this._scheduling = new chunkVEOAMBEX_js.SchedulingService(this);
1157
1292
  }
1158
1293
  return this._scheduling;
1159
1294
  }
1160
1295
  get lite() {
1161
1296
  if (!this._lite) {
1162
- this._lite = new chunkIVJEUGWF_js.LiteService(this);
1297
+ this._lite = new chunkVEOAMBEX_js.LiteService(this);
1163
1298
  }
1164
1299
  return this._lite;
1165
1300
  }
1166
1301
  get fx() {
1167
1302
  if (!this._fx) {
1168
- this._fx = new chunkIVJEUGWF_js.FxService(this);
1303
+ this._fx = new chunkVEOAMBEX_js.FxService(this);
1169
1304
  }
1170
1305
  return this._fx;
1171
1306
  }
@@ -1200,7 +1335,7 @@ var CimplifyClient = class {
1200
1335
  if (businessId) {
1201
1336
  this.setBusinessId(businessId);
1202
1337
  }
1203
- return chunkIVJEUGWF_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
1338
+ return chunkVEOAMBEX_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
1204
1339
  }
1205
1340
  };
1206
1341
  function createCimplifyClient(config = {}) {