@cimplify/sdk 0.88.0 → 0.90.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/{chunk-A7NODD4Q.mjs → chunk-2UDEWILL.mjs} +83 -17
  4. package/dist/{chunk-W5BVGAO6.js → chunk-BN4V4ONE.js} +83 -17
  5. package/dist/{chunk-6JA4HBBD.js → chunk-JVWFIFQ7.js} +4 -4
  6. package/dist/{chunk-ROBTTS3Q.js → chunk-KJP4U6L3.js} +28 -1
  7. package/dist/{chunk-VU5LFNEX.mjs → chunk-NGE37REW.mjs} +2 -2
  8. package/dist/{chunk-APBLFZ2I.mjs → chunk-NNGKC3MM.mjs} +28 -1
  9. package/dist/chunk-U4MW6PYU.mjs +23 -0
  10. package/dist/chunk-XREIZ56K.js +26 -0
  11. package/dist/{client-D0PrO1-Q.d.ts → client-CR1f94wY.d.ts} +97 -7
  12. package/dist/{client-B3FBDfTg.d.ts → client-CqpOcbin.d.ts} +2 -2
  13. package/dist/{client-B-8ceVyt.d.mts → client-DMttx1xk.d.mts} +2 -2
  14. package/dist/{client-r5VSGFRU.d.mts → client-YiSelM7x.d.mts} +97 -7
  15. package/dist/{index-C-Pxrzna.d.ts → index-CxTVu0HZ.d.ts} +3 -3
  16. package/dist/{index-DLulxmF1.d.mts → index-DD9z396M.d.mts} +3 -3
  17. package/dist/index.d.mts +6 -6
  18. package/dist/index.d.ts +6 -6
  19. package/dist/index.js +17 -10
  20. package/dist/index.mjs +8 -2
  21. package/dist/mock/cli.mjs +49 -1
  22. package/dist/mock/library.js +49 -1
  23. package/dist/mock/library.mjs +49 -1
  24. package/dist/mock/msw.js +49 -1
  25. package/dist/mock/msw.mjs +49 -1
  26. package/dist/{payment-TnJUoHqL.d.mts → payment-5d8FTA1q.d.mts} +1 -1
  27. package/dist/{payment-Cfoo9MT7.d.ts → payment-BX7ccIKY.d.ts} +1 -1
  28. package/dist/{price-CCDSrIsc.d.ts → price-DtfP_Xfq.d.ts} +1 -1
  29. package/dist/{price-CM0zVSyM.d.mts → price-arl_4Rzn.d.mts} +1 -1
  30. package/dist/{product-DoA36Eqh.d.mts → product-DZX4QuKS.d.mts} +68 -4
  31. package/dist/{product-DoA36Eqh.d.ts → product-DZX4QuKS.d.ts} +68 -4
  32. package/dist/react.d.mts +405 -7
  33. package/dist/react.d.ts +405 -7
  34. package/dist/react.js +2345 -74
  35. package/dist/react.mjs +2323 -72
  36. package/dist/{server-CI1CUFVu.d.mts → server-BceZMxcK.d.mts} +8 -1
  37. package/dist/{server-CHfYeTAa.d.ts → server-DoJGSC7L.d.ts} +8 -1
  38. package/dist/server.d.mts +4 -4
  39. package/dist/server.d.ts +4 -4
  40. package/dist/server.js +2 -2
  41. package/dist/server.mjs +1 -1
  42. package/dist/styles.css +1 -1
  43. package/dist/testing/msw.d.mts +2 -2
  44. package/dist/testing/msw.d.ts +2 -2
  45. package/dist/testing/msw.js +3 -2
  46. package/dist/testing/msw.mjs +2 -1
  47. package/dist/testing/suite.d.mts +6 -6
  48. package/dist/testing/suite.d.ts +6 -6
  49. package/dist/testing/suite.js +23 -22
  50. package/dist/testing/suite.mjs +4 -3
  51. package/dist/testing.d.mts +5 -5
  52. package/dist/testing.d.ts +5 -5
  53. package/dist/testing.js +79 -78
  54. package/dist/testing.mjs +5 -4
  55. package/dist/utils.d.mts +4 -4
  56. package/dist/utils.d.ts +4 -4
  57. package/package.json +4 -1
  58. package/registry/chat-widget.json +1 -1
  59. package/registry/product-customizer.json +1 -1
