@cimplify/sdk 0.90.0 → 0.93.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 (67) 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-KJP4U6L3.js → chunk-6Y7KC5YZ.js} +23 -0
  6. package/dist/{chunk-JVWFIFQ7.js → chunk-AWNWP5J3.js} +4 -4
  7. package/dist/{chunk-2UDEWILL.mjs → chunk-FKARGZK3.mjs} +307 -90
  8. package/dist/{chunk-T7Z25EY4.js → chunk-HKN3YG76.js} +84 -0
  9. package/dist/{chunk-BN4V4ONE.js → chunk-QLGZIBRO.js} +348 -128
  10. package/dist/{chunk-NGE37REW.mjs → chunk-QXWX7CD2.mjs} +2 -2
  11. package/dist/{chunk-OZDDHSIB.mjs → chunk-RRBY35TJ.mjs} +80 -1
  12. package/dist/{chunk-GHFDYM5K.js → chunk-VEOAMBEX.js} +11 -4
  13. package/dist/{chunk-ZU4ZRYUR.mjs → chunk-VUSHG3HA.mjs} +11 -4
  14. package/dist/{chunk-NNGKC3MM.mjs → chunk-X36FZZT6.mjs} +23 -0
  15. package/dist/{client-YiSelM7x.d.mts → client-BTL9d_nN.d.mts} +117 -11
  16. package/dist/{client-CR1f94wY.d.ts → client-BX30FAWZ.d.ts} +117 -11
  17. package/dist/{client-DMttx1xk.d.mts → client-Bhe2TnFW.d.mts} +2 -2
  18. package/dist/{client-CqpOcbin.d.ts → client-DrkuEK_I.d.ts} +2 -2
  19. package/dist/{index-DD9z396M.d.mts → index-BuNjyfaV.d.mts} +3 -3
  20. package/dist/{index-CxTVu0HZ.d.ts → index-D-w5h82t.d.ts} +3 -3
  21. package/dist/index.d.mts +49 -7
  22. package/dist/index.d.ts +49 -7
  23. package/dist/index.js +103 -83
  24. package/dist/index.mjs +5 -5
  25. package/dist/mock/cli.mjs +23 -0
  26. package/dist/mock/library.js +23 -0
  27. package/dist/mock/library.mjs +23 -0
  28. package/dist/mock/msw.js +23 -0
  29. package/dist/mock/msw.mjs +23 -0
  30. package/dist/{payment-BX7ccIKY.d.ts → payment-By0JidTe.d.ts} +1 -1
  31. package/dist/{payment-5d8FTA1q.d.mts → payment-pKPpaORI.d.mts} +1 -1
  32. package/dist/{price-DtfP_Xfq.d.ts → price-23RNXftz.d.ts} +1 -1
  33. package/dist/{price-arl_4Rzn.d.mts → price-BvRtp6ak.d.mts} +1 -1
  34. package/dist/{product-DZX4QuKS.d.ts → product-O8-wcHSe.d.mts} +49 -0
  35. package/dist/{product-DZX4QuKS.d.mts → product-O8-wcHSe.d.ts} +49 -0
  36. package/dist/react.d.mts +79 -6
  37. package/dist/react.d.ts +79 -6
  38. package/dist/react.js +607 -379
  39. package/dist/react.mjs +539 -315
  40. package/dist/{server-BceZMxcK.d.mts → server-BN9ZCAKT.d.mts} +5 -1
  41. package/dist/{server-DoJGSC7L.d.ts → server-DDGbfW_S.d.ts} +5 -1
  42. package/dist/server.d.mts +4 -4
  43. package/dist/server.d.ts +4 -4
  44. package/dist/server.js +7 -7
  45. package/dist/server.mjs +2 -2
  46. package/dist/styles.css +1 -1
  47. package/dist/testing/msw.d.mts +2 -2
  48. package/dist/testing/msw.d.ts +2 -2
  49. package/dist/testing/msw.js +2 -2
  50. package/dist/testing/msw.mjs +1 -1
  51. package/dist/testing/suite.d.mts +6 -6
  52. package/dist/testing/suite.d.ts +6 -6
  53. package/dist/testing/suite.js +23 -23
  54. package/dist/testing/suite.mjs +4 -4
  55. package/dist/testing.d.mts +5 -5
  56. package/dist/testing.d.ts +5 -5
  57. package/dist/testing.js +79 -79
  58. package/dist/testing.mjs +5 -5
  59. package/dist/utils.d.mts +4 -4
  60. package/dist/utils.d.ts +4 -4
  61. package/package.json +1 -1
  62. package/registry/booking-page.json +1 -1
  63. package/registry/chat-widget.json +1 -1
  64. package/registry/customer-input-fields.json +1 -1
  65. package/registry/date-slot-picker.json +1 -1
  66. package/registry/product-customizer.json +1 -1
  67. package/registry/rental-service-card.json +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkGHFDYM5K_js = require('./chunk-GHFDYM5K.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 chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_js.safe(this.client.get(path));
121
+ return chunkVEOAMBEX_js.safe(this.client.get(path));
107
122
  }
