@cimplify/sdk 0.92.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 (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 +13 -5
  35. package/dist/react.d.ts +13 -5
  36. package/dist/react.js +174 -75
  37. package/dist/react.mjs +156 -58
  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
- export { k as AuthService, C as BusinessService, O as CartOperations, P as CatalogueQueries, ab as CheckoutOperations, ab as CheckoutService, ah as CimplifyElement, ai as CimplifyElements, aK as ELEMENT_TYPES, aL as EVENT_TYPES, aO as ElementEventType, aP as ElementOptions, aQ as ElementType, aY as ElementsOptions, b4 as FetchQuoteInput, bd as FxService, bh as GetProductsOptions, bk as InventoryService, bs as LinkService, by as LiteService, bF as MESSAGE_TYPES, c5 as OrderQueries, cr as PriceQuote, cx as QuoteBundleSelectionInput, cy as QuoteCompositeSelectionInput, cz as QuoteDynamicBuckets, cA as QuoteStatus, cB as QuoteUiMessage, cD as RefreshQuoteInput, cE as RefreshQuoteResult, d4 as SchedulingService, dK as createElements } from './client-BQbSKlHS.mjs';
2
- import './product-bZ8G5Z8D.mjs';
3
- import './payment-BFtLqiG2.mjs';
1
+ export { k as AuthService, C as BusinessService, O as CartOperations, P as CatalogueQueries, ab as CheckoutOperations, ab as CheckoutService, ah as CimplifyElement, ai as CimplifyElements, aK as ELEMENT_TYPES, aL as EVENT_TYPES, aO as ElementEventType, aP as ElementOptions, aQ as ElementType, aY as ElementsOptions, b4 as FetchQuoteInput, bd as FxService, bh as GetProductsOptions, bk as InventoryService, bs as LinkService, by as LiteService, bF as MESSAGE_TYPES, c5 as OrderQueries, cr as PriceQuote, cx as QuoteBundleSelectionInput, cy as QuoteCompositeSelectionInput, cz as QuoteDynamicBuckets, cA as QuoteStatus, cB as QuoteUiMessage, cD as RefreshQuoteInput, cE as RefreshQuoteResult, d4 as SchedulingService, dK as createElements } from './client-BTL9d_nN.mjs';
2
+ import './product-O8-wcHSe.mjs';
3
+ import './payment-pKPpaORI.mjs';
4
4
 
5
5
  declare function generateIdempotencyKey(prefix?: string): string;
6
6
 
@@ -1,6 +1,6 @@
1
- export { k as AuthService, C as BusinessService, O as CartOperations, P as CatalogueQueries, ab as CheckoutOperations, ab as CheckoutService, ah as CimplifyElement, ai as CimplifyElements, aK as ELEMENT_TYPES, aL as EVENT_TYPES, aO as ElementEventType, aP as ElementOptions, aQ as ElementType, aY as ElementsOptions, b4 as FetchQuoteInput, bd as FxService, bh as GetProductsOptions, bk as InventoryService, bs as LinkService, by as LiteService, bF as MESSAGE_TYPES, c5 as OrderQueries, cr as PriceQuote, cx as QuoteBundleSelectionInput, cy as QuoteCompositeSelectionInput, cz as QuoteDynamicBuckets, cA as QuoteStatus, cB as QuoteUiMessage, cD as RefreshQuoteInput, cE as RefreshQuoteResult, d4 as SchedulingService, dK as createElements } from './client-CeW3acve.js';
2
- import './product-bZ8G5Z8D.js';
3
- import './payment-Cq8FT1B6.js';
1
+ export { k as AuthService, C as BusinessService, O as CartOperations, P as CatalogueQueries, ab as CheckoutOperations, ab as CheckoutService, ah as CimplifyElement, ai as CimplifyElements, aK as ELEMENT_TYPES, aL as EVENT_TYPES, aO as ElementEventType, aP as ElementOptions, aQ as ElementType, aY as ElementsOptions, b4 as FetchQuoteInput, bd as FxService, bh as GetProductsOptions, bk as InventoryService, bs as LinkService, by as LiteService, bF as MESSAGE_TYPES, c5 as OrderQueries, cr as PriceQuote, cx as QuoteBundleSelectionInput, cy as QuoteCompositeSelectionInput, cz as QuoteDynamicBuckets, cA as QuoteStatus, cB as QuoteUiMessage, cD as RefreshQuoteInput, cE as RefreshQuoteResult, d4 as SchedulingService, dK as createElements } from './client-BX30FAWZ.js';
2
+ import './product-O8-wcHSe.js';
3
+ import './payment-By0JidTe.js';
4
4
 
5
5
  declare function generateIdempotencyKey(prefix?: string): string;
6
6
 
package/dist/advanced.js CHANGED
@@ -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
  require('./chunk-PTPOQVXS.js');
5
5
  require('./chunk-AETVRBKI.js');
6
6
  require('./chunk-OWW5GUSB.js');
@@ -9,77 +9,77 @@ require('./chunk-OWW5GUSB.js');
9
9
 
10
10
  Object.defineProperty(exports, "AuthService", {
11
11
  enumerable: true,
12
- get: function () { return chunkIVJEUGWF_js.AuthService; }
12
+ get: function () { return chunkVEOAMBEX_js.AuthService; }
13
13
  });
14
14
  Object.defineProperty(exports, "BusinessService", {
15
15
  enumerable: true,
16
- get: function () { return chunkIVJEUGWF_js.BusinessService; }
16
+ get: function () { return chunkVEOAMBEX_js.BusinessService; }
17
17
  });
18
18
  Object.defineProperty(exports, "CartOperations", {
19
19
  enumerable: true,
20
- get: function () { return chunkIVJEUGWF_js.CartOperations; }
20
+ get: function () { return chunkVEOAMBEX_js.CartOperations; }
21
21
  });
22
22
  Object.defineProperty(exports, "CatalogueQueries", {
23
23
  enumerable: true,
24
- get: function () { return chunkIVJEUGWF_js.CatalogueQueries; }
24
+ get: function () { return chunkVEOAMBEX_js.CatalogueQueries; }
25
25
  });
26
26
  Object.defineProperty(exports, "CheckoutOperations", {
27
27
  enumerable: true,
28
- get: function () { return chunkIVJEUGWF_js.CheckoutService; }
28
+ get: function () { return chunkVEOAMBEX_js.CheckoutService; }
29
29
  });
30
30
  Object.defineProperty(exports, "CheckoutService", {
31
31
  enumerable: true,
32
- get: function () { return chunkIVJEUGWF_js.CheckoutService; }
32
+ get: function () { return chunkVEOAMBEX_js.CheckoutService; }
33
33
  });
34
34
  Object.defineProperty(exports, "CimplifyElement", {
35
35
  enumerable: true,
36
- get: function () { return chunkIVJEUGWF_js.CimplifyElement; }
36
+ get: function () { return chunkVEOAMBEX_js.CimplifyElement; }
37
37
  });
38
38
  Object.defineProperty(exports, "CimplifyElements", {
39
39
  enumerable: true,
40
- get: function () { return chunkIVJEUGWF_js.CimplifyElements; }
40
+ get: function () { return chunkVEOAMBEX_js.CimplifyElements; }
41
41
  });
42
42
  Object.defineProperty(exports, "ELEMENT_TYPES", {
43
43
  enumerable: true,
44
- get: function () { return chunkIVJEUGWF_js.ELEMENT_TYPES; }
44
+ get: function () { return chunkVEOAMBEX_js.ELEMENT_TYPES; }
45
45
  });
46
46
  Object.defineProperty(exports, "EVENT_TYPES", {
47
47
  enumerable: true,
48
- get: function () { return chunkIVJEUGWF_js.EVENT_TYPES; }
48
+ get: function () { return chunkVEOAMBEX_js.EVENT_TYPES; }
49
49
  });
50
50
  Object.defineProperty(exports, "FxService", {
51
51
  enumerable: true,
52
- get: function () { return chunkIVJEUGWF_js.FxService; }
52
+ get: function () { return chunkVEOAMBEX_js.FxService; }
53
53
  });
54
54
  Object.defineProperty(exports, "InventoryService", {
55
55
  enumerable: true,
56
- get: function () { return chunkIVJEUGWF_js.InventoryService; }
56
+ get: function () { return chunkVEOAMBEX_js.InventoryService; }
57
57
  });
58
58
  Object.defineProperty(exports, "LinkService", {
59
59
  enumerable: true,
60
- get: function () { return chunkIVJEUGWF_js.LinkService; }
60
+ get: function () { return chunkVEOAMBEX_js.LinkService; }
61
61
  });
62
62
  Object.defineProperty(exports, "LiteService", {
63
63
  enumerable: true,
64
- get: function () { return chunkIVJEUGWF_js.LiteService; }
64
+ get: function () { return chunkVEOAMBEX_js.LiteService; }
65
65
  });
66
66
  Object.defineProperty(exports, "MESSAGE_TYPES", {
67
67
  enumerable: true,
68
- get: function () { return chunkIVJEUGWF_js.MESSAGE_TYPES; }
68
+ get: function () { return chunkVEOAMBEX_js.MESSAGE_TYPES; }
69
69
  });
70
70
  Object.defineProperty(exports, "OrderQueries", {
71
71
  enumerable: true,
72
- get: function () { return chunkIVJEUGWF_js.OrderQueries; }
72
+ get: function () { return chunkVEOAMBEX_js.OrderQueries; }
73
73
  });
74
74
  Object.defineProperty(exports, "SchedulingService", {
75
75
  enumerable: true,
76
- get: function () { return chunkIVJEUGWF_js.SchedulingService; }
76
+ get: function () { return chunkVEOAMBEX_js.SchedulingService; }
77
77
  });
78
78
  Object.defineProperty(exports, "createElements", {
79
79
  enumerable: true,
80
- get: function () { return chunkIVJEUGWF_js.createElements; }
80
+ get: function () { return chunkVEOAMBEX_js.createElements; }
81
81
  });
82
82
  Object.defineProperty(exports, "generateIdempotencyKey", {
83
83
  enumerable: true,
84
- get: function () { return chunkIVJEUGWF_js.generateIdempotencyKey; }
84
+ get: function () { return chunkVEOAMBEX_js.generateIdempotencyKey; }
85
85
  });
package/dist/advanced.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { AuthService, BusinessService, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyElement, CimplifyElements, ELEMENT_TYPES, EVENT_TYPES, FxService, InventoryService, LinkService, LiteService, MESSAGE_TYPES, OrderQueries, SchedulingService, createElements, generateIdempotencyKey } from './chunk-T7LDBZZZ.mjs';
1
+ export { AuthService, BusinessService, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyElement, CimplifyElements, ELEMENT_TYPES, EVENT_TYPES, FxService, InventoryService, LinkService, LiteService, MESSAGE_TYPES, OrderQueries, SchedulingService, createElements, generateIdempotencyKey } from './chunk-VUSHG3HA.mjs';
2
2
  import './chunk-KFLGQGMC.mjs';
3
3
  import './chunk-K5EN2W2Q.mjs';
4
4
  import './chunk-3G6RQLXK.mjs';
@@ -2482,6 +2482,10 @@ function buildV1(deps) {
2482
2482
  "/support/conversation",
2483
2483
  (c) => tryRoute(c, () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id))
2484
2484
  );