@@ -1,6 +1,6 @@
1
- export { k as AuthService, C as BusinessService, O as CartOperations, P as CatalogueQueries, a8 as CheckoutOperations, a8 as CheckoutService, ae as CimplifyElement, af as CimplifyElements, aG as ELEMENT_TYPES, aH as EVENT_TYPES, aK as ElementEventType, aL as ElementOptions, aM as ElementType, aU as ElementsOptions, b0 as FetchQuoteInput, b9 as FxService, bd as GetProductsOptions, bg as InventoryService, bo as LinkService, bs as LiteService, bz as MESSAGE_TYPES, b$ as OrderQueries, cl as PriceQuote, cr as QuoteBundleSelectionInput, cs as QuoteCompositeSelectionInput, ct as QuoteDynamicBuckets, cu as QuoteStatus, cv as QuoteUiMessage, cx as RefreshQuoteInput, cy as RefreshQuoteResult, c_ as SchedulingService, dE as createElements } from './client-r5VSGFRU.mjs';
2
- import './product-DoA36Eqh.mjs';
3
- import './payment-TnJUoHqL.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, aJ as ELEMENT_TYPES, aK as EVENT_TYPES, aN as ElementEventType, aO as ElementOptions, aP as ElementType, aX as ElementsOptions, b3 as FetchQuoteInput, bc as FxService, bg as GetProductsOptions, bj as InventoryService, br as LinkService, bx as LiteService, bE as MESSAGE_TYPES, c4 as OrderQueries, cq as PriceQuote, cw as QuoteBundleSelectionInput, cx as QuoteCompositeSelectionInput, cy as QuoteDynamicBuckets, cz as QuoteStatus, cA as QuoteUiMessage, cC as RefreshQuoteInput, cD as RefreshQuoteResult, d3 as SchedulingService, dK as createElements } from './client-YiSelM7x.mjs';
2
+ import './product-DZX4QuKS.mjs';
3
+ import './payment-5d8FTA1q.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, a8 as CheckoutOperations, a8 as CheckoutService, ae as CimplifyElement, af as CimplifyElements, aG as ELEMENT_TYPES, aH as EVENT_TYPES, aK as ElementEventType, aL as ElementOptions, aM as ElementType, aU as ElementsOptions, b0 as FetchQuoteInput, b9 as FxService, bd as GetProductsOptions, bg as InventoryService, bo as LinkService, bs as LiteService, bz as MESSAGE_TYPES, b$ as OrderQueries, cl as PriceQuote, cr as QuoteBundleSelectionInput, cs as QuoteCompositeSelectionInput, ct as QuoteDynamicBuckets, cu as QuoteStatus, cv as QuoteUiMessage, cx as RefreshQuoteInput, cy as RefreshQuoteResult, c_ as SchedulingService, dE as createElements } from './client-D0PrO1-Q.js';
2
- import './product-DoA36Eqh.js';
3
- import './payment-Cfoo9MT7.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, aJ as ELEMENT_TYPES, aK as EVENT_TYPES, aN as ElementEventType, aO as ElementOptions, aP as ElementType, aX as ElementsOptions, b3 as FetchQuoteInput, bc as FxService, bg as GetProductsOptions, bj as InventoryService, br as LinkService, bx as LiteService, bE as MESSAGE_TYPES, c4 as OrderQueries, cq as PriceQuote, cw as QuoteBundleSelectionInput, cx as QuoteCompositeSelectionInput, cy as QuoteDynamicBuckets, cz as QuoteStatus, cA as QuoteUiMessage, cC as RefreshQuoteInput, cD as RefreshQuoteResult, d3 as SchedulingService, dK as createElements } from './client-CR1f94wY.js';
2
+ import './product-DZX4QuKS.js';
3
+ import './payment-BX7ccIKY.js';
4
4
 