108
123
  async dismissMessage(code) {
109
- return chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_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 ?? chunkGHFDYM5K_js.generateIdempotencyKey();
154
- return chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_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 ?? chunkGHFDYM5K_js.generateIdempotencyKey();
177
- return chunkGHFDYM5K_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 ?? chunkGHFDYM5K_js.generateIdempotencyKey();
194
- return chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_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 chunkGHFDYM5K_js.safe(
301
+ return chunkVEOAMBEX_js.safe(
281
302
  this.client.get(`/api/v1/delivery/fee?${params.toString()}`)
282
303
  );
283
304
  }
@@ -289,21 +310,148 @@ 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 chunkGHFDYM5K_js.safe(
313
+ return chunkVEOAMBEX_js.safe(
293
314
  this.client.get(`/api/v1/delivery/options?${params.toString()}`)
294
315
  );
295
316
  }
296
317
  };
297
318
 
319
+ // src/internal/events.ts
320
+ var MUTATION_ERROR = "mutation:error";
321
+ var AUTH_TOKEN_CHANGED = "auth:token-changed";
322
+ var SESSION_CLAIMED = "session:claimed";
323
+ var SESSION_CLEARED = "session:cleared";
324
+ function createClientEvents() {
325
+ const listeners = /* @__PURE__ */ new Map();
326
+ return {
327
+ on(name, listener) {
328
+ let set = listeners.get(name);
329
+ if (!set) {
330
+ set = /* @__PURE__ */ new Set();
331
+ listeners.set(name, set);
332
+ }
333
+ set.add(listener);
334
+ return () => {
335
+ set?.delete(listener);
336
+ };
337
+ },
338
+ off(name, listener) {
339
+ listeners.get(name)?.delete(listener);
340
+ },
341
+ emit(name, payload) {
342
+ const set = listeners.get(name);
343
+ if (!set) return;
344
+ const snapshot = Array.from(set);
345
+ for (const listener of snapshot) {
346
+ try {
347
+ listener(payload);
348
+ } catch (err2) {
349
+ console.error(`[Cimplify] event listener for "${name}" threw:`, err2);
350
+ }
351
+ }
352
+ }
353
+ };
354
+ }
355
+
298
356
  // src/support.ts