2485
+ app.get(
2486
+ "/support/conversation",
2487
+ (c) => tryRoute(c, () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id))
2488
+ );
2485
2489
  app.post("/support/conversation/messages", async (c) => {
2486
2490
  const body = await c.req.json().catch(() => ({}));
2487
2491
  return tryRoute(
@@ -5480,6 +5484,13 @@ function createSupportService(opts) {
5480
5484
  registry.conversations.put(id, conv);
5481
5485
  return conv;
5482
5486
  },
5487
+ peekConversation(businessId, customerId) {
5488
+ const matches = registry.conversations.list(
5489
+ (c) => c.business_id === businessId && c.customer_id === customerId
5490
+ );
5491
+ const conv = matches[matches.length - 1];
5492
+ return conv ? { conversation: conv, messages: conv.messages } : { conversation: null, messages: [] };
5493
+ },
5483
5494
  sendMessage(conversationId, body) {
5484
5495
  const conv = registry.conversations.get(conversationId);
5485
5496
  if (!conv) throw notFound(`Conversation ${conversationId} not found`);
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkOAHSF542_js = require('./chunk-OAHSF542.js');
4
- var chunkDCRN67NO_js = require('./chunk-DCRN67NO.js');
3
+ var chunk6Y7KC5YZ_js = require('./chunk-6Y7KC5YZ.js');
4
+ var chunkQLGZIBRO_js = require('./chunk-QLGZIBRO.js');
5
5
  var zod = require('zod');
6
6
 
7
7
  var cimplifyRegistry = zod.z.registry();
@@ -600,7 +600,7 @@ async function toForwardedRequest(input, init) {
600
600
  };
601
601
  }
602
602
  function createTestClient(options = {}) {
603
- const mock = chunkOAHSF542_js.createMockApp(options);
603
+ const mock = chunk6Y7KC5YZ_js.createMockApp(options);
604
604
  let sessionToken;
605
605
  const fetchImpl = async (input, init) => {
606
606
  const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
@@ -619,7 +619,7 @@ function createTestClient(options = {}) {
619
619
  if (echoed) sessionToken = echoed;
620
620
  return res;
621
621
  };
622
- const client = chunkDCRN67NO_js.createCimplifyClient({
622
+ const client = chunkQLGZIBRO_js.createCimplifyClient({
623
623
  baseUrl: TEST_BASE_URL,
624
624
  // Link mock lives at /v1/link on the same Hono app, so point the SDK's
625
625
  // separate Link transport at the same TEST_BASE_URL.
@@ -1,4 +1,4 @@
1
- import { safe, generateIdempotencyKey, err, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-T7LDBZZZ.mjs';
1
+ import { safe, generateIdempotencyKey, err, ok, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-VUSHG3HA.mjs';
2
2
  import { CimplifyError, ErrorCode, IdempotencyMismatchError, enrichError } from './chunk-K5EN2W2Q.mjs';
3
3
 
4
4
  // src/store-credit.ts
@@ -72,6 +72,21 @@ var ActivityService = class {
72
72
  is_new_visitor: isNewVisitor
73
73
  };
74
74
  }
75
+ /**
76
+ * Record a page the visitor landed on. Product and category views already
77
+ * imply one, so call this for everything else — home, listings, booking,
78
+ * checkout — or entry pages, exits and bounce rate are computed from
79
+ * product pages alone.
80
+ */
81
+ trackPageView(options = {}) {
82
+ this.sendEvents([
83
+ {
84
+ type: "page_view",
85
+ page_path: options.pagePath ?? currentPath(),
86
+ page_title: options.pageTitle ?? currentTitle()
87
+ }
88
+ ]);
89
+ }
75
90
  trackProductView(productId, options = {}) {
76
91
  const event = {
77
92
  type: "product_view",
@@ -120,6 +135,12 @@ function currentPath() {
120
135
  }
121
136
  return void 0;
122
137
  }
138
+ function currentTitle() {
139
+ if (typeof document !== "undefined" && document.title) {
140
+ return document.title;
141
+ }
142
+ return void 0;
143
+ }
123
144
  function resolveVisitor() {
124
145
  try {
125
146
  const existing = localStorage.getItem(VISITOR_ID_STORAGE_KEY);
@@ -331,16 +352,21 @@ function createClientEvents() {
331
352
  }
332
353
 
333
354
  // src/support.ts
355
+ var CLAIM_TIMEOUT_MS = 15e3;
334
356
  var SupportService = class {
335
357
  constructor(client) {
336
358
  this.client = client;
337
359
  this.claimInFlight = null;
360
+ this.claimInFlightToken = null;
338
361
  this.lastClaimedAccessToken = null;
339
362
  this.claimedName = null;
340
363
  this.client.events.on(SESSION_CLEARED, () => {
341
364
  this.lastClaimedAccessToken = null;
342
365
  this.claimedName = null;
343
366
  });
367
+ this.client.events.on(SESSION_CLAIMED, (event) => {
368
+ if (event.customerName) this.claimedName = event.customerName;
369
+ });
344
370
  }
345
371
  /** The verified customer this session's conversation was claimed for, null while anonymous. */
346
372
  get claimedCustomerName() {
@@ -361,20 +387,34 @@ var SupportService = class {
361
387
  if (!accessToken) {
362
388
  return err(new CimplifyError("not_authenticated", "No access token to claim with"));
363
389
  }
364
- if (this.claimInFlight) return this.claimInFlight;
390
+ if (this.claimInFlight) {
391
+ if (this.claimInFlightToken === accessToken) return this.claimInFlight;
392
+ await this.claimInFlight;
393
+ return this.claimConversation();
394
+ }
365
395
  if (this.lastClaimedAccessToken === accessToken) {
366
396
  return err(new CimplifyError("already_claimed", "Session already claimed for this token"));
367
397
  }
398
+ const epoch = this.client.getSessionEpoch();
399
+ this.claimInFlightToken = accessToken;
368
400
  this.claimInFlight = (async () => {
369
401
  const result = await safe(
370
- this.client.post("/api/v1/support/conversation/claim", {
371
- access_token: accessToken
372
- })
402
+ this.client.post(
403
+ "/api/v1/support/conversation/claim",
404
+ { access_token: accessToken },
405
+ { timeoutMs: CLAIM_TIMEOUT_MS }
406
+ )
373
407
  );
374
408
  if (result.ok) {
409
+ if (this.client.getSessionEpoch() !== epoch) {
410
+ return err(
411
+ new CimplifyError("session_cleared", "Session was cleared during the claim")
412
+ );
413
+ }
375
414
  this.lastClaimedAccessToken = accessToken;
376
415
  this.claimedName = result.value.customer_name || null;
377
416
  this.client.adoptSessionToken(result.value.session_token);
417
+ this.client.publishSessionClaimed(this.claimedName);
378
418
  this.client.events.emit(SESSION_CLAIMED, {
379
419
  sessionToken: result.value.session_token,
380
420
  threadId: result.value.thread_id ?? null,
@@ -387,8 +427,25 @@ var SupportService = class {
387
427
  return await this.claimInFlight;
388
428
  } finally {
389
429
  this.claimInFlight = null;
430
+ this.claimInFlightToken = null;
390
431
  }
391
432
  }
433
+ /**
434
+ * Peek at the conversation without creating one: resolves the existing
435
+ * thread (or null) so a page load can hydrate history without littering
436
+ * the inbox with empty threads.
437
+ */
438
+ async peekConversation() {
439
+ const result = await safe(
440
+ this.client.get("/api/v1/support/conversation")
441
+ );
442
+ if (!result.ok) return result;
443
+ if (!result.value.conversation) return ok(null);
444
+ return ok({
445
+ conversation: result.value.conversation,
446
+ messages: result.value.messages
447
+ });
448
+ }
392
449
  /** Open (or resume) the customer's widget conversation. */
393
450
  async openConversation(opts) {
394
451
  const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
@@ -458,6 +515,7 @@ var SupportService = class {
458
515
 
459
516
  // src/client.ts
460
517
  var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
518
+ var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
461
519
  var ORDER_TOKEN_PREFIX = "cimplify_ot_";
462
520
  var SESSION_TOKEN_HEADER = "x-session-token";
463
521
  var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -574,6 +632,7 @@ var CimplifyClient = class {
574
632
  constructor(config = {}) {
575
633
  this.accessToken = null;
576
634
  this.sessionToken = null;
635
+ this.sessionEpoch = 0;
577
636
  this.context = {};
578
637
  this.businessId = null;
579
638
  this.businessIdResolvePromise = null;
@@ -596,6 +655,7 @@ var CimplifyClient = class {
596
655
  this.hooks = config.hooks ?? {};
597
656
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
598
657
  this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
658
+ this.watchCrossTabSession();
599
659
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
600
660
  console.warn(
601
661
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -662,10 +722,15 @@ var CimplifyClient = class {
662
722
  const previous = this.accessToken;
663
723
  this.accessToken = null;
664
724
  this.sessionToken = null;
665
- if (typeof window !== "undefined" && window.localStorage) {
666
- localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
725
+ this.sessionEpoch++;
726
+ try {
727
+ this.safeStorage()?.removeItem(SESSION_TOKEN_STORAGE_KEY);
728
+ } catch {
667
729
  }
668
730
  this.sessionToken = this.mintSessionToken();
731
+ if (this.sessionToken) {
732
+ this.broadcastSessionSync({ type: "cleared", token: this.sessionToken });
733
+ }
669
734
  this.hooks.onSessionChange?.({
670
735
  previousToken: previous,
671
736
  newToken: null,
@@ -674,42 +739,89 @@ var CimplifyClient = class {
674
739
  this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
675
740
  this.events.emit(SESSION_CLEARED, {});
676
741
  }
677
- setOrderToken(orderId, token) {
678
- if (typeof window !== "undefined" && window.localStorage) {
742
+ getSessionEpoch() {
743
+ return this.sessionEpoch;
744
+ }
745
+ publishSessionClaimed(customerName) {
746
+ if (!this.sessionToken) return;
747
+ this.broadcastSessionSync({
748
+ type: "claimed",
749
+ token: this.sessionToken,
750
+ name: customerName
751
+ });
752
+ }
753
+ broadcastSessionSync(payload) {
754
+ try {
755
+ this.safeStorage()?.setItem(
756
+ SESSION_SYNC_STORAGE_KEY,
757
+ JSON.stringify({ ...payload, at: Date.now() })
758
+ );
759
+ } catch {
760
+ }
761
+ }
762
+ watchCrossTabSession() {
763
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
764
+ window.addEventListener("storage", (event) => {
765
+ if (event.key !== SESSION_SYNC_STORAGE_KEY || !event.newValue) return;
766
+ let payload;
679
767
  try {
680
- const entry = JSON.stringify({ token, storedAt: Date.now() });
681
- localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
768
+ payload = JSON.parse(event.newValue);
682
769
  } catch {
770
+ return;
771
+ }
772
+ if (!payload?.token || payload.token === this.sessionToken) return;
773
+ if (payload.type === "claimed") {
774
+ this.sessionToken = payload.token;
775
+ this.events.emit(SESSION_CLAIMED, {
776
+ sessionToken: payload.token,
777
+ threadId: null,
778
+ customerName: payload.name ?? ""
779
+ });
780
+ } else if (payload.type === "cleared") {
781
+ this.accessToken = null;
782
+ this.sessionToken = payload.token;
783
+ this.sessionEpoch++;
784
+ this.events.emit(AUTH_TOKEN_CHANGED, { token: null });
785
+ this.events.emit(SESSION_CLEARED, {});
683
786
  }
787
+ });
788
+ }
789
+ setOrderToken(orderId, token) {
790
+ try {
791
+ const entry = JSON.stringify({ token, storedAt: Date.now() });
792
+ this.safeStorage()?.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
793
+ } catch {
684
794
  }
685
795
  }
686
796
  getOrderToken(orderId) {
687
- if (typeof window !== "undefined" && window.localStorage) {
688
- try {
689
- const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
690
- if (!raw) return null;
691
- const entry = JSON.parse(raw);
692
- if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
693
- localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
694
- return null;
695
- }
696
- return entry.token;
697
- } catch {
797
+ try {
798
+ const storage = this.safeStorage();
799
+ if (!storage) return null;
800
+ const raw = storage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
801
+ if (!raw) return null;
802
+ const entry = JSON.parse(raw);
803
+ if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
804
+ storage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
698
805
  return null;
699
806
  }
807
+ return entry.token;
808
+ } catch {
809
+ return null;
700
810
  }
701
- return null;
702
811
  }
703
812
  clearOrderTokens() {
704
- if (typeof window !== "undefined" && window.localStorage) {
813
+ try {
814
+ const storage = this.safeStorage();
815
+ if (!storage) return;
705
816
  const keysToRemove = [];
706
- for (let i = 0; i < localStorage.length; i++) {
707
- const key = localStorage.key(i);
817
+ for (let i = 0; i < storage.length; i++) {
818
+ const key = storage.key(i);
708
819
  if (key?.startsWith(ORDER_TOKEN_PREFIX)) {
709
820
  keysToRemove.push(key);
710
821
  }
711
822
  }
712
- keysToRemove.forEach((k) => localStorage.removeItem(k));
823
+ keysToRemove.forEach((k) => storage.removeItem(k));
824
+ } catch {
713
825
  }
714
826
  }
715
827
  setLocationId(locationId) {
@@ -768,22 +880,29 @@ var CimplifyClient = class {
768
880
  this.businessIdResolvePromise = null;
769
881
  }
770
882
  }
771
- async authedFetch(url, options) {
772
- return this.resilientFetch(url, options);
883
+ async authedFetch(url, options, timeoutMs) {
884
+ return this.resilientFetch(url, options, timeoutMs);
773
885
  }
774
886
  // Storage guards: even the `window.localStorage` property access throws in
775
887
  // some sandboxed iframes and strict private-browsing modes. These run in the
776
888
  // constructor at module load, so a throw would white-screen the whole app —
777
889
  // fall back to an in-memory session token instead.
778
- loadSessionToken() {
890
+ safeStorage() {
779
891
  try {
780
892
  if (typeof window !== "undefined" && window.localStorage) {
781
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
893
+ return window.localStorage;
782
894
  }
783
895
  } catch {
784
896
  }
785
897
  return null;
786
898
  }
899
+ loadSessionToken() {
900
+ try {
901
+ return this.safeStorage()?.getItem(SESSION_TOKEN_STORAGE_KEY) ?? null;
902
+ } catch {
903
+ return null;
904
+ }
905
+ }
787
906
  /**
788
907
  * Mint the session token client-side so the very first request already
789
908
  * carries it. Without this, parallel first-load requests each get a
@@ -803,15 +922,15 @@ var CimplifyClient = class {
803
922
  }
804
923
  saveSessionToken(token) {
805
924
  try {
806
- if (typeof window !== "undefined" && window.localStorage) {
807
- localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
808
- }
925
+ this.safeStorage()?.setItem(SESSION_TOKEN_STORAGE_KEY, token);
809
926
  } catch {
810
927
  }
811
928
  }
812
929
  captureSessionToken(response) {
930
+ if (typeof window === "undefined") return;
931
+ if (this.sessionToken) return;
813
932
  const token = response.headers.get(SESSION_TOKEN_HEADER);
814
- if (token && token !== this.sessionToken) {
933
+ if (token) {
815
934
  this.sessionToken = token;
816
935
  this.saveSessionToken(token);
817
936
  }
@@ -839,7 +958,7 @@ var CimplifyClient = class {
839
958
  }
840
959
  return headers;
841
960
  }
842
- async resilientFetch(url, options) {
961
+ async resilientFetch(url, options, timeoutMs) {
843
962
  const method = options.method || "GET";
844
963
  const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
845
964
  const startTime = Date.now();
@@ -856,7 +975,7 @@ var CimplifyClient = class {
856
975
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
857
976
  try {
858
977
  const controller = new AbortController();
859
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
978
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs ?? this.timeout);
860
979
  const response = await this.fetchImpl(url, {
861
980
  ...options,
862
981
  signal: controller.signal
@@ -987,29 +1106,41 @@ var CimplifyClient = class {
987
1106
  });
988
1107
  }
989
1108
  async post(path, body, opts) {
990
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
991
- method: "POST",
992
- credentials: this.credentials,
993
- headers: mergeOptionHeaders(this.getHeaders(), opts),
994
- body: body ? JSON.stringify(body) : void 0
995
- });
1109
+ const response = await this.authedFetch(
1110
+ this.buildUrl(this.baseUrl, path),
1111
+ {
1112
+ method: "POST",
1113
+ credentials: this.credentials,
1114
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1115
+ body: body ? JSON.stringify(body) : void 0
1116
+ },
1117
+ opts?.timeoutMs
1118
+ );
996
1119
  return this.handleRestResponse(response);
997
1120
  }
998
1121
  async patch(path, body, opts) {
999
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
1000
- method: "PATCH",
1001
- credentials: this.credentials,
1002
- headers: mergeOptionHeaders(this.getHeaders(), opts),
1003
- body: body ? JSON.stringify(body) : void 0
1004
- });
1122
+ const response = await this.authedFetch(
1123
+ this.buildUrl(this.baseUrl, path),
1124
+ {
1125
+ method: "PATCH",
1126
+ credentials: this.credentials,
1127
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1128
+ body: body ? JSON.stringify(body) : void 0
1129
+ },
1130
+ opts?.timeoutMs
1131
+ );
1005
1132
  return this.handleRestResponse(response);
1006
1133
  }
1007
1134
  async delete(path, opts) {
1008
- const response = await this.authedFetch(this.buildUrl(this.baseUrl, path), {
1009
- method: "DELETE",
1010
- credentials: this.credentials,
1011
- headers: mergeOptionHeaders(this.getHeaders(), opts)
1012
- });
1135
+ const response = await this.authedFetch(
1136
+ this.buildUrl(this.baseUrl, path),
1137
+ {
1138
+ method: "DELETE",
1139
+ credentials: this.credentials,
1140
+ headers: mergeOptionHeaders(this.getHeaders(), opts)
1141
+ },
1142
+ opts?.timeoutMs
1143
+ );
1013
1144
  return this.handleRestResponse(response);
1014
1145
  }
1015
1146
  async linkGet(path, opts) {
@@ -1025,12 +1156,16 @@ var CimplifyClient = class {
1025
1156
  });
1026
1157
  }
1027
1158
  async linkPost(path, body, opts) {
1028
- const response = await this.authedFetch(`${this.linkApiUrl}${path}`, {
1029
- method: "POST",
1030
- credentials: this.credentials,
1031
- headers: mergeOptionHeaders(this.getHeaders(), opts),
1032
- body: body ? JSON.stringify(body) : void 0
1033
- });
1159
+ const response = await this.authedFetch(
1160
+ `${this.linkApiUrl}${path}`,
1161
+ {
1162
+ method: "POST",
1163
+ credentials: this.credentials,
1164
+ headers: mergeOptionHeaders(this.getHeaders(), opts),
1165
+ body: body ? JSON.stringify(body) : void 0
1166
+ },
1167
+ opts?.timeoutMs
1168
+ );
1034
1169
  return this.handleRestResponse(response);
1035
1170
  }
1036
1171
  async linkDelete(path, opts) {