5
5
  declare function generateIdempotencyKey(prefix?: string): string;
6
6
 
@@ -307,26 +307,62 @@ var SupportService = class {
307
307
  })
308
308
  );
309
309
  }
310
- /** Send a message in the active conversation. */
310
+ /**
311
+ * Send a message in the active conversation.
312
+ *
313
+ * The idempotency key doubles as the message `client_id`: the backend
314
+ * dedupes on it, so client retries of the same send never insert twice.
315
+ * `replyToMessageId` quotes another message by its `ChatMessage.id`; the
316
+ * server resolves it thread-scoped and echoes the quote as `reply_to`.
317
+ */
311
318
  async sendMessage(content, opts) {
312
319
  const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
313
320
  return safe(
314
321
  this.client.post(
315
322
  "/api/v1/support/conversation/messages",
316
- { content },
323
+ {
324
+ content,
325
+ client_id: idempotencyKey,
326
+ reply_to_message_id: opts?.replyToMessageId,
327
+ upload_ids: opts?.attachments?.map((a) => a.upload_id)
328
+ },
317
329
  { idempotencyKey }
318
330
  )
319
331
  );
320
332
  }
321
- /** Poll for new messages since the given cursor. */
333
+ /**
334
+ * Poll for messages. `after` pages forward (live updates); `before` pages
335
+ * backward for scrollback into older history.
336
+ */
322
337
  async getMessages(options = {}) {
323
338
  const params = new URLSearchParams();
324
339
  if (options.after) params.set("after", options.after);
340
+ if (options.before) params.set("before", options.before);
325
341
  if (options.limit) params.set("limit", String(options.limit));
326
342
  const query = params.toString();
327
343
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
328
344
  return safe(this.client.get(path));
329
345
  }
346
+ /** React to a message in the active conversation by its `ChatMessage.id`. */
347
+ async reactToMessage(messageId, emoji) {
348
+ return safe(
349
+ this.client.post(
350
+ `/api/v1/support/conversation/messages/${messageId}/reactions`,
351
+ { emoji }
352
+ )
353
+ );
354
+ }
355
+ /** Ask for a person: flags the thread for the merchant's inbox. */
356
+ async requestHuman(opts) {
357
+ const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
358
+ return safe(
359
+ this.client.post(
360
+ "/api/v1/support/conversation/handoff",
361
+ void 0,
362
+ { idempotencyKey }
363
+ )
364
+ );
365
+ }
330
366
  };
331
367
 
332
368
  // src/internal/events.ts
@@ -394,6 +430,16 @@ function mergeOptionHeaders(base, opts) {
394
430
  }
395
431
  return merged;
396
432
  }