357
+ var CLAIM_TIMEOUT_MS = 15e3;
299
358
  var SupportService = class {
300
359
  constructor(client) {
301
360
  this.client = client;
361
+ this.claimInFlight = null;
362
+ this.claimInFlightToken = null;
363
+ this.lastClaimedAccessToken = null;
364
+ this.claimedName = null;
365
+ this.client.events.on(SESSION_CLEARED, () => {
366
+ this.lastClaimedAccessToken = null;
367
+ this.claimedName = null;
368
+ });
369
+ this.client.events.on(SESSION_CLAIMED, (event) => {
370
+ if (event.customerName) this.claimedName = event.customerName;
371
+ });
372
+ }
373
+ /** The verified customer this session's conversation was claimed for, null while anonymous. */
374
+ get claimedCustomerName() {
375
+ return this.claimedName;
376
+ }
377
+ /**
378
+ * Claim the anonymous session for the verified Link identity: the server
379
+ * verifies the access token, rotates the session token (adopted here, so
380
+ * every subsequent request rides the bound session), folds the guest cart
381
+ * in, and adopts or merges the widget conversation.
382
+ *
383
+ * Idempotent and single-flight: concurrent calls share one request, and a
384
+ * token already claimed by this instance short-circuits without a network
385
+ * round trip. Emits `session:claimed` on the client's event channel.
386
+ */
387
+ async claimConversation() {
388
+ const accessToken = this.client.getAccessToken();
389
+ if (!accessToken) {
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();
396
+ }
397
+ if (this.lastClaimedAccessToken === accessToken) {
398
+ return chunkVEOAMBEX_js.err(new chunkAETVRBKI_js.CimplifyError("already_claimed", "Session already claimed for this token"));
399
+ }
400
+ const epoch = this.client.getSessionEpoch();
401
+ this.claimInFlightToken = accessToken;
402
+ this.claimInFlight = (async () => {
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
+ )
409
+ );
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
+ }
416
+ this.lastClaimedAccessToken = accessToken;
417
+ this.claimedName = result.value.customer_name || null;
418
+ this.client.adoptSessionToken(result.value.session_token);
419
+ this.client.publishSessionClaimed(this.claimedName);
420
+ this.client.events.emit(SESSION_CLAIMED, {
421
+ sessionToken: result.value.session_token,
422
+ threadId: result.value.thread_id ?? null,
423
+ customerName: result.value.customer_name
424
+ });
425
+ }
426
+ return result;
427
+ })();
428
+ try {
429
+ return await this.claimInFlight;
430
+ } finally {
431
+ this.claimInFlight = null;
432
+ this.claimInFlightToken = null;
433
+ }
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
+ });
302
450
  }
303
451
  /** Open (or resume) the customer's widget conversation. */
304
452
  async openConversation(opts) {
305
- const idempotencyKey = opts?.idempotencyKey ?? chunkGHFDYM5K_js.generateIdempotencyKey();
306
- return chunkGHFDYM5K_js.safe(
453
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
454
+ return chunkVEOAMBEX_js.safe(
307
455
  this.client.post("/api/v1/support/conversation", void 0, {
308
456
  idempotencyKey
309
457
  })
@@ -318,8 +466,8 @@ var SupportService = class {
318
466
  * server resolves it thread-scoped and echoes the quote as `reply_to`.
319
467
  */
320
468
  async sendMessage(content, opts) {
321
- const idempotencyKey = opts?.idempotencyKey ?? chunkGHFDYM5K_js.generateIdempotencyKey();
322
- return chunkGHFDYM5K_js.safe(
469
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
470
+ return chunkVEOAMBEX_js.safe(
323
471
  this.client.post(
324
472
  "/api/v1/support/conversation/messages",
325
473
  {
@@ -343,11 +491,11 @@ var SupportService = class {
343
491
  if (options.limit) params.set("limit", String(options.limit));
344
492
  const query = params.toString();
345
493
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
346
- return chunkGHFDYM5K_js.safe(this.client.get(path));
494
+ return chunkVEOAMBEX_js.safe(this.client.get(path));
347
495
  }
348
496
  /** React to a message in the active conversation by its `ChatMessage.id`. */
349
497
  async reactToMessage(messageId, emoji) {
350
- return chunkGHFDYM5K_js.safe(
498
+ return chunkVEOAMBEX_js.safe(
351
499
  this.client.post(
352
500
  `/api/v1/support/conversation/messages/${messageId}/reactions`,
353
501
  { emoji }
@@ -356,8 +504,8 @@ var SupportService = class {
356
504
  }
357
505
  /** Ask for a person: flags the thread for the merchant's inbox. */
358
506
  async requestHuman(opts) {
359
- const idempotencyKey = opts?.idempotencyKey ?? chunkGHFDYM5K_js.generateIdempotencyKey();
360
- return chunkGHFDYM5K_js.safe(
507
+ const idempotencyKey = opts?.idempotencyKey ?? chunkVEOAMBEX_js.generateIdempotencyKey();
508
+ return chunkVEOAMBEX_js.safe(
361
509
  this.client.post(
362
510
  "/api/v1/support/conversation/handoff",
363
511
  void 0,
@@ -367,41 +515,9 @@ var SupportService = class {
367
515
  }
368
516
  };
369
517
 
370
- // src/internal/events.ts
371
- function createClientEvents() {
372
- const listeners = /* @__PURE__ */ new Map();
373
- return {
374
- on(name, listener) {
375
- let set = listeners.get(name);
376
- if (!set) {
377
- set = /* @__PURE__ */ new Set();
378
- listeners.set(name, set);
379
- }
380
- set.add(listener);
381
- return () => {
382
- set?.delete(listener);
383
- };
384
- },
385
- off(name, listener) {
386
- listeners.get(name)?.delete(listener);
387
- },
388
- emit(name, payload) {
389
- const set = listeners.get(name);
390
- if (!set) return;
391
- const snapshot = Array.from(set);
392
- for (const listener of snapshot) {
393
- try {
394
- listener(payload);
395
- } catch (err) {
396
- console.error(`[Cimplify] event listener for "${name}" threw:`, err);
397
- }
398
- }
399
- }
400
- };
401
- }
402
-
403
518
  // src/client.ts
404
519
  var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
520
+ var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
405
521
  var ORDER_TOKEN_PREFIX = "cimplify_ot_";
406
522
  var SESSION_TOKEN_HEADER = "x-session-token";
407
523
  var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -518,6 +634,7 @@ var CimplifyClient = class {
518
634
  constructor(config = {}) {
519
635
  this.accessToken = null;
520
636
  this.sessionToken = null;
637
+ this.sessionEpoch = 0;
521
638
  this.context = {};
522
639
  this.businessId = null;
523
640
  this.businessIdResolvePromise = null;
@@ -540,6 +657,7 @@ var CimplifyClient = class {
540
657
  this.hooks = config.hooks ?? {};
541
658
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
542
659
  this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
660
+ this.watchCrossTabSession();
543
661
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
544
662
  console.warn(
545
663
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -579,57 +697,133 @@ var CimplifyClient = class {
579
697
  newToken: token,
580
698
  source: "manual"
581
699
  });
700
+ this.events.emit(AUTH_TOKEN_CHANGED, { token });
701
+ }
702
+ /**
703
+ * Zero-UI claim: a freshly verified customer identity (OTP verify, silent
704
+ * refresh restore) binds the anonymous session so the conversation, cart
705
+ * and orders survive a cleared browser. Best-effort by design — a failed
706
+ * claim leaves the session anonymous, exactly as it was. Called by the
707
+ * auth flows, never by the raw token setter.
708
+ */
709
+ autoClaimChatIdentity() {
710
+ if (typeof window === "undefined" || !this.sessionToken || !this.accessToken) return;
711
+ void this.support.claimConversation();
712
+ }
713
+ /**
714
+ * Adopt a server-rotated session token (claim flow). The old token stays
715
+ * in flight-safe use until the next request; the storage swap makes the
716
+ * rotation durable across reloads.
717
+ */
718
+ adoptSessionToken(token) {
719
+ if (!token || token === this.sessionToken) return;
720
+ this.sessionToken = token;
721
+ this.saveSessionToken(token);
582
722
  }
583
723
  clearSession() {
584
724
  const previous = this.accessToken;
585
725
  this.accessToken = null;
586
726
  this.sessionToken = null;
587
- if (typeof window !== "undefined" && window.localStorage) {
588
- localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
727
+ this.sessionEpoch++;
728
+ try {
729
+ this.safeStorage()?.removeItem(SESSION_TOKEN_STORAGE_KEY);
730
+ } catch {
589
731
  }
590
732
  this.sessionToken = this.mintSessionToken();
733
+ if (this.sessionToken) {
734
+ this.broadcastSessionSync({ type: "cleared", token: this.sessionToken });
735
+ }
591
736
  this.hooks.onSessionChange?.({
592
737
  previousToken: previous,
593
738
  newToken: null,
594
739
  source: "clear"
595
740
  });
741
+ this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
742
+ this.events.emit(SESSION_CLEARED, {});
743
+ }
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
+ });
596
754
  }
597
- setOrderToken(orderId, token) {
598
- if (typeof window !== "undefined" && window.localStorage) {
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;
599
769
  try {
600
- const entry = JSON.stringify({ token, storedAt: Date.now() });
601
- localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
770
+ payload = JSON.parse(event.newValue);
602
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, {});
603
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 {
604
796
  }
605
797
  }
606
798
  getOrderToken(orderId) {
607
- if (typeof window !== "undefined" && window.localStorage) {
608
- try {
609
- const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
610
- if (!raw) return null;
611
- const entry = JSON.parse(raw);
612
- if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
613
- localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
614
- return null;
615
- }
616
- return entry.token;
617
- } 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}`);
618
807
  return null;
619
808
  }
809
+ return entry.token;
810
+ } catch {
811
+ return null;
620
812
  }
621
- return null;
622
813
  }
623
814
  clearOrderTokens() {
624
- if (typeof window !== "undefined" && window.localStorage) {
815
+ try {
816
+ const storage = this.safeStorage();
817
+ if (!storage) return;
625
818
  const keysToRemove = [];
626
- for (let i = 0; i < localStorage.length; i++) {
627
- const key = localStorage.key(i);
819
+ for (let i = 0; i < storage.length; i++) {
820
+ const key = storage.key(i);
628
821
  if (key?.startsWith(ORDER_TOKEN_PREFIX)) {
629
822
  keysToRemove.push(key);
630
823
  }
631
824
  }
632
- keysToRemove.forEach((k) => localStorage.removeItem(k));
825
+ keysToRemove.forEach((k) => storage.removeItem(k));
826
+ } catch {
633
827
  }
634
828
  }
635
829
  setLocationId(locationId) {
@@ -688,22 +882,29 @@ var CimplifyClient = class {
688
882
  this.businessIdResolvePromise = null;
689
883
  }
690
884
  }
691
- async authedFetch(url, options) {
692
- return this.resilientFetch(url, options);
885
+ async authedFetch(url, options, timeoutMs) {
886
+ return this.resilientFetch(url, options, timeoutMs);
693
887
  }
694
888
  // Storage guards: even the `window.localStorage` property access throws in
695
889
  // some sandboxed iframes and strict private-browsing modes. These run in the
696
890
  // constructor at module load, so a throw would white-screen the whole app —
697
891
  // fall back to an in-memory session token instead.
698
- loadSessionToken() {
892
+ safeStorage() {
699
893
  try {
700
894
  if (typeof window !== "undefined" && window.localStorage) {
701
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
895
+ return window.localStorage;
702
896
  }
703
897
  } catch {
704
898
  }
705
899
  return null;
706
900
  }
901
+ loadSessionToken() {
902
+ try {
903
+ return this.safeStorage()?.getItem(SESSION_TOKEN_STORAGE_KEY) ?? null;
904
+ } catch {
905
+ return null;
906
+ }
907
+ }
707
908
  /**
708
909
  * Mint the session token client-side so the very first request already
709
910
  * carries it. Without this, parallel first-load requests each get a
@@ -723,15 +924,15 @@ var CimplifyClient = class {
723
924
  }
724
925
  saveSessionToken(token) {
725
926
  try {
726
- if (typeof window !== "undefined" && window.localStorage) {
727
- localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
728
- }
927
+ this.safeStorage()?.setItem(SESSION_TOKEN_STORAGE_KEY, token);
729
928
  } catch {
730
929
  }
731
930
  }
732
931
  captureSessionToken(response) {
932
+ if (typeof window === "undefined") return;
933
+ if (this.sessionToken) return;
733
934
  const token = response.headers.get(SESSION_TOKEN_HEADER);
734
- if (token && token !== this.sessionToken) {
935
+ if (token) {
735
936
  this.sessionToken = token;
736
937
  this.saveSessionToken(token);
737
938
  }
@@ -759,7 +960,7 @@ var CimplifyClient = class {
759
960
  }
760
961
  return headers;
761
962
  }
762
- async resilientFetch(url, options) {
963
+ async resilientFetch(url, options, timeoutMs) {
763
964
  const method = options.method || "GET";
764
965
  const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
765
966
  const startTime = Date.now();
@@ -776,7 +977,7 @@ var CimplifyClient = class {
776
977
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
777
978
  try {
778
979
  const controller = new AbortController();
779
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
980
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs ?? this.timeout);
780
981
  const response = await this.fetchImpl(url, {
781
982
  ...options,
782
983
  signal: controller.signal
@@ -907,29 +1108,41 @@ var CimplifyClient = class {
907
1108
  });
908
1109
  }
909
1110
  async post(path, body, opts) {
910
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
911
- method: "POST",
912
- credentials: this.credentials,
913
- headers: mergeOptionHeaders(this.getHeaders(), opts),
914
- body: body ? JSON.stringify(body) : void 0
915
- });
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
+ );
916
1121
  return this.handleRestResponse(response);
917
1122
  }
918
1123
  async patch(path, body, opts) {
919
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
920
- method: "PATCH",
921
- credentials: this.credentials,
922
- headers: mergeOptionHeaders(this.getHeaders(), opts),
923
- body: body ? JSON.stringify(body) : void 0
924
- });
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
+ );
925
1134
  return this.handleRestResponse(response);
926
1135
  }
927
1136
  async delete(path, opts) {
928
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
929
- method: "DELETE",
930
- credentials: this.credentials,
931
- headers: mergeOptionHeaders(this.getHeaders(), opts)
932
- });
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
+ );
933
1146
  return this.handleRestResponse(response);
934
1147
  }
935
1148
  async linkGet(path, opts) {
@@ -945,12 +1158,16 @@ var CimplifyClient = class {
945
1158
  });
946
1159
  }
947
1160
  async linkPost(path, body, opts) {
948
- const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
949
- method: "POST",
950
- credentials: this.credentials,
951
- headers: mergeOptionHeaders(this.getHeaders(), opts),
952
- body: body ? JSON.stringify(body) : void 0
953
- });
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
+ );
954
1171
  return this.handleRestResponse(response);
955
1172
  }
956
1173
  async linkDelete(path, opts) {
@@ -999,25 +1216,25 @@ var CimplifyClient = class {
999
1216
  }
1000
1217
  get catalogue() {
1001
1218
  if (!this._catalogue) {
1002
- this._catalogue = new chunkGHFDYM5K_js.CatalogueQueries(this);
1219
+ this._catalogue = new chunkVEOAMBEX_js.CatalogueQueries(this);
1003
1220
  }
1004
1221
  return this._catalogue;
1005
1222
  }
1006
1223
  get cart() {
1007
1224
  if (!this._cart) {
1008
- this._cart = new chunkGHFDYM5K_js.CartOperations(this);
1225
+ this._cart = new chunkVEOAMBEX_js.CartOperations(this);
1009
1226
  }
1010
1227
  return this._cart;
1011
1228
  }
1012
1229
  get checkout() {
1013
1230
  if (!this._checkout) {
1014
- this._checkout = new chunkGHFDYM5K_js.CheckoutService(this);
1231
+ this._checkout = new chunkVEOAMBEX_js.CheckoutService(this);
1015
1232
  }
1016
1233
  return this._checkout;
1017
1234
  }
1018
1235
  get orders() {
1019
1236
  if (!this._orders) {
1020
- this._orders = new chunkGHFDYM5K_js.OrderQueries(this);
1237
+ this._orders = new chunkVEOAMBEX_js.OrderQueries(this);
1021
1238
  }
1022
1239
  return this._orders;
1023
1240
  }
@@ -1047,43 +1264,43 @@ var CimplifyClient = class {
1047
1264
  }
1048
1265
  get link() {
1049
1266
  if (!this._link) {
1050
- this._link = new chunkGHFDYM5K_js.LinkService(this);
1267
+ this._link = new chunkVEOAMBEX_js.LinkService(this);
1051
1268
  }
1052
1269
  return this._link;
1053
1270
  }
1054
1271
  get auth() {
1055
1272
  if (!this._auth) {
1056
- this._auth = new chunkGHFDYM5K_js.AuthService(this);
1273
+ this._auth = new chunkVEOAMBEX_js.AuthService(this);
1057
1274
  }
1058
1275
  return this._auth;
1059
1276
  }
1060
1277
  get business() {
1061
1278
  if (!this._business) {
1062
- this._business = new chunkGHFDYM5K_js.BusinessService(this);
1279
+ this._business = new chunkVEOAMBEX_js.BusinessService(this);
1063
1280
  }
1064
1281
  return this._business;
1065
1282
  }
1066
1283
  get inventory() {
1067
1284
  if (!this._inventory) {
1068
- this._inventory = new chunkGHFDYM5K_js.InventoryService(this);
1285
+ this._inventory = new chunkVEOAMBEX_js.InventoryService(this);
1069
1286
  }
1070
1287
  return this._inventory;
1071
1288
  }
1072
1289
  get scheduling() {
1073
1290
  if (!this._scheduling) {
1074
- this._scheduling = new chunkGHFDYM5K_js.SchedulingService(this);
1291
+ this._scheduling = new chunkVEOAMBEX_js.SchedulingService(this);
1075
1292
  }
1076
1293
  return this._scheduling;
1077
1294
  }
1078
1295
  get lite() {
1079
1296
  if (!this._lite) {
1080
- this._lite = new chunkGHFDYM5K_js.LiteService(this);
1297
+ this._lite = new chunkVEOAMBEX_js.LiteService(this);
1081
1298
  }
1082
1299
  return this._lite;
1083
1300
  }
1084
1301
  get fx() {
1085
1302
  if (!this._fx) {
1086
- this._fx = new chunkGHFDYM5K_js.FxService(this);
1303
+ this._fx = new chunkVEOAMBEX_js.FxService(this);
1087
1304
  }
1088
1305
  return this._fx;
1089
1306
  }
@@ -1118,7 +1335,7 @@ var CimplifyClient = class {
1118
1335
  if (businessId) {
1119
1336
  this.setBusinessId(businessId);
1120
1337
  }
1121
- return chunkGHFDYM5K_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
1338
+ return chunkVEOAMBEX_js.createElements(this, businessId ?? this.businessId ?? void 0, options);
1122
1339
  }
1123
1340
  };
1124
1341
  function createCimplifyClient(config = {}) {
@@ -1128,7 +1345,10 @@ function createCimplifyClient(config = {}) {
1128
1345
  exports.ActivityService = ActivityService;
1129
1346
  exports.CimplifyClient = CimplifyClient;
1130
1347
  exports.DeliveryService = DeliveryService;
1348
+ exports.MUTATION_ERROR = MUTATION_ERROR;
1131
1349
  exports.PlacesService = PlacesService;
1350
+ exports.SESSION_CLAIMED = SESSION_CLAIMED;
1351
+ exports.SESSION_CLEARED = SESSION_CLEARED;
1132
1352
  exports.StoreCreditQueries = StoreCreditQueries;
1133
1353
  exports.SubscriptionService = SubscriptionService;
1134
1354
  exports.SupportService = SupportService;