433
+ function generateSessionToken() {
434
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
435
+ return crypto.randomUUID();
436
+ }
437
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
438
+ const r = Math.random() * 16 | 0;
439
+ const v = c === "x" ? r : r & 3 | 8;
440
+ return v.toString(16);
441
+ });
442
+ }
397
443
  function isRetryable(error) {
398
444
  if (error instanceof TypeError && error.message.includes("fetch")) {
399
445
  return true;
@@ -491,7 +537,7 @@ var CimplifyClient = class {
491
537
  this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
492
538
  this.hooks = config.hooks ?? {};
493
539
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
494
- this.sessionToken = this.loadSessionToken();
540
+ this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
495
541
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
496
542
  console.warn(
497
543
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -539,6 +585,7 @@ var CimplifyClient = class {
539
585
  if (typeof window !== "undefined" && window.localStorage) {
540
586
  localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
541
587
  }
588
+ this.sessionToken = this.mintSessionToken();
542
589
  this.hooks.onSessionChange?.({
543
590
  previousToken: previous,
544
591
  newToken: null,
@@ -642,18 +689,42 @@ var CimplifyClient = class {
642
689
  async authedFetch(url, options) {
643
690
  return this.resilientFetch(url, options);
644
691
  }
692
+ // Storage guards: even the `window.localStorage` property access throws in
693
+ // some sandboxed iframes and strict private-browsing modes. These run in the
694
+ // constructor at module load, so a throw would white-screen the whole app —
695
+ // fall back to an in-memory session token instead.
645
696
  loadSessionToken() {
646
- if (typeof window !== "undefined" && window.localStorage) {
647
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
697
+ try {
698
+ if (typeof window !== "undefined" && window.localStorage) {
699
+ return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
700
+ }
701
+ } catch {
648
702
  }
649
703
  return null;
650
704
  }
705
+ /**
706
+ * Mint the session token client-side so the very first request already
707
+ * carries it. Without this, parallel first-load requests each get a
708
+ * different server-minted token and last-writer-wins splits the session
709
+ * (cart writes and chat conversations land on dropped tokens).
710
+ *
711
+ * Browser-only: minting on a server-shared client instance would pin
712
+ * every visitor to one session, so SSR keeps the lazy server-minted flow.
713
+ */
714
+ mintSessionToken() {
715
+ if (typeof window === "undefined") {
716
+ return null;
717
+ }
718
+ const token = generateSessionToken();
719
+ this.saveSessionToken(token);
720
+ return token;
721
+ }
651
722
  saveSessionToken(token) {
652
- if (typeof window !== "undefined" && window.localStorage) {
653
- try {
723
+ try {
724
+ if (typeof window !== "undefined" && window.localStorage) {
654
725
  localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
655
- } catch {
656
726
  }
727
+ } catch {
657
728
  }
658
729
  }
659
730
  captureSessionToken(response) {
@@ -898,14 +969,9 @@ var CimplifyClient = class {
898
969
  const originalCreatedAt = typeof json.error === "object" && json.error?.original_created_at || "";
899
970
  throw new IdempotencyMismatchError(errorMessage, originalCreatedAt);
900
971
  }
901
- const error = enrichError(
902
- new CimplifyError(
903
- errorCode,
904
- errorMessage,
905
- retryable
906
- ),
907
- { isTestMode: this.isTestMode() }
908
- );
972
+ const error = enrichError(new CimplifyError(errorCode, errorMessage, retryable), {
973
+ isTestMode: this.isTestMode()
974
+ });
909
975
  if ((response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) && this.accessToken) {
910
976
  console.warn(
911
977
  "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
@@ -309,26 +309,62 @@ var SupportService = class {
309
309
  })
310
310
  );
311
311
  }
312
- /** Send a message in the active conversation. */
312
+ /**
313
+ * Send a message in the active conversation.
314
+ *
315
+ * The idempotency key doubles as the message `client_id`: the backend
316
+ * dedupes on it, so client retries of the same send never insert twice.
317
+ * `replyToMessageId` quotes another message by its `ChatMessage.id`; the
318
+ * server resolves it thread-scoped and echoes the quote as `reply_to`.
319
+ */
313
320
  async sendMessage(content, opts) {
314
321
  const idempotencyKey = opts?.idempotencyKey ?? chunkGHFDYM5K_js.generateIdempotencyKey();
315
322
  return chunkGHFDYM5K_js.safe(
316
323
  this.client.post(
317
324
  "/api/v1/support/conversation/messages",
318
- { content },
325
+ {
326
+ content,
327
+ client_id: idempotencyKey,
328
+ reply_to_message_id: opts?.replyToMessageId,
329
+ upload_ids: opts?.attachments?.map((a) => a.upload_id)
330
+ },
319
331
  { idempotencyKey }
320
332
  )
321
333
  );
322
334
  }
323
- /** Poll for new messages since the given cursor. */
335
+ /**
336
+ * Poll for messages. `after` pages forward (live updates); `before` pages
337
+ * backward for scrollback into older history.
338
+ */
324
339
  async getMessages(options = {}) {
325
340
  const params = new URLSearchParams();
326
341
  if (options.after) params.set("after", options.after);
342
+ if (options.before) params.set("before", options.before);
327
343
  if (options.limit) params.set("limit", String(options.limit));
328
344
  const query = params.toString();
329
345
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
330
346
  return chunkGHFDYM5K_js.safe(this.client.get(path));
331
347
  }
348
+ /** React to a message in the active conversation by its `ChatMessage.id`. */
349
+ async reactToMessage(messageId, emoji) {
350
+ return chunkGHFDYM5K_js.safe(
351
+ this.client.post(
352
+ `/api/v1/support/conversation/messages/${messageId}/reactions`,
353
+ { emoji }
354
+ )
355
+ );
356
+ }
357
+ /** Ask for a person: flags the thread for the merchant's inbox. */
358
+ async requestHuman(opts) {
359
+ const idempotencyKey = opts?.idempotencyKey ?? chunkGHFDYM5K_js.generateIdempotencyKey();
360
+ return chunkGHFDYM5K_js.safe(
361
+ this.client.post(
362
+ "/api/v1/support/conversation/handoff",
363
+ void 0,
364
+ { idempotencyKey }
365
+ )
366
+ );
367
+ }
332
368
  };
333
369
 
334
370
  // src/internal/events.ts
@@ -396,6 +432,16 @@ function mergeOptionHeaders(base, opts) {
396
432
  }
397
433
  return merged;
398
434
  }
435
+ function generateSessionToken() {
436
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
437
+ return crypto.randomUUID();
438
+ }
439
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
440
+ const r = Math.random() * 16 | 0;
441
+ const v = c === "x" ? r : r & 3 | 8;
442
+ return v.toString(16);
443
+ });
444
+ }
399
445
  function isRetryable(error) {
400
446
  if (error instanceof TypeError && error.message.includes("fetch")) {
401
447
  return true;
@@ -493,7 +539,7 @@ var CimplifyClient = class {
493
539
  this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
494
540
  this.hooks = config.hooks ?? {};
495
541
  this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
496
- this.sessionToken = this.loadSessionToken();
542
+ this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
497
543
  if (!this.publicKey && !config.suppressPublicKeyWarning) {
498
544
  console.warn(
499
545
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "cpk_..." } to createCimplifyClient().'
@@ -541,6 +587,7 @@ var CimplifyClient = class {
541
587
  if (typeof window !== "undefined" && window.localStorage) {
542
588
  localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
543
589
  }
590
+ this.sessionToken = this.mintSessionToken();
544
591
  this.hooks.onSessionChange?.({
545
592
  previousToken: previous,
546
593
  newToken: null,
@@ -644,18 +691,42 @@ var CimplifyClient = class {
644
691
  async authedFetch(url, options) {
645
692
  return this.resilientFetch(url, options);
646
693
  }
694
+ // Storage guards: even the `window.localStorage` property access throws in
695
+ // some sandboxed iframes and strict private-browsing modes. These run in the
696
+ // constructor at module load, so a throw would white-screen the whole app —
697
+ // fall back to an in-memory session token instead.
647
698
  loadSessionToken() {
648
- if (typeof window !== "undefined" && window.localStorage) {
649
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
699
+ try {
700
+ if (typeof window !== "undefined" && window.localStorage) {
701
+ return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
702
+ }
703
+ } catch {
650
704
  }
651
705
  return null;
652
706
  }
707
+ /**
708
+ * Mint the session token client-side so the very first request already
709
+ * carries it. Without this, parallel first-load requests each get a
710
+ * different server-minted token and last-writer-wins splits the session
711
+ * (cart writes and chat conversations land on dropped tokens).
712
+ *
713
+ * Browser-only: minting on a server-shared client instance would pin
714
+ * every visitor to one session, so SSR keeps the lazy server-minted flow.
715
+ */
716
+ mintSessionToken() {
717
+ if (typeof window === "undefined") {
718
+ return null;
719
+ }
720
+ const token = generateSessionToken();
721
+ this.saveSessionToken(token);
722
+ return token;
723
+ }
653
724
  saveSessionToken(token) {
654
- if (typeof window !== "undefined" && window.localStorage) {
655
- try {
725
+ try {
726
+ if (typeof window !== "undefined" && window.localStorage) {
656
727
  localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
657
- } catch {
658
728
  }
729
+ } catch {
659
730
  }
660
731
  }
661
732
  captureSessionToken(response) {
@@ -900,14 +971,9 @@ var CimplifyClient = class {
900
971
  const originalCreatedAt = typeof json.error === "object" && json.error?.original_created_at || "";
901
972
  throw new chunkAETVRBKI_js.IdempotencyMismatchError(errorMessage, originalCreatedAt);
902
973
  }
903
- const error = chunkAETVRBKI_js.enrichError(
904
- new chunkAETVRBKI_js.CimplifyError(
905
- errorCode,
906
- errorMessage,
907
- retryable
908
- ),
909
- { isTestMode: this.isTestMode() }
910
- );
974
+ const error = chunkAETVRBKI_js.enrichError(new chunkAETVRBKI_js.CimplifyError(errorCode, errorMessage, retryable), {
975
+ isTestMode: this.isTestMode()
976
+ });
911
977
  if ((response.status === 401 || error.code === chunkAETVRBKI_js.ErrorCode.UNAUTHORIZED) && this.accessToken) {
912
978
  console.warn(
913
979
  "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkROBTTS3Q_js = require('./chunk-ROBTTS3Q.js');
4
- var chunkW5BVGAO6_js = require('./chunk-W5BVGAO6.js');
3
+ var chunkKJP4U6L3_js = require('./chunk-KJP4U6L3.js');
4
+ var chunkBN4V4ONE_js = require('./chunk-BN4V4ONE.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 = chunkROBTTS3Q_js.createMockApp(options);
603
+ const mock = chunkKJP4U6L3_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 = chunkW5BVGAO6_js.createCimplifyClient({
622
+ const client = chunkBN4V4ONE_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,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var chunkXREIZ56K_js = require('./chunk-XREIZ56K.js');
3
4
  var chunkAETVRBKI_js = require('./chunk-AETVRBKI.js');
4
5
  var chunkOWW5GUSB_js = require('./chunk-OWW5GUSB.js');
5
6
 
@@ -2485,13 +2486,18 @@ function buildV1(deps) {
2485
2486
  const body = await c.req.json().catch(() => ({}));
2486
2487
  return tryRoute(
2487
2488
  c,
2488
- () => deps.support.sendMessage(body.conversation_id ?? "", { content: body.content ?? "", content_type: body.content_type, sender_type: body.sender_type })
2489
+ () => deps.support.sendMessage(body.conversation_id ?? "", { content: body.content ?? "", content_type: body.content_type, sender_type: body.sender_type, reply_to_message_id: body.reply_to_message_id })
2489
2490
  );
2490
2491
  });
2491
2492
  app.get(
2492
2493
  "/support/conversation/messages",
2493
2494
  (c) => tryRoute(c, () => deps.support.listMessages(c.req.query("conversation_id") ?? "", { limit: getQueryNum(c, "limit") }))
2494
2495
  );
2496
+ app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
2497
+ const body = await c.req.json().catch(() => ({}));
2498
+ return tryRoute(c, () => deps.support.react(c.req.param("messageId"), body.emoji ?? ""));
2499
+ });
2500
+ app.post("/support/conversation/handoff", (c) => c.json({ data: { requested: true } }));
2495
2501
  app.get(
2496
2502
  "/support/conversation/ws",
2497
2503
  (c) => c.json({ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false }, 426)
@@ -5465,12 +5471,14 @@ function createSupportService(opts) {
5465
5471
  sendMessage(conversationId, body) {
5466
5472
  const conv = registry.conversations.get(conversationId);
5467
5473
  if (!conv) throw notFound(`Conversation ${conversationId} not found`);
5474
+ const target = body.reply_to_message_id ? conv.messages.find((m) => m.id === body.reply_to_message_id) : void 0;
5468
5475
  const msg = {
5469
5476
  id: ids.message(),
5470
5477
  conversation_id: conversationId,
5471
5478
  sender_type: body.sender_type ?? "customer",
5472
5479
  content_type: body.content_type ?? "text",
5473
5480
  content: body.content,
5481
+ reply_to: target ? { id: target.id, sender_type: target.sender_type, preview: chunkXREIZ56K_js.messagePreview(target.content) } : void 0,
5474
5482
  created_at: clock.iso()
5475
5483
  };
5476
5484
  conv.messages.push(msg);
@@ -5492,6 +5500,25 @@ function createSupportService(opts) {
5492
5500
  }
5493
5501
  return msg;
5494
5502
  },
5503
+ react(messageId, emoji) {
5504
+ for (const conv of registry.conversations.values()) {
5505
+ const target = conv.messages.find((m) => m.id === messageId);
5506
+ if (!target) continue;
5507
+ const reaction = {
5508
+ id: ids.message(),
5509
+ conversation_id: conv.id,
5510
+ sender_type: "customer",
5511
+ content_type: "text",
5512
+ content: emoji,
5513
+ reply_to: { id: target.id, sender_type: target.sender_type, preview: chunkXREIZ56K_js.messagePreview(target.content) },
5514
+ created_at: clock.iso()
5515
+ };
5516
+ conv.messages.push(reaction);
5517
+ registry.conversations.put(conv.id, conv);
5518
+ return reaction;
5519
+ }
5520
+ throw notFound(`Message ${messageId} not found`);
5521
+ },
5495
5522
  listMessages(conversationId, opts2) {
5496
5523
  const conv = registry.conversations.get(conversationId);
5497
5524
  if (!conv) throw notFound(`Conversation ${conversationId} not found`);
@@ -1,5 +1,5 @@
1
- import { createMockApp } from './chunk-APBLFZ2I.mjs';
2
- import { createCimplifyClient } from './chunk-A7NODD4Q.mjs';
1
+ import { createMockApp } from './chunk-NNGKC3MM.mjs';
2
+ import { createCimplifyClient } from './chunk-2UDEWILL.mjs';
3
3
  import { z } from 'zod';
4
4
 
5
5
  var cimplifyRegistry = z.registry();
@@ -1,3 +1,4 @@
1
+ import { messagePreview } from './chunk-U4MW6PYU.mjs';
1
2
  import { ErrorCode } from './chunk-K5EN2W2Q.mjs';
2
3
  import { __publicField, __privateAdd, __privateSet, __privateGet, __privateMethod, __privateWrapper } from './chunk-3G6RQLXK.mjs';
3
4
 
@@ -2483,13 +2484,18 @@ function buildV1(deps) {
2483
2484
  const body = await c.req.json().catch(() => ({}));
2484
2485
  return tryRoute(
2485
2486
  c,
2486
- () => deps.support.sendMessage(body.conversation_id ?? "", { content: body.content ?? "", content_type: body.content_type, sender_type: body.sender_type })
2487
+ () => deps.support.sendMessage(body.conversation_id ?? "", { content: body.content ?? "", content_type: body.content_type, sender_type: body.sender_type, reply_to_message_id: body.reply_to_message_id })
2487
2488
  );
2488
2489
  });
2489
2490
  app.get(
2490
2491
  "/support/conversation/messages",
2491
2492
  (c) => tryRoute(c, () => deps.support.listMessages(c.req.query("conversation_id") ?? "", { limit: getQueryNum(c, "limit") }))
2492
2493
  );
2494
+ app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
2495
+ const body = await c.req.json().catch(() => ({}));
2496
+ return tryRoute(c, () => deps.support.react(c.req.param("messageId"), body.emoji ?? ""));
2497
+ });
2498
+ app.post("/support/conversation/handoff", (c) => c.json({ data: { requested: true } }));
2493
2499
  app.get(
2494
2500
  "/support/conversation/ws",
2495
2501
  (c) => c.json({ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false }, 426)
@@ -5463,12 +5469,14 @@ function createSupportService(opts) {
5463
5469
  sendMessage(conversationId, body) {
5464
5470
  const conv = registry.conversations.get(conversationId);
5465
5471
  if (!conv) throw notFound(`Conversation ${conversationId} not found`);
5472
+ const target = body.reply_to_message_id ? conv.messages.find((m) => m.id === body.reply_to_message_id) : void 0;
5466
5473
  const msg = {
5467
5474
  id: ids.message(),
5468
5475
  conversation_id: conversationId,
5469
5476
  sender_type: body.sender_type ?? "customer",
5470
5477
  content_type: body.content_type ?? "text",
5471
5478
  content: body.content,
5479
+ reply_to: target ? { id: target.id, sender_type: target.sender_type, preview: messagePreview(target.content) } : void 0,
5472
5480
  created_at: clock.iso()
5473
5481
  };
5474
5482
  conv.messages.push(msg);
@@ -5490,6 +5498,25 @@ function createSupportService(opts) {
5490
5498
  }
5491
5499
  return msg;
5492
5500
  },
5501
+ react(messageId, emoji) {
5502
+ for (const conv of registry.conversations.values()) {
5503
+ const target = conv.messages.find((m) => m.id === messageId);
5504
+ if (!target) continue;
5505
+ const reaction = {
5506
+ id: ids.message(),
5507
+ conversation_id: conv.id,
5508
+ sender_type: "customer",
5509
+ content_type: "text",
5510
+ content: emoji,
5511
+ reply_to: { id: target.id, sender_type: target.sender_type, preview: messagePreview(target.content) },
5512
+ created_at: clock.iso()
5513
+ };
5514
+ conv.messages.push(reaction);
5515
+ registry.conversations.put(conv.id, conv);
5516
+ return reaction;
5517
+ }
5518
+ throw notFound(`Message ${messageId} not found`);
5519
+ },
5493
5520
  listMessages(conversationId, opts2) {
5494
5521
  const conv = registry.conversations.get(conversationId);
5495
5522
  if (!conv) throw notFound(`Conversation ${conversationId} not found`);
@@ -0,0 +1,23 @@
1
+ // src/genui/segments.ts
2
+ var FENCE_PATTERN = /```genui\s*\n([\s\S]*?)(?:```|$)/g;
3
+ function splitGenUIContent(content) {
4
+ const segments = [];
5
+ let cursor = 0;
6
+ for (const match of content.matchAll(FENCE_PATTERN)) {
7
+ const prose = content.slice(cursor, match.index).trim();
8
+ if (prose) segments.push({ kind: "prose", text: prose });
9
+ const source = match[1].trim();
10
+ if (source) segments.push({ kind: "program", source });
11
+ cursor = match.index + match[0].length;
12
+ }
13
+ const tail = content.slice(cursor).trim();
14
+ if (tail) segments.push({ kind: "prose", text: tail });
15
+ return segments;
16
+ }
17
+ function messagePreview(content, max = 90) {
18
+ const prose = splitGenUIContent(content).filter((segment) => segment.kind === "prose").map((segment) => segment.text).join(" ").replace(/\s+/g, " ").trim();
19
+ if (!prose) return "Structured answer";
20
+ return prose.length > max ? `${prose.slice(0, max)}\u2026` : prose;
21
+ }
22
+
23
+ export { messagePreview, splitGenUIContent };
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ // src/genui/segments.ts
4
+ var FENCE_PATTERN = /```genui\s*\n([\s\S]*?)(?:```|$)/g;
5
+ function splitGenUIContent(content) {
6
+ const segments = [];
7
+ let cursor = 0;
8
+ for (const match of content.matchAll(FENCE_PATTERN)) {
9
+ const prose = content.slice(cursor, match.index).trim();
10
+ if (prose) segments.push({ kind: "prose", text: prose });
11
+ const source = match[1].trim();
12
+ if (source) segments.push({ kind: "program", source });
13
+ cursor = match.index + match[0].length;
14
+ }
15
+ const tail = content.slice(cursor).trim();
16
+ if (tail) segments.push({ kind: "prose", text: tail });
17
+ return segments;
18
+ }
19
+ function messagePreview(content, max = 90) {
20
+ const prose = splitGenUIContent(content).filter((segment) => segment.kind === "prose").map((segment) => segment.text).join(" ").replace(/\s+/g, " ").trim();
21
+ if (!prose) return "Structured answer";
22
+ return prose.length > max ? `${prose.slice(0, max)}\u2026` : prose;
23
+ }
24
+
25
+ exports.messagePreview = messagePreview;
26
+ exports.splitGenUIContent = splitGenUIContent;