@cimplify/sdk 0.89.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-DENWOZEA.mjs → chunk-2UDEWILL.mjs} +46 -8
  4. package/dist/{chunk-T2CJ67QV.js → chunk-BN4V4ONE.js} +46 -8
  5. package/dist/{chunk-JHJTXAPS.js → chunk-JVWFIFQ7.js} +4 -4
  6. package/dist/{chunk-ROBTTS3Q.js → chunk-KJP4U6L3.js} +28 -1
  7. package/dist/{chunk-M4ALCELT.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-CqZgdUtw.d.ts → client-CR1f94wY.d.ts} +81 -6
  12. package/dist/{client-CUbwb6Om.d.ts → client-CqpOcbin.d.ts} +2 -2
  13. package/dist/{client-CAY2NbRG.d.mts → client-DMttx1xk.d.mts} +2 -2
  14. package/dist/{client-D8ZFs-sq.d.mts → client-YiSelM7x.d.mts} +81 -6
  15. package/dist/{index-Bc5qUxAt.d.ts → index-CxTVu0HZ.d.ts} +3 -3
  16. package/dist/{index-CmWOz9bi.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-Dcgb9n1n.d.mts → payment-5d8FTA1q.d.mts} +1 -1
  27. package/dist/{payment-Xq0WDZXh.d.ts → payment-BX7ccIKY.d.ts} +1 -1
  28. package/dist/{price-DAAjKgAp.d.ts → price-DtfP_Xfq.d.ts} +1 -1
  29. package/dist/{price--Ma_WO5_.d.mts → price-arl_4Rzn.d.mts} +1 -1
  30. package/dist/{product-BakHcsP2.d.mts → product-DZX4QuKS.d.mts} +57 -2
  31. package/dist/{product-BakHcsP2.d.ts → product-DZX4QuKS.d.ts} +57 -2
  32. package/dist/react.d.mts +405 -7
  33. package/dist/react.d.ts +405 -7
  34. package/dist/react.js +2325 -69
  35. package/dist/react.mjs +2303 -67
  36. package/dist/{server-Bk_hlefX.d.mts → server-BceZMxcK.d.mts} +8 -1
  37. package/dist/{server-Bei5lBrc.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
package/dist/react.js CHANGED
@@ -2,7 +2,8 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkT7Z25EY4_js = require('./chunk-T7Z25EY4.js');
5
- var chunkT2CJ67QV_js = require('./chunk-T2CJ67QV.js');
5
+ var chunkXREIZ56K_js = require('./chunk-XREIZ56K.js');
6
+ var chunkBN4V4ONE_js = require('./chunk-BN4V4ONE.js');
6
7
  var chunkGHFDYM5K_js = require('./chunk-GHFDYM5K.js');
7
8
  var chunkPTPOQVXS_js = require('./chunk-PTPOQVXS.js');
8
9
  var chunkAETVRBKI_js = require('./chunk-AETVRBKI.js');
@@ -25,6 +26,8 @@ var xss = require('xss');
25
26
  var dialog = require('@base-ui/react/dialog');
26
27
  var field = require('@base-ui/react/field');
27
28
  var input = require('@base-ui/react/input');
29
+ var DOMPurify = require('dompurify');
30
+ var marked = require('marked');
28
31
 
29
32
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
33
 
@@ -48,6 +51,7 @@ function _interopNamespace(e) {
48
51
 
49
52
  var React14__default = /*#__PURE__*/_interopDefault(React14);
50
53
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
54
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
51
55
 
52
56
  // src/ads/identity.ts
53
57
  var COOKIE_NAME = "_cimplify_uid";
@@ -790,15 +794,15 @@ function deriveView(base, ops) {
790
794
  };
791
795
  }
792
796
  async function syncFromServer(entry) {
793
- if (entry.syncing) return;
794
- entry.syncing = true;
795
- try {
797
+ const run = async () => {
796
798
  const result = await entry.client.cart.get();
797
799
  if (!result.ok) throw result.error;
798
800
  entry.collection.setBase(mapServerCart(result.value, entry.currency));
799
- } finally {
800
- entry.syncing = false;
801
- }
801
+ };
802
+ const next = entry.syncTail.then(run, run);
803
+ entry.syncTail = next.catch(() => {
804
+ });
805
+ return next;
802
806
  }
803
807
  function emitMutationError(entry, operation, opId, idempotencyKey, error) {
804
808
  entry.client.events.emit("mutation:error", {
@@ -838,7 +842,7 @@ function getOrCreateStore(params) {
838
842
  optimisticEnabled,
839
843
  initialized: false,
840
844
  initializePromise: null,
841
- syncing: false,
845
+ syncTail: Promise.resolve(),
842
846
  failedOpRemovers: /* @__PURE__ */ new Set()
843
847
  };
844
848
  cartStores.set(storeKey, entry);
@@ -1132,7 +1136,7 @@ var DEFAULT_COUNTRY = "US";
1132
1136
  function createDefaultClient() {
1133
1137
  const processRef = globalThis.process;
1134
1138
  const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
1135
- return chunkT2CJ67QV_js.createCimplifyClient({ publicKey: envPublicKey });
1139
+ return chunkBN4V4ONE_js.createCimplifyClient({ publicKey: envPublicKey });
1136
1140
  }
1137
1141
  function getStoredLocationId() {
1138
1142
  if (typeof window === "undefined" || !window.localStorage) {
@@ -4303,7 +4307,7 @@ function Price({
4303
4307
  ] });
4304
4308
  }
4305
4309
  function createCachedQuery(config) {
4306
- const cache = /* @__PURE__ */ new Map();
4310
+ const cache2 = /* @__PURE__ */ new Map();
4307
4311
  const inflight = /* @__PURE__ */ new Map();
4308
4312
  const gcMaxAge = config.gcMaxAge ?? 3e5;
4309
4313
  let lastSweep = 0;
@@ -4312,8 +4316,8 @@ function createCachedQuery(config) {
4312
4316
  if (now - lastSweep < 6e4) return;
4313
4317
  lastSweep = now;
4314
4318
  const cutoff = now - gcMaxAge;
4315
- for (const [key, entry] of cache) {
4316
- if (entry.ts < cutoff) cache.delete(key);
4319
+ for (const [key, entry] of cache2) {
4320
+ if (entry.ts < cutoff) cache2.delete(key);
4317
4321
  }
4318
4322
  }
4319
4323
  function useCachedQuery(options = {}) {
@@ -4331,13 +4335,13 @@ function createCachedQuery(config) {
4331
4335
  const optionsRef = React14.useRef(options);
4332
4336
  optionsRef.current = options;
4333
4337
  if (config.locationSensitive && previousLocationRef.current !== locationId) {
4334
- cache.clear();
4338
+ cache2.clear();
4335
4339
  inflight.clear();
4336
4340
  previousLocationRef.current = locationId;
4337
4341
  }
4338
4342
  sweep();
4339
4343
  const cacheKey2 = config.key(client, options);
4340
- const cached = cache.get(cacheKey2);
4344
+ const cached = cache2.get(cacheKey2);
4341
4345
  const [data, setData] = React14.useState(cached?.data ?? null);
4342
4346
  const [isLoading, setIsLoading] = React14.useState(enabled && !cached);
4343
4347
  const [error, setError] = React14.useState(null);
@@ -4350,7 +4354,7 @@ function createCachedQuery(config) {
4350
4354
  const nextRequestId = ++requestIdRef.current;
4351
4355
  setError(null);
4352
4356
  if (!force) {
4353
- const hit = cache.get(cacheKey2);
4357
+ const hit = cache2.get(cacheKey2);
4354
4358
  if (hit) {
4355
4359
  setData(hit.data);
4356
4360
  setIsLoading(false);
@@ -4367,7 +4371,7 @@ function createCachedQuery(config) {
4367
4371
  });
4368
4372
  }
4369
4373
  const value = await promise;
4370
- cache.set(cacheKey2, { data: value, ts: Date.now() });
4374
+ cache2.set(cacheKey2, { data: value, ts: Date.now() });
4371
4375
  if (nextRequestId === requestIdRef.current) {
4372
4376
  setData(value);
4373
4377
  setError(null);
@@ -4388,23 +4392,23 @@ function createCachedQuery(config) {
4388
4392
  void load(false);
4389
4393
  }, [load]);
4390
4394
  const refetch = React14.useCallback(async () => {
4391
- cache.delete(cacheKey2);
4395
+ cache2.delete(cacheKey2);
4392
4396
  await load(true);
4393
4397
  }, [cacheKey2, load]);
4394
4398
  return { data, isLoading, error, refetch };
4395
4399
  }
4396
4400
  useCachedQuery.prefetch = (client, options) => {
4397
4401
  const key = config.key(client, options);
4398
- if (cache.has(key) || inflight.has(key)) return void 0;
4402
+ if (cache2.has(key) || inflight.has(key)) return void 0;
4399
4403
  const promise = config.fetch(client, options);
4400
4404
  inflight.set(key, promise);
4401
4405
  return promise.then((value) => {
4402
- cache.set(key, { data: value, ts: Date.now() });
4406
+ cache2.set(key, { data: value, ts: Date.now() });
4403
4407
  }).catch(() => {
4404
4408
  }).finally(() => inflight.delete(key));
4405
4409
  };
4406
4410
  useCachedQuery.clear = () => {
4407
- cache.clear();
4411
+ cache2.clear();
4408
4412
  inflight.clear();
4409
4413
  };
4410
4414
  return useCachedQuery;
@@ -4532,6 +4536,9 @@ function useCategories(options = {}) {
4532
4536
  return { categories: data ?? [], isLoading, error, refetch };
4533
4537
  }
4534
4538
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled", "refunded"]);
4539
+ function isTerminalOrderStatus(status) {
4540
+ return TERMINAL_STATUSES.has(status);
4541
+ }
4535
4542
  var orderCache = /* @__PURE__ */ new Map();
4536
4543
  var orderInflight = /* @__PURE__ */ new Map();
4537
4544
  function buildOrderCacheKey(client, orderId) {
@@ -5373,6 +5380,9 @@ function useOrders(options = {}) {
5373
5380
  const { data, isLoading, error, refetch } = ordersQuery(options);
5374
5381
  return { orders: data ?? [], isLoading, error, refetch };
5375
5382
  }
5383
+ function clearOrdersCache() {
5384
+ ordersQuery.clear();
5385
+ }
5376
5386
  function useSubscriptions(options = {}) {
5377
5387
  const { client } = useCimplifyClient();
5378
5388
  const { status, enabled = true } = options;
@@ -5878,6 +5888,7 @@ var POLL_IDLE_INTERVAL_MS = 15e3;
5878
5888
  var IDLE_TIMEOUT_MS = 6e4;
5879
5889
  var WS_MAX_RECONNECT_ATTEMPTS = 10;
5880
5890
  var WS_PATH = "/api/v1/support/conversation/ws";
5891
+ var AWAIT_REPLY_TIMEOUT_MS = 3e4;
5881
5892
  function useChat(options = {}) {
5882
5893
  const context = useOptionalCimplifyClient();
5883
5894
  const client = options.client ?? context?.client;
@@ -5886,6 +5897,10 @@ function useChat(options = {}) {
5886
5897
  const [isSending, setIsSending] = React14.useState(false);
5887
5898
  const [error, setError] = React14.useState(null);
5888
5899
  const [conversationOpened, setConversationOpened] = React14.useState(false);
5900
+ const [humanRequested, setHumanRequested] = React14.useState(false);
5901
+ const [awaitingReply, setAwaitingReply] = React14.useState(false);
5902
+ const [seenAt, setSeenAt] = React14.useState(null);
5903
+ const [mayHaveOlder, setMayHaveOlder] = React14.useState(false);
5889
5904
  const pollRef = React14.useRef(null);
5890
5905
  const lastActivityRef = React14.useRef(Date.now());
5891
5906
  const openedRef = React14.useRef(false);
@@ -5894,17 +5909,42 @@ function useChat(options = {}) {
5894
5909
  const wsRef = React14.useRef(null);
5895
5910
  const wsReconnectAttemptRef = React14.useRef(0);
5896
5911
  const wsReconnectTimerRef = React14.useRef(null);
5912
+ const aiEnabledRef = React14.useRef(false);
5913
+ const humanRequestedRef = React14.useRef(false);
5914
+ const awaitReplyTimerRef = React14.useRef(null);
5897
5915
  messagesRef.current = messages;
5898
5916
  clientRef.current = client;
5917
+ humanRequestedRef.current = humanRequested;
5899
5918
  const pollInterval = options.pollInterval ?? POLL_INTERVAL_MS;
5900
5919
  const pollIdleInterval = options.pollIdleInterval ?? POLL_IDLE_INTERVAL_MS;
5901
- const appendMessages = React14.useCallback((incoming) => {
5902
- setMessages((prev) => {
5903
- const ids = new Set(prev.map((m) => m.id));
5904
- const fresh = incoming.filter((m) => !ids.has(m.id));
5905
- return fresh.length > 0 ? [...prev, ...fresh] : prev;
5906
- });
5920
+ const stopAwaitingReply = React14.useCallback(() => {
5921
+ if (awaitReplyTimerRef.current) {
5922
+ clearTimeout(awaitReplyTimerRef.current);
5923
+ awaitReplyTimerRef.current = null;
5924
+ }
5925
+ setAwaitingReply(false);
5926
+ }, []);
5927
+ const startAwaitingReply = React14.useCallback(() => {
5928
+ setAwaitingReply(true);
5929
+ if (awaitReplyTimerRef.current) clearTimeout(awaitReplyTimerRef.current);
5930
+ awaitReplyTimerRef.current = setTimeout(() => {
5931
+ awaitReplyTimerRef.current = null;
5932
+ setAwaitingReply(false);
5933
+ }, AWAIT_REPLY_TIMEOUT_MS);
5907
5934
  }, []);
5935
+ const appendMessages = React14.useCallback(
5936
+ (incoming) => {
5937
+ if (incoming.some((m) => m.sender_type === "bot" || m.sender_type === "agent")) {
5938
+ stopAwaitingReply();
5939
+ }
5940
+ setMessages((prev) => {
5941
+ const ids = new Set(prev.map((m) => m.id));
5942
+ const fresh = incoming.filter((m) => !ids.has(m.id));
5943
+ return fresh.length > 0 ? [...prev, ...fresh] : prev;
5944
+ });
5945
+ },
5946
+ [stopAwaitingReply]
5947
+ );
5908
5948
  const fetchNewMessages = React14.useCallback(async () => {
5909
5949
  const c = clientRef.current;
5910
5950
  if (!c) return;
@@ -5953,6 +5993,13 @@ function useChat(options = {}) {
5953
5993
  const envelope = JSON.parse(event.data);
5954
5994
  if (envelope.type === "message.created" && envelope.data) {
5955
5995
  appendMessages([envelope.data]);
5996
+ } else if (envelope.type === "thread.read") {
5997
+ const at = envelope.data?.last_read_at;
5998
+ if (at) setSeenAt((prev) => !prev || prev < at ? at : prev);
5999
+ } else if (envelope.type === "thread.responding") {
6000
+ const active = envelope.data?.active;
6001
+ if (active) startAwaitingReply();
6002
+ else stopAwaitingReply();
5956
6003
  } else if (envelope.type === "resync") {
5957
6004
  const latest = envelope.latest_message_at;
5958
6005
  const last = messagesRef.current[messagesRef.current.length - 1];
@@ -5983,6 +6030,7 @@ function useChat(options = {}) {
5983
6030
  return () => {
5984
6031
  if (pollRef.current) clearInterval(pollRef.current);
5985
6032
  if (wsReconnectTimerRef.current) clearTimeout(wsReconnectTimerRef.current);
6033
+ if (awaitReplyTimerRef.current) clearTimeout(awaitReplyTimerRef.current);
5986
6034
  if (wsRef.current) {
5987
6035
  wsRef.current.onclose = null;
5988
6036
  wsRef.current.close();
@@ -5998,6 +6046,10 @@ function useChat(options = {}) {
5998
6046
  if (result.ok) {
5999
6047
  setMessages(result.value.messages);
6000
6048
  setConversationOpened(true);
6049
+ aiEnabledRef.current = result.value.conversation.ai_enabled;
6050
+ setHumanRequested(result.value.conversation.needs_human_review ?? false);
6051
+ setSeenAt(result.value.conversation.team_read_at ?? null);
6052
+ setMayHaveOlder(result.value.messages.length >= 50);
6001
6053
  connectWebSocket();
6002
6054
  } else {
6003
6055
  openedRef.current = false;
@@ -6006,27 +6058,39 @@ function useChat(options = {}) {
6006
6058
  setIsLoading(false);
6007
6059
  }, [client, connectWebSocket]);
6008
6060
  const send = React14.useCallback(
6009
- async (content) => {
6010
- if (!client || !content.trim()) return;
6061
+ async (content, opts) => {
6062
+ const attachments = opts?.attachments ?? [];
6063
+ if (!client || !content.trim() && attachments.length === 0) return false;
6011
6064
  setError(null);
6012
6065
  lastActivityRef.current = Date.now();
6013
6066
  if (!openedRef.current) {
6014
6067
  await openConversation();
6015
- if (!openedRef.current) return;
6068
+ if (!openedRef.current) return false;
6016
6069
  }
6070
+ const replyTo = opts?.replyTo;
6017
6071
  const optimisticId = `opt_${Date.now()}`;
6018
6072
  const optimistic = {
6019
6073
  id: optimisticId,
6020
6074
  sender_type: "customer",
6021
6075
  content: content.trim(),
6022
- content_type: "text",
6023
- attachments: [],
6076
+ content_type: attachments.length > 0 ? "image" : "text",
6077
+ attachments,
6024
6078
  metadata: {},
6079
+ // Same shape the server echoes back, so the bubble doesn't reflow
6080
+ // when the confirmed message replaces it.
6081
+ reply_to: replyTo ? {
6082
+ id: replyTo.id,
6083
+ sender_type: replyTo.sender_type,
6084
+ preview: chunkXREIZ56K_js.messagePreview(replyTo.content)
6085
+ } : void 0,
6025
6086
  created_at: (/* @__PURE__ */ new Date()).toISOString()
6026
6087
  };
6027
6088
  setMessages((prev) => [...prev, optimistic]);
6028
6089
  setIsSending(true);
6029
- const result = await client.support.sendMessage(content.trim());
6090
+ const result = await client.support.sendMessage(content.trim(), {
6091
+ replyToMessageId: replyTo?.id,
6092
+ attachments: attachments.length > 0 ? attachments : void 0
6093
+ });
6030
6094
  if (result.ok) {
6031
6095
  const confirmed = result.value;
6032
6096
  setMessages(
@@ -6037,13 +6101,17 @@ function useChat(options = {}) {
6037
6101
  prev.some((m) => m.id === confirmed.id) ? prev.filter((m) => m.id !== optimisticId) : prev.map((m) => m.id === optimisticId ? confirmed : m)
6038
6102
  )
6039
6103
  );
6104
+ if (aiEnabledRef.current && !humanRequestedRef.current) {
6105
+ startAwaitingReply();
6106
+ }
6040
6107
  } else {
6041
6108
  setMessages((prev) => prev.filter((m) => m.id !== optimisticId));
6042
6109
  setError(result.error);
6043
6110
  }
6044
6111
  setIsSending(false);
6112
+ return result.ok;
6045
6113
  },
6046
- [client, openConversation]
6114
+ [client, openConversation, startAwaitingReply]
6047
6115
  );
6048
6116
  const startConversation = React14.useCallback(
6049
6117
  async (starterText) => {
@@ -6054,14 +6122,65 @@ function useChat(options = {}) {
6054
6122
  },
6055
6123
  [openConversation, send]
6056
6124
  );
6125
+ const react = React14.useCallback(
6126
+ async (message, emoji) => {
6127
+ if (!client || message.id.startsWith("opt_")) return false;
6128
+ const result = await client.support.reactToMessage(message.id, emoji);
6129
+ if (result.ok) appendMessages([result.value]);
6130
+ return result.ok;
6131
+ },
6132
+ [client, appendMessages]
6133
+ );
6134
+ const requestHuman = React14.useCallback(async () => {
6135
+ if (!client) return false;
6136
+ setError(null);
6137
+ if (!openedRef.current) {
6138
+ await openConversation();
6139
+ if (!openedRef.current) return false;
6140
+ }
6141
+ const result = await client.support.requestHuman();
6142
+ if (result.ok) {
6143
+ setHumanRequested(true);
6144
+ return true;
6145
+ }
6146
+ setError(result.error);
6147
+ return false;
6148
+ }, [client, openConversation]);
6149
+ const loadOlder = React14.useCallback(async () => {
6150
+ const c = clientRef.current;
6151
+ const earliest = messagesRef.current[0];
6152
+ if (!c || !earliest) return false;
6153
+ const result = await c.support.getMessages({ before: earliest.created_at, limit: 50 });
6154
+ if (!result.ok) {
6155
+ setError(result.error);
6156
+ return false;
6157
+ }
6158
+ const older = result.value;
6159
+ setMayHaveOlder(older.length >= 50);
6160
+ if (older.length === 0) return false;
6161
+ setMessages((prev) => {
6162
+ const ids = new Set(prev.map((m) => m.id));
6163
+ const fresh = older.filter((m) => !ids.has(m.id));
6164
+ return fresh.length > 0 ? [...fresh, ...prev] : prev;
6165
+ });
6166
+ return true;
6167
+ }, []);
6168
+ const agentArrived = messages.some((m) => m.sender_type === "agent");
6057
6169
  return {
6058
6170
  messages,
6059
6171
  isLoading,
6060
6172
  isSending,
6061
6173
  error,
6062
6174
  isActive: conversationOpened && messages.length > 0,
6175
+ humanRequested: humanRequested && !agentArrived,
6176
+ awaitingReply,
6177
+ seenAt,
6178
+ mayHaveOlder,
6063
6179
  send,
6064
- startConversation
6180
+ startConversation,
6181
+ react,
6182
+ requestHuman,
6183
+ loadOlder
6065
6184
  };
6066
6185
  }
6067
6186
  var ElementsContext = React14.createContext({
@@ -9359,6 +9478,7 @@ function ProductCustomizer({
9359
9478
  onAddToCart,
9360
9479
  onVariantChange,
9361
9480
  showSpecialInstructions = true,
9481
+ submitLabel,
9362
9482
  className,
9363
9483
  classNames
9364
9484
  }) {
@@ -9747,8 +9867,10 @@ function ProductCustomizer({
9747
9867
  isAdded && classNames?.submitButtonAdded,
9748
9868
  classNames?.submitButton
9749
9869
  ),
9750
- children: isAdded ? "Added to Cart" : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9751
- "Add to Cart \xB7 ",
9870
+ children: isAdded ? "Added" : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9871
+ submitLabel ?? "Add to Cart",
9872
+ " \xB7",
9873
+ " ",
9752
9874
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: displayTotalPrice, currency })
9753
9875
  ] })
9754
9876
  }
@@ -9908,13 +10030,13 @@ function StoreVideo({
9908
10030
  autoplay = true,
9909
10031
  loop = true,
9910
10032
  muted = true,
9911
- lazy = true,
10033
+ lazy: lazy2 = true,
9912
10034
  className
9913
10035
  }) {
9914
10036
  const ref = React14.useRef(null);
9915
- const [inView, setInView] = React14.useState(!lazy);
10037
+ const [inView, setInView] = React14.useState(!lazy2);
9916
10038
  React14.useEffect(() => {
9917
- if (!lazy || inView) return;
10039
+ if (!lazy2 || inView) return;
9918
10040
  const node = ref.current;
9919
10041
  if (!node || typeof IntersectionObserver === "undefined") {
9920
10042
  setInView(true);
@@ -9931,7 +10053,7 @@ function StoreVideo({
9931
10053
  );
9932
10054
  observer.observe(node);
9933
10055
  return () => observer.disconnect();
9934
- }, [lazy, inView]);
10056
+ }, [lazy2, inView]);
9935
10057
  return /* @__PURE__ */ jsxRuntime.jsx(
9936
10058
  "div",
9937
10059
  {
@@ -9949,7 +10071,7 @@ function StoreVideo({
9949
10071
  muted,
9950
10072
  playsInline: true,
9951
10073
  controls,
9952
- preload: lazy ? "metadata" : "auto",
10074
+ preload: lazy2 ? "metadata" : "auto",
9953
10075
  "aria-label": alt,
9954
10076
  style: { width: "100%", height: "100%", objectFit: "cover", display: "block" },
9955
10077
  children: poster ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -16751,6 +16873,112 @@ function CurrencySelector({
16751
16873
  );
16752
16874
  }) });
16753
16875
  }
16876
+ var Streamdown = React14.lazy(() => import('streamdown').then((m) => ({ default: m.Streamdown })));
16877
+ function detectLookbehindSupport() {
16878
+ try {
16879
+ new RegExp("(?<=a)b");
16880
+ return true;
16881
+ } catch {
16882
+ return false;
16883
+ }
16884
+ }
16885
+ var supportsRegExpLookbehind = detectLookbehindSupport();
16886
+ marked.marked.setOptions({
16887
+ gfm: true,
16888
+ breaks: true
16889
+ });
16890
+ var ALLOWED_TAGS = [
16891
+ "a",
16892
+ "b",
16893
+ "blockquote",
16894
+ "br",
16895
+ "code",
16896
+ "del",
16897
+ "em",
16898
+ "h1",
16899
+ "h2",
16900
+ "h3",
16901
+ "h4",
16902
+ "hr",
16903
+ "i",
16904
+ "li",
16905
+ "ol",
16906
+ "p",
16907
+ "pre",
16908
+ "strong",
16909
+ "table",
16910
+ "tbody",
16911
+ "td",
16912
+ "th",
16913
+ "thead",
16914
+ "tr",
16915
+ "ul"
16916
+ ];
16917
+ var ALLOWED_ATTR = ["href", "rel", "target", "title", "start"];
16918
+ var hooksInstalled = false;
16919
+ function installHooks() {
16920
+ if (hooksInstalled) return;
16921
+ hooksInstalled = true;
16922
+ DOMPurify__default.default.addHook("afterSanitizeAttributes", (node) => {
16923
+ if (!(node instanceof HTMLAnchorElement)) return;
16924
+ if (!node.getAttribute("href")) return;
16925
+ node.setAttribute("rel", "noreferrer noopener");
16926
+ node.setAttribute("target", "_blank");
16927
+ });
16928
+ }
16929
+ var CACHE_LIMIT = 300;
16930
+ var cache = /* @__PURE__ */ new Map();
16931
+ function renderMarkdown(text) {
16932
+ const cached = cache.get(text);
16933
+ if (cached !== void 0) return cached;
16934
+ installHooks();
16935
+ const html = DOMPurify__default.default.sanitize(marked.marked.parse(text), {
16936
+ ALLOWED_TAGS,
16937
+ ALLOWED_ATTR
16938
+ });
16939
+ if (cache.size >= CACHE_LIMIT) {
16940
+ const oldest = cache.keys().next().value;
16941
+ if (oldest !== void 0) cache.delete(oldest);
16942
+ }
16943
+ cache.set(text, html);
16944
+ return html;
16945
+ }
16946
+ function SettledMarkdown({ text, className }) {
16947
+ const html = React14.useMemo(() => renderMarkdown(text), [text]);
16948
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, dangerouslySetInnerHTML: { __html: html } });
16949
+ }
16950
+ var ChatMarkdown = React14.memo(function ChatMarkdown2({
16951
+ text,
16952
+ className,
16953
+ streaming = false
16954
+ }) {
16955
+ if (streaming && supportsRegExpLookbehind) {
16956
+ return (
16957
+ // While the streamdown chunk loads, the settled renderer keeps the
16958
+ // text on screen — no blank frame at stream start.
16959
+ /* @__PURE__ */ jsxRuntime.jsx(React14.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(SettledMarkdown, { text, className }), children: /* @__PURE__ */ jsxRuntime.jsx(Streamdown, { className, children: text }) })
16960
+ );
16961
+ }
16962
+ return /* @__PURE__ */ jsxRuntime.jsx(SettledMarkdown, { text, className });
16963
+ });
16964
+
16965
+ // src/react/chat-model.ts
16966
+ function partitionMessages(messages) {
16967
+ const bubbles = [];
16968
+ const reactionsByTarget = /* @__PURE__ */ new Map();
16969
+ for (const message of messages) {
16970
+ if (message.content_type === "reaction") {
16971
+ const targetId = message.reply_to?.id;
16972
+ if (!targetId) continue;
16973
+ const list = reactionsByTarget.get(targetId);
16974
+ if (list) list.push(message);
16975
+ else reactionsByTarget.set(targetId, [message]);
16976
+ continue;
16977
+ }
16978
+ bubbles.push(message);
16979
+ }
16980
+ return { bubbles, reactionsByTarget };
16981
+ }
16754
16982
  function ChatWidget({
16755
16983
  client: clientProp,
16756
16984
  businessName = "Support",
@@ -16768,7 +16996,35 @@ function ChatWidget({
16768
16996
  const client = clientProp ?? context?.client;
16769
16997
  const [open, setOpen] = React14.useState(defaultOpen);
16770
16998
  const [unread, setUnread] = React14.useState(0);
16771
- const { messages, isLoading, isSending, error, isActive, send, startConversation } = useChat({ client, pollInterval });
16999
+ const {
17000
+ messages,
17001
+ isLoading,
17002
+ isSending,
17003
+ awaitingReply,
17004
+ seenAt,
17005
+ error,
17006
+ isActive,
17007
+ send,
17008
+ react,
17009
+ startConversation
17010
+ } = useChat({ client, pollInterval });
17011
+ const showTyping = isSending || awaitingReply;
17012
+ const attachPhoto = React14.useCallback(
17013
+ async (file) => {
17014
+ if (!client || !file.type.startsWith("image/") || file.size > 5 * 1024 * 1024) return;
17015
+ const uploaded = await client.uploads.upload(file);
17016
+ if (!uploaded.ok) return;
17017
+ const attachment = {
17018
+ upload_id: uploaded.value.id,
17019
+ url: uploaded.value.url,
17020
+ mime_type: uploaded.value.content_type,
17021
+ filename: uploaded.value.filename,
17022
+ size: uploaded.value.size_bytes
17023
+ };
17024
+ await send("", { attachments: [attachment] });
17025
+ },
17026
+ [client, send]
17027
+ );
16772
17028
  const prevCountRef = React14.useRef(messages.length);
16773
17029
  React14.useEffect(() => {
16774
17030
  if (!open && messages.length > prevCountRef.current) {
@@ -16815,11 +17071,15 @@ function ChatWidget({
16815
17071
  messages,
16816
17072
  isLoading,
16817
17073
  isSending,
17074
+ isTyping: showTyping,
17075
+ seenAt,
16818
17076
  error,
16819
17077
  isActive,
16820
17078
  isLeft,
16821
17079
  onClose: handleClose,
16822
17080
  onSend: send,
17081
+ onReact: react,
17082
+ onAttach: attachPhoto,
16823
17083
  onStartConversation: startConversation,
16824
17084
  classNames
16825
17085
  }
@@ -16872,11 +17132,15 @@ function Panel({
16872
17132
  messages,
16873
17133
  isLoading,
16874
17134
  isSending,
17135
+ isTyping,
17136
+ seenAt,
16875
17137
  error,
16876
17138
  isActive,
16877
17139
  isLeft,
16878
17140
  onClose,
16879
17141
  onSend,
17142
+ onReact,
17143
+ onAttach,
16880
17144
  onStartConversation,
16881
17145
  classNames
16882
17146
  }) {
@@ -16914,7 +17178,9 @@ function Panel({
16914
17178
  {
16915
17179
  messages,
16916
17180
  isLoading,
16917
- isSending,
17181
+ isSending: isTyping,
17182
+ seenAt,
17183
+ onReact,
16918
17184
  className: classNames?.messages
16919
17185
  }
16920
17186
  ),
@@ -16925,6 +17191,7 @@ function Panel({
16925
17191
  placeholder,
16926
17192
  isSending,
16927
17193
  onSend,
17194
+ onAttach,
16928
17195
  className: classNames?.input
16929
17196
  }
16930
17197
  ),
@@ -17020,16 +17287,29 @@ function Welcome({
17020
17287
  }
17021
17288
  );
17022
17289
  }
17290
+ var QUICK_REACTIONS = ["\u{1F44D}", "\u2764\uFE0F"];
17291
+ function lastSeenCustomerMessageId(bubbles, seenAt) {
17292
+ if (!seenAt || !bubbles.some((m) => m.sender_type === "agent")) return null;
17293
+ for (let i = bubbles.length - 1; i >= 0; i--) {
17294
+ if (bubbles[i].sender_type !== "customer") continue;
17295
+ return bubbles[i].created_at <= seenAt ? bubbles[i].id : null;
17296
+ }
17297
+ return null;
17298
+ }
17023
17299
  function MessageList({
17024
17300
  messages,
17025
17301
  isLoading,
17026
17302
  isSending,
17303
+ seenAt,
17304
+ onReact,
17027
17305
  className
17028
17306
  }) {
17029
17307
  const bottomRef = React14.useRef(null);
17030
17308
  React14.useEffect(() => {
17031
17309
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
17032
17310
  }, [messages.length, isSending]);
17311
+ const { bubbles, reactionsByTarget } = partitionMessages(messages);
17312
+ const seenMessageId = lastSeenCustomerMessageId(bubbles, seenAt);
17033
17313
  return /* @__PURE__ */ jsxRuntime.jsxs(
17034
17314
  "div",
17035
17315
  {
@@ -17039,40 +17319,111 @@ function MessageList({
17039
17319
  ),
17040
17320
  children: [
17041
17321
  isLoading && messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
17042
- messages.map((msg, i) => {
17322
+ bubbles.map((msg, i) => {
17043
17323
  const isCustomer = msg.sender_type === "customer";
17044
- const prev = messages[i - 1];
17324
+ const prev = bubbles[i - 1];
17045
17325
  const sameSenderAsPrev = prev?.sender_type === msg.sender_type;
17046
17326
  const isOptimistic = msg.id.startsWith("opt_");
17327
+ const reactions = reactionsByTarget.get(msg.id);
17047
17328
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
17048
17329
  !sameSenderAsPrev && i > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3" }),
17049
- /* @__PURE__ */ jsxRuntime.jsx(
17330
+ /* @__PURE__ */ jsxRuntime.jsxs(
17050
17331
  "div",
17051
17332
  {
17052
17333
  className: cn(
17053
- "flex max-w-[85%]",
17334
+ "group relative flex max-w-[85%]",
17054
17335
  isCustomer ? "ml-auto" : "mr-auto"
17055
17336
  ),
17056
- children: /* @__PURE__ */ jsxRuntime.jsxs(
17057
- "div",
17058
- {
17059
- className: cn(
17060
- "rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
17061
- isCustomer ? "bg-foreground text-background" : "border border-border bg-background text-foreground",
17062
- isCustomer ? sameSenderAsPrev ? "rounded-tr" : "rounded-br" : sameSenderAsPrev ? "rounded-tl" : "rounded-bl",
17063
- isOptimistic && "opacity-70"
17064
- ),
17065
- children: [
17066
- !isCustomer && !sameSenderAsPrev && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 inline-flex items-center gap-1 rounded bg-violet-100 px-1.5 py-0.5 text-[10px] font-semibold text-violet-600", children: [
17067
- /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-[11px] w-[11px]" }),
17068
- "AI"
17069
- ] }),
17070
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap", children: msg.content })
17071
- ]
17072
- }
17073
- )
17337
+ children: [
17338
+ !isCustomer && !isOptimistic && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-3 right-0 z-10 hidden gap-0.5 rounded-full border border-border bg-background px-1 py-0.5 shadow-sm group-hover:flex", children: QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
17339
+ "button",
17340
+ {
17341
+ type: "button",
17342
+ "aria-label": `React ${emoji}`,
17343
+ onClick: () => void onReact(msg, emoji),
17344
+ className: "flex h-6 w-6 items-center justify-center rounded-full text-[13px] hover:bg-muted",
17345
+ children: emoji
17346
+ },
17347
+ emoji
17348
+ )) }),
17349
+ /* @__PURE__ */ jsxRuntime.jsxs(
17350
+ "div",
17351
+ {
17352
+ className: cn(
17353
+ "rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
17354
+ isCustomer ? "bg-foreground text-background" : "border border-border bg-background text-foreground",
17355
+ isCustomer ? sameSenderAsPrev ? "rounded-tr" : "rounded-br" : sameSenderAsPrev ? "rounded-tl" : "rounded-bl",
17356
+ isOptimistic && "opacity-70"
17357
+ ),
17358
+ children: [
17359
+ !isCustomer && !sameSenderAsPrev && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 inline-flex items-center gap-1 rounded bg-violet-100 px-1.5 py-0.5 text-[10px] font-semibold text-violet-600", children: [
17360
+ /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-[11px] w-[11px]" }),
17361
+ "AI"
17362
+ ] }),
17363
+ msg.reply_to && /* @__PURE__ */ jsxRuntime.jsxs(
17364
+ "div",
17365
+ {
17366
+ className: cn(
17367
+ "mb-1.5 flex gap-1.5 rounded-lg px-2 py-1 text-xs",
17368
+ isCustomer ? "bg-background/15" : "bg-muted"
17369
+ ),
17370
+ children: [
17371
+ /* @__PURE__ */ jsxRuntime.jsx(
17372
+ "span",
17373
+ {
17374
+ className: cn(
17375
+ "w-[3px] shrink-0 self-stretch rounded-full",
17376
+ isCustomer ? "bg-background/40" : "bg-muted-foreground/40"
17377
+ )
17378
+ }
17379
+ ),
17380
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate opacity-80", children: msg.reply_to.preview })
17381
+ ]
17382
+ }
17383
+ ),
17384
+ msg.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-1.5", msg.content && "mb-1.5"), children: msg.attachments.map(
17385
+ (attachment, index) => attachment.mime_type?.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: attachment.url, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(
17386
+ "img",
17387
+ {
17388
+ src: attachment.url,
17389
+ alt: attachment.filename ?? "Photo",
17390
+ loading: "lazy",
17391
+ className: "max-h-48 max-w-full rounded-lg object-cover"
17392
+ }
17393
+ ) }, index) : /* @__PURE__ */ jsxRuntime.jsx(
17394
+ "a",
17395
+ {
17396
+ href: attachment.url,
17397
+ target: "_blank",
17398
+ rel: "noreferrer",
17399
+ className: "truncate text-xs underline",
17400
+ children: attachment.filename ?? "Attachment"
17401
+ },
17402
+ index
17403
+ )
17404
+ ) }),
17405
+ isCustomer ? msg.content && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap", children: msg.content }) : /* @__PURE__ */ jsxRuntime.jsx(
17406
+ ChatMarkdown,
17407
+ {
17408
+ text: msg.content,
17409
+ className: "[&_p]:my-0 [&_p+p]:mt-1.5 [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:my-0.5 [&_h1]:text-sm [&_h1]:font-bold [&_h2]:text-sm [&_h2]:font-bold [&_h3]:text-sm [&_h3]:font-semibold [&_hr]:my-2 [&_table]:my-1 [&_table]:w-full [&_th]:pb-1 [&_th]:text-left [&_th]:text-[10px] [&_th]:font-semibold [&_th]:uppercase [&_td]:py-1 [&_td:last-child]:text-right [&_td:last-child]:font-semibold [&_td:last-child]:tabular-nums [&_a]:underline"
17410
+ }
17411
+ )
17412
+ ]
17413
+ }
17414
+ )
17415
+ ]
17074
17416
  }
17075
- )
17417
+ ),
17418
+ reactions && reactions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mt-0.5 flex gap-1", isCustomer ? "justify-end" : "justify-start"), children: reactions.map((reaction) => /* @__PURE__ */ jsxRuntime.jsx(
17419
+ "span",
17420
+ {
17421
+ className: "rounded-full border border-border bg-background px-1.5 py-0.5 text-xs shadow-sm",
17422
+ children: reaction.content
17423
+ },
17424
+ reaction.id
17425
+ )) }),
17426
+ msg.id === seenMessageId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 text-right text-[10px] font-medium text-muted-foreground", children: "Seen" })
17076
17427
  ] }, msg.id);
17077
17428
  }),
17078
17429
  isSending && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mr-auto mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
@@ -17085,10 +17436,24 @@ function ChatInput({
17085
17436
  placeholder,
17086
17437
  isSending,
17087
17438
  onSend,
17439
+ onAttach,
17088
17440
  className
17089
17441
  }) {
17090
17442
  const [value, setValue] = React14.useState("");
17443
+ const [uploading, setUploading] = React14.useState(false);
17091
17444
  const textareaRef = React14.useRef(null);
17445
+ const fileRef = React14.useRef(null);
17446
+ const handleAttach = React14.useCallback(
17447
+ async (file) => {
17448
+ setUploading(true);
17449
+ try {
17450
+ await onAttach(file);
17451
+ } finally {
17452
+ setUploading(false);
17453
+ }
17454
+ },
17455
+ [onAttach]
17456
+ );
17092
17457
  const handleSend = React14.useCallback(() => {
17093
17458
  const trimmed = value.trim();
17094
17459
  if (!trimmed || isSending) return;
@@ -17122,6 +17487,37 @@ function ChatInput({
17122
17487
  className
17123
17488
  ),
17124
17489
  children: [
17490
+ /* @__PURE__ */ jsxRuntime.jsx(
17491
+ "input",
17492
+ {
17493
+ ref: fileRef,
17494
+ type: "file",
17495
+ accept: "image/*",
17496
+ className: "hidden",
17497
+ "aria-hidden": "true",
17498
+ tabIndex: -1,
17499
+ onChange: (e) => {
17500
+ const file = e.target.files?.[0];
17501
+ e.target.value = "";
17502
+ if (file) void handleAttach(file);
17503
+ }
17504
+ }
17505
+ ),
17506
+ /* @__PURE__ */ jsxRuntime.jsx(
17507
+ "button",
17508
+ {
17509
+ type: "button",
17510
+ "aria-label": "Attach a photo",
17511
+ disabled: uploading,
17512
+ onClick: () => fileRef.current?.click(),
17513
+ className: cn(
17514
+ "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[10px]",
17515
+ "bg-muted text-muted-foreground transition-colors hover:text-foreground",
17516
+ uploading && "animate-pulse"
17517
+ ),
17518
+ children: /* @__PURE__ */ jsxRuntime.jsx(ImageIcon, { className: "h-[18px] w-[18px]" })
17519
+ }
17520
+ ),
17125
17521
  /* @__PURE__ */ jsxRuntime.jsx(
17126
17522
  "div",
17127
17523
  {
@@ -17224,6 +17620,25 @@ function SendIcon({ className }) {
17224
17620
  }
17225
17621
  );
17226
17622
  }
17623
+ function ImageIcon({ className }) {
17624
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17625
+ "svg",
17626
+ {
17627
+ className,
17628
+ viewBox: "0 0 24 24",
17629
+ fill: "none",
17630
+ stroke: "currentColor",
17631
+ strokeWidth: 2,
17632
+ strokeLinecap: "round",
17633
+ strokeLinejoin: "round",
17634
+ children: [
17635
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
17636
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
17637
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "21 15 16 10 5 21" })
17638
+ ]
17639
+ }
17640
+ );
17641
+ }
17227
17642
  function SparkleIcon({ className }) {
17228
17643
  return /* @__PURE__ */ jsxRuntime.jsx(
17229
17644
  "svg",
@@ -17238,9 +17653,1838 @@ function SparkleIcon({ className }) {
17238
17653
  );
17239
17654
  }
17240
17655
 
17241
- Object.defineProperty(exports, "getVariantDisplayName", {
17242
- enumerable: true,
17243
- get: function () { return chunkT7Z25EY4_js.getVariantDisplayName; }
17656
+ // src/react/genui/catalog.ts
17657
+ function genUICatalog(registry) {
17658
+ return new Map(
17659
+ registry.components.map((component) => [
17660
+ component.name,
17661
+ {
17662
+ params: component.params.map((param) => ({
17663
+ name: param.name,
17664
+ required: param.required ?? false
17665
+ }))
17666
+ }
17667
+ ])
17668
+ );
17669
+ }
17670
+
17671
+ // src/genui/lang/parser/ast.ts
17672
+ function isRuntimeExpr(node) {
17673
+ switch (node.k) {
17674
+ case "StateRef":
17675
+ case "RuntimeRef":
17676
+ case "BinOp":
17677
+ case "UnaryOp":
17678
+ case "Ternary":
17679
+ case "Member":
17680
+ case "Index":
17681
+ case "Assign":
17682
+ return true;
17683
+ default:
17684
+ return false;
17685
+ }
17686
+ }
17687
+ var AST_KINDS = /* @__PURE__ */ new Set([
17688
+ "Comp",
17689
+ "Ref",
17690
+ "StateRef",
17691
+ "RuntimeRef",
17692
+ "BinOp",
17693
+ "UnaryOp",
17694
+ "Ternary",
17695
+ "Member",
17696
+ "Index",
17697
+ "Assign",
17698
+ "Str",
17699
+ "Num",
17700
+ "Bool",
17701
+ "Null",
17702
+ "Arr",
17703
+ "Obj",
17704
+ "Ph"
17705
+ ]);
17706
+ function isASTNode(value) {
17707
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
17708
+ return AST_KINDS.has(value.k);
17709
+ }
17710
+ function walkAST(node, visit) {
17711
+ const walk = (current) => {
17712
+ visit(current);
17713
+ switch (current.k) {
17714
+ case "Comp":
17715
+ current.args.forEach(walk);
17716
+ Object.values(current.mappedProps ?? {}).forEach(walk);
17717
+ break;
17718
+ case "Arr":
17719
+ current.els.forEach(walk);
17720
+ break;
17721
+ case "Obj":
17722
+ current.entries.forEach(([, value]) => walk(value));
17723
+ break;
17724
+ case "BinOp":
17725
+ walk(current.left);
17726
+ walk(current.right);
17727
+ break;
17728
+ case "UnaryOp":
17729
+ walk(current.operand);
17730
+ break;
17731
+ case "Ternary":
17732
+ walk(current.cond);
17733
+ walk(current.then);
17734
+ walk(current.else);
17735
+ break;
17736
+ case "Member":
17737
+ walk(current.obj);
17738
+ break;
17739
+ case "Index":
17740
+ walk(current.obj);
17741
+ walk(current.index);
17742
+ break;
17743
+ case "Assign":
17744
+ walk(current.value);
17745
+ break;
17746
+ }
17747
+ };
17748
+ walk(node);
17749
+ }
17750
+
17751
+ // src/genui/lang/parser/builtins.ts
17752
+ function resolveField(obj, path) {
17753
+ if (!path || obj == null) return void 0;
17754
+ if (!path.includes(".")) return obj[path];
17755
+ let cur = obj;
17756
+ for (const p of path.split(".")) {
17757
+ if (cur == null) return void 0;
17758
+ cur = cur[p];
17759
+ }
17760
+ return cur;
17761
+ }
17762
+ function toNumber2(val) {
17763
+ if (typeof val === "number") return val;
17764
+ if (typeof val === "string") {
17765
+ const n = Number(val);
17766
+ return isNaN(n) ? 0 : n;
17767
+ }
17768
+ if (typeof val === "boolean") return val ? 1 : 0;
17769
+ return 0;
17770
+ }
17771
+ var BUILTINS = {
17772
+ Count: {
17773
+ name: "Count",
17774
+ signature: "Count(array) \u2192 number",
17775
+ description: "Returns array length",
17776
+ fn: (arr) => Array.isArray(arr) ? arr.length : 0
17777
+ },
17778
+ First: {
17779
+ name: "First",
17780
+ signature: "First(array) \u2192 element",
17781
+ description: "Returns first element of array",
17782
+ fn: (arr) => Array.isArray(arr) ? arr[0] ?? null : null
17783
+ },
17784
+ Last: {
17785
+ name: "Last",
17786
+ signature: "Last(array) \u2192 element",
17787
+ description: "Returns last element of array",
17788
+ fn: (arr) => Array.isArray(arr) ? arr[arr.length - 1] ?? null : null
17789
+ },
17790
+ Sum: {
17791
+ name: "Sum",
17792
+ signature: "Sum(numbers[]) \u2192 number",
17793
+ description: "Sum of numeric array",
17794
+ fn: (arr) => Array.isArray(arr) ? arr.reduce((a, b) => a + toNumber2(b), 0) : 0
17795
+ },
17796
+ Avg: {
17797
+ name: "Avg",
17798
+ signature: "Avg(numbers[]) \u2192 number",
17799
+ description: "Average of numeric array",
17800
+ fn: (arr) => Array.isArray(arr) && arr.length ? arr.reduce((a, b) => a + toNumber2(b), 0) / arr.length : 0
17801
+ },
17802
+ Min: {
17803
+ name: "Min",
17804
+ signature: "Min(numbers[]) \u2192 number",
17805
+ description: "Minimum value in array",
17806
+ fn: (arr) => Array.isArray(arr) && arr.length ? arr.reduce((acc, b) => Math.min(acc, toNumber2(b)), toNumber2(arr[0])) : 0
17807
+ },
17808
+ Max: {
17809
+ name: "Max",
17810
+ signature: "Max(numbers[]) \u2192 number",
17811
+ description: "Maximum value in array",
17812
+ fn: (arr) => Array.isArray(arr) && arr.length ? arr.reduce((acc, b) => Math.max(acc, toNumber2(b)), toNumber2(arr[0])) : 0
17813
+ },
17814
+ Sort: {
17815
+ name: "Sort",
17816
+ signature: "Sort(array, field, direction?) \u2192 sorted array",
17817
+ description: 'Sort array by field. Direction: "asc" (default) or "desc"',
17818
+ fn: (arr, field, dir) => {
17819
+ if (!Array.isArray(arr)) return arr;
17820
+ const f = String(field ?? "");
17821
+ const desc = String(dir ?? "asc") === "desc";
17822
+ return [...arr].sort((a, b) => {
17823
+ const av = f ? resolveField(a, f) : a;
17824
+ const bv = f ? resolveField(b, f) : b;
17825
+ const aIsNumeric = typeof av === "number" || typeof av === "string" && !isNaN(Number(av)) && av !== "";
17826
+ const bIsNumeric = typeof bv === "number" || typeof bv === "string" && !isNaN(Number(bv)) && bv !== "";
17827
+ if (aIsNumeric && bIsNumeric) {
17828
+ const diff = toNumber2(av) - toNumber2(bv);
17829
+ return desc ? -diff : diff;
17830
+ }
17831
+ const cmp = String(av ?? "").localeCompare(String(bv ?? ""));
17832
+ return desc ? -cmp : cmp;
17833
+ });
17834
+ }
17835
+ },
17836
+ Filter: {
17837
+ name: "Filter",
17838
+ signature: 'Filter(array, field, operator: "==" | "!=" | ">" | "<" | ">=" | "<=" | "contains", value) \u2192 filtered array',
17839
+ description: "Filter array by field value",
17840
+ fn: (arr, field, op, value) => {
17841
+ if (!Array.isArray(arr)) return [];
17842
+ const f = String(field ?? "");
17843
+ const o = String(op ?? "==");
17844
+ return arr.filter((item) => {
17845
+ const v = f ? resolveField(item, f) : item;
17846
+ switch (o) {
17847
+ case "==":
17848
+ return v == value;
17849
+ case "!=":
17850
+ return v != value;
17851
+ case ">":
17852
+ return toNumber2(v) > toNumber2(value);
17853
+ case "<":
17854
+ return toNumber2(v) < toNumber2(value);
17855
+ case ">=":
17856
+ return toNumber2(v) >= toNumber2(value);
17857
+ case "<=":
17858
+ return toNumber2(v) <= toNumber2(value);
17859
+ case "contains":
17860
+ return String(v ?? "").includes(String(value ?? ""));
17861
+ default:
17862
+ return false;
17863
+ }
17864
+ });
17865
+ }
17866
+ },
17867
+ Round: {
17868
+ name: "Round",
17869
+ signature: "Round(number, decimals?) \u2192 number",
17870
+ description: "Round to N decimal places (default 0)",
17871
+ fn: (n, decimals) => {
17872
+ const num = toNumber2(n);
17873
+ const d = decimals != null ? toNumber2(decimals) : 0;
17874
+ const factor = Math.pow(10, d);
17875
+ return Math.round(num * factor) / factor;
17876
+ }
17877
+ },
17878
+ Abs: {
17879
+ name: "Abs",
17880
+ signature: "Abs(number) \u2192 number",
17881
+ description: "Absolute value",
17882
+ fn: (n) => Math.abs(toNumber2(n))
17883
+ },
17884
+ Floor: {
17885
+ name: "Floor",
17886
+ signature: "Floor(number) \u2192 number",
17887
+ description: "Round down to nearest integer",
17888
+ fn: (n) => Math.floor(toNumber2(n))
17889
+ },
17890
+ Ceil: {
17891
+ name: "Ceil",
17892
+ signature: "Ceil(number) \u2192 number",
17893
+ description: "Round up to nearest integer",
17894
+ fn: (n) => Math.ceil(toNumber2(n))
17895
+ }
17896
+ };
17897
+ var LAZY_BUILTINS = /* @__PURE__ */ new Set(["Each"]);
17898
+ var ACTION_STEPS = {
17899
+ Run: "run",
17900
+ ToAssistant: "continue_conversation",
17901
+ OpenUrl: "open_url",
17902
+ Set: "set",
17903
+ Reset: "reset"
17904
+ };
17905
+ var ACTION_NAMES = /* @__PURE__ */ new Set(["Action", ...Object.keys(ACTION_STEPS)]);
17906
+ var BUILTIN_NAMES = /* @__PURE__ */ new Set([
17907
+ ...Object.keys(BUILTINS),
17908
+ ...LAZY_BUILTINS,
17909
+ ...ACTION_NAMES
17910
+ ]);
17911
+ function isBuiltin(name) {
17912
+ return BUILTIN_NAMES.has(name);
17913
+ }
17914
+ var RESERVED_CALLS = { Query: "Query", Mutation: "Mutation" };
17915
+ function isReservedCall(name) {
17916
+ return name in RESERVED_CALLS;
17917
+ }
17918
+
17919
+ // src/genui/lang/parser/expressions.ts
17920
+ var PREC_TERNARY = 1;
17921
+ var PREC_OR = 2;
17922
+ var PREC_AND = 3;
17923
+ var PREC_EQ = 4;
17924
+ var PREC_CMP = 5;
17925
+ var PREC_ADD = 6;
17926
+ var PREC_MUL = 7;
17927
+ var PREC_UNARY = 8;
17928
+ var PREC_MEMBER = 9;
17929
+ function parseExpression(tokens) {
17930
+ let pos = 0;
17931
+ const cur = () => tokens[pos] ?? { t: 13 /* EOF */ };
17932
+ const adv = () => {
17933
+ const tok = cur();
17934
+ pos++;
17935
+ return tok;
17936
+ };
17937
+ const eat = (kind) => {
17938
+ if (cur().t === kind) pos++;
17939
+ };
17940
+ function getInfixPrec(tok) {
17941
+ switch (tok.t) {
17942
+ case 34 /* Question */:
17943
+ return PREC_TERNARY;
17944
+ case 32 /* Or */:
17945
+ return PREC_OR;
17946
+ case 31 /* And */:
17947
+ return PREC_AND;
17948
+ case 25 /* EqEq */:
17949
+ case 26 /* NotEq */:
17950
+ return PREC_EQ;
17951
+ case 27 /* Greater */:
17952
+ case 28 /* Less */:
17953
+ case 29 /* GreaterEq */:
17954
+ case 30 /* LessEq */:
17955
+ return PREC_CMP;
17956
+ case 20 /* Plus */:
17957
+ case 21 /* Minus */:
17958
+ return PREC_ADD;
17959
+ case 22 /* Star */:
17960
+ case 23 /* Slash */:
17961
+ case 24 /* Percent */:
17962
+ return PREC_MUL;
17963
+ case 19 /* Dot */:
17964
+ case 3 /* LBrack */:
17965
+ return PREC_MEMBER;
17966
+ default:
17967
+ return 0;
17968
+ }
17969
+ }
17970
+ function parseExpr(minPrec = 0) {
17971
+ let left = parsePrefix();
17972
+ while (getInfixPrec(cur()) > minPrec) {
17973
+ left = parseInfix(left);
17974
+ }
17975
+ return left;
17976
+ }
17977
+ function parsePrefix() {
17978
+ const tok = cur();
17979
+ if (tok.t === 14 /* Str */) {
17980
+ adv();
17981
+ return { k: "Str", v: tok.v };
17982
+ }
17983
+ if (tok.t === 15 /* Num */) {
17984
+ adv();
17985
+ return { k: "Num", v: tok.v };
17986
+ }
17987
+ if (tok.t === 10 /* True */) {
17988
+ adv();
17989
+ return { k: "Bool", v: true };
17990
+ }
17991
+ if (tok.t === 11 /* False */) {
17992
+ adv();
17993
+ return { k: "Bool", v: false };
17994
+ }
17995
+ if (tok.t === 12 /* Null */) {
17996
+ adv();
17997
+ return { k: "Null" };
17998
+ }
17999
+ if (tok.t === 3 /* LBrack */) return parseArr();
18000
+ if (tok.t === 5 /* LBrace */) return parseObj();
18001
+ if (tok.t === 18 /* StateVar */) {
18002
+ const name = tok.v;
18003
+ adv();
18004
+ if (cur().t === 9 /* Equals */) {
18005
+ adv();
18006
+ const value = parseExpr(0);
18007
+ return { k: "Assign", target: name, value };
18008
+ }
18009
+ return { k: "StateRef", n: name };
18010
+ }
18011
+ if (tok.t === 17 /* Type */) {
18012
+ const name = tok.v;
18013
+ if (tokens[pos + 1]?.t === 1 /* LParen */ && (!isBuiltin(name) || name === "Action"))
18014
+ return parseComp();
18015
+ adv();
18016
+ return { k: "Ref", n: name };
18017
+ }
18018
+ if (tok.t === 35 /* BuiltinCall */) {
18019
+ if (tokens[pos + 1]?.t === 1 /* LParen */) return parseComp();
18020
+ adv();
18021
+ return { k: "Ref", n: tok.v };
18022
+ }
18023
+ if (tok.t === 16 /* Ident */) {
18024
+ adv();
18025
+ return { k: "Ref", n: tok.v };
18026
+ }
18027
+ if (tok.t === 33 /* Not */) {
18028
+ adv();
18029
+ return { k: "UnaryOp", op: "!", operand: parseExpr(PREC_UNARY) };
18030
+ }
18031
+ if (tok.t === 21 /* Minus */) {
18032
+ adv();
18033
+ return { k: "UnaryOp", op: "-", operand: parseExpr(PREC_UNARY) };
18034
+ }
18035
+ if (tok.t === 1 /* LParen */) {
18036
+ adv();
18037
+ const inner = parseExpr(0);
18038
+ eat(2 /* RParen */);
18039
+ return inner;
18040
+ }
18041
+ adv();
18042
+ return { k: "Null" };
18043
+ }
18044
+ function parseInfix(left) {
18045
+ const tok = cur();
18046
+ if (tok.t === 20 /* Plus */) {
18047
+ adv();
18048
+ return { k: "BinOp", op: "+", left, right: parseExpr(PREC_ADD) };
18049
+ }
18050
+ if (tok.t === 21 /* Minus */) {
18051
+ adv();
18052
+ return { k: "BinOp", op: "-", left, right: parseExpr(PREC_ADD) };
18053
+ }
18054
+ if (tok.t === 22 /* Star */) {
18055
+ adv();
18056
+ return { k: "BinOp", op: "*", left, right: parseExpr(PREC_MUL) };
18057
+ }
18058
+ if (tok.t === 23 /* Slash */) {
18059
+ adv();
18060
+ return { k: "BinOp", op: "/", left, right: parseExpr(PREC_MUL) };
18061
+ }
18062
+ if (tok.t === 24 /* Percent */) {
18063
+ adv();
18064
+ return { k: "BinOp", op: "%", left, right: parseExpr(PREC_MUL) };
18065
+ }
18066
+ if (tok.t === 25 /* EqEq */) {
18067
+ adv();
18068
+ return { k: "BinOp", op: "==", left, right: parseExpr(PREC_EQ) };
18069
+ }
18070
+ if (tok.t === 26 /* NotEq */) {
18071
+ adv();
18072
+ return { k: "BinOp", op: "!=", left, right: parseExpr(PREC_EQ) };
18073
+ }
18074
+ if (tok.t === 27 /* Greater */) {
18075
+ adv();
18076
+ return { k: "BinOp", op: ">", left, right: parseExpr(PREC_CMP) };
18077
+ }
18078
+ if (tok.t === 28 /* Less */) {
18079
+ adv();
18080
+ return { k: "BinOp", op: "<", left, right: parseExpr(PREC_CMP) };
18081
+ }
18082
+ if (tok.t === 29 /* GreaterEq */) {
18083
+ adv();
18084
+ return { k: "BinOp", op: ">=", left, right: parseExpr(PREC_CMP) };
18085
+ }
18086
+ if (tok.t === 30 /* LessEq */) {
18087
+ adv();
18088
+ return { k: "BinOp", op: "<=", left, right: parseExpr(PREC_CMP) };
18089
+ }
18090
+ if (tok.t === 31 /* And */) {
18091
+ adv();
18092
+ return { k: "BinOp", op: "&&", left, right: parseExpr(PREC_AND) };
18093
+ }
18094
+ if (tok.t === 32 /* Or */) {
18095
+ adv();
18096
+ return { k: "BinOp", op: "||", left, right: parseExpr(PREC_OR) };
18097
+ }
18098
+ if (tok.t === 34 /* Question */) {
18099
+ adv();
18100
+ const then = parseExpr(0);
18101
+ eat(8 /* Colon */);
18102
+ const els = parseExpr(0);
18103
+ return { k: "Ternary", cond: left, then, else: els };
18104
+ }
18105
+ if (tok.t === 19 /* Dot */) {
18106
+ adv();
18107
+ const fieldTok = cur();
18108
+ const field = fieldTok.t === 16 /* Ident */ || fieldTok.t === 17 /* Type */ || fieldTok.t === 14 /* Str */ || fieldTok.t === 15 /* Num */ ? (adv(), String(fieldTok.v)) : fieldTok.t === 18 /* StateVar */ ? (adv(), fieldTok.v.replace(/^\$/, "")) : (adv(), "?");
18109
+ return { k: "Member", obj: left, field };
18110
+ }
18111
+ if (tok.t === 3 /* LBrack */) {
18112
+ adv();
18113
+ const index = parseExpr(0);
18114
+ eat(4 /* RBrack */);
18115
+ return { k: "Index", obj: left, index };
18116
+ }
18117
+ return left;
18118
+ }
18119
+ function parseComp() {
18120
+ const name = cur().v;
18121
+ adv();
18122
+ eat(1 /* LParen */);
18123
+ const args = [];
18124
+ while (cur().t !== 2 /* RParen */ && cur().t !== 13 /* EOF */) {
18125
+ args.push(parseExpr(0));
18126
+ if (cur().t === 7 /* Comma */) adv();
18127
+ }
18128
+ eat(2 /* RParen */);
18129
+ return { k: "Comp", name, args };
18130
+ }
18131
+ function parseArr() {
18132
+ adv();
18133
+ const els = [];
18134
+ while (cur().t !== 4 /* RBrack */ && cur().t !== 13 /* EOF */) {
18135
+ els.push(parseExpr(0));
18136
+ if (cur().t === 7 /* Comma */) adv();
18137
+ }
18138
+ eat(4 /* RBrack */);
18139
+ return { k: "Arr", els };
18140
+ }
18141
+ function parseObj() {
18142
+ adv();
18143
+ const entries = [];
18144
+ while (cur().t !== 6 /* RBrace */ && cur().t !== 13 /* EOF */) {
18145
+ const kt = cur();
18146
+ const key = kt.t === 16 /* Ident */ || kt.t === 14 /* Str */ || kt.t === 17 /* Type */ || kt.t === 15 /* Num */ ? (adv(), String(kt.v)) : kt.t === 18 /* StateVar */ ? (adv(), kt.v.replace(/^\$/, "")) : (adv(), "?");
18147
+ eat(8 /* Colon */);
18148
+ entries.push([key, parseExpr(0)]);
18149
+ if (cur().t === 7 /* Comma */) adv();
18150
+ }
18151
+ eat(6 /* RBrace */);
18152
+ return { k: "Obj", entries };
18153
+ }
18154
+ return parseExpr(0);
18155
+ }
18156
+
18157
+ // src/genui/lang/parser/lexer.ts
18158
+ function tokenize(src) {
18159
+ const tokens = [];
18160
+ let i = 0;
18161
+ const n = src.length;
18162
+ while (i < n) {
18163
+ while (i < n && (src[i] === " " || src[i] === " " || src[i] === "\r")) i++;
18164
+ if (i >= n) break;
18165
+ const c = src[i];
18166
+ if (c === "\n") {
18167
+ tokens.push({ t: 0 /* Newline */ });
18168
+ i++;
18169
+ continue;
18170
+ }
18171
+ if (c === "(") {
18172
+ tokens.push({ t: 1 /* LParen */ });
18173
+ i++;
18174
+ continue;
18175
+ }
18176
+ if (c === ")") {
18177
+ tokens.push({ t: 2 /* RParen */ });
18178
+ i++;
18179
+ continue;
18180
+ }
18181
+ if (c === "[") {
18182
+ tokens.push({ t: 3 /* LBrack */ });
18183
+ i++;
18184
+ continue;
18185
+ }
18186
+ if (c === "]") {
18187
+ tokens.push({ t: 4 /* RBrack */ });
18188
+ i++;
18189
+ continue;
18190
+ }
18191
+ if (c === "{") {
18192
+ tokens.push({ t: 5 /* LBrace */ });
18193
+ i++;
18194
+ continue;
18195
+ }
18196
+ if (c === "}") {
18197
+ tokens.push({ t: 6 /* RBrace */ });
18198
+ i++;
18199
+ continue;
18200
+ }
18201
+ if (c === ",") {
18202
+ tokens.push({ t: 7 /* Comma */ });
18203
+ i++;
18204
+ continue;
18205
+ }
18206
+ if (c === ":") {
18207
+ tokens.push({ t: 8 /* Colon */ });
18208
+ i++;
18209
+ continue;
18210
+ }
18211
+ if (c === "=") {
18212
+ if (i + 1 < n && src[i + 1] === "=") {
18213
+ tokens.push({ t: 25 /* EqEq */ });
18214
+ i += 2;
18215
+ } else {
18216
+ tokens.push({ t: 9 /* Equals */ });
18217
+ i++;
18218
+ }
18219
+ continue;
18220
+ }
18221
+ if (c === "!") {
18222
+ if (i + 1 < n && src[i + 1] === "=") {
18223
+ tokens.push({ t: 26 /* NotEq */ });
18224
+ i += 2;
18225
+ } else {
18226
+ tokens.push({ t: 33 /* Not */ });
18227
+ i++;
18228
+ }
18229
+ continue;
18230
+ }
18231
+ if (c === ">") {
18232
+ if (i + 1 < n && src[i + 1] === "=") {
18233
+ tokens.push({ t: 29 /* GreaterEq */ });
18234
+ i += 2;
18235
+ } else {
18236
+ tokens.push({ t: 27 /* Greater */ });
18237
+ i++;
18238
+ }
18239
+ continue;
18240
+ }
18241
+ if (c === "<") {
18242
+ if (i + 1 < n && src[i + 1] === "=") {
18243
+ tokens.push({ t: 30 /* LessEq */ });
18244
+ i += 2;
18245
+ } else {
18246
+ tokens.push({ t: 28 /* Less */ });
18247
+ i++;
18248
+ }
18249
+ continue;
18250
+ }
18251
+ if (c === "&") {
18252
+ if (i + 1 < n && src[i + 1] === "&") {
18253
+ tokens.push({ t: 31 /* And */ });
18254
+ i += 2;
18255
+ } else {
18256
+ tokens.push({ t: 31 /* And */ });
18257
+ i++;
18258
+ }
18259
+ continue;
18260
+ }
18261
+ if (c === "|") {
18262
+ if (i + 1 < n && src[i + 1] === "|") {
18263
+ tokens.push({ t: 32 /* Or */ });
18264
+ i += 2;
18265
+ } else {
18266
+ tokens.push({ t: 32 /* Or */ });
18267
+ i++;
18268
+ }
18269
+ continue;
18270
+ }
18271
+ if (c === ".") {
18272
+ tokens.push({ t: 19 /* Dot */ });
18273
+ i++;
18274
+ continue;
18275
+ }
18276
+ if (c === "?") {
18277
+ tokens.push({ t: 34 /* Question */ });
18278
+ i++;
18279
+ continue;
18280
+ }
18281
+ if (c === "+") {
18282
+ tokens.push({ t: 20 /* Plus */ });
18283
+ i++;
18284
+ continue;
18285
+ }
18286
+ if (c === "*") {
18287
+ tokens.push({ t: 22 /* Star */ });
18288
+ i++;
18289
+ continue;
18290
+ }
18291
+ if (c === "/") {
18292
+ tokens.push({ t: 23 /* Slash */ });
18293
+ i++;
18294
+ continue;
18295
+ }
18296
+ if (c === "%") {
18297
+ tokens.push({ t: 24 /* Percent */ });
18298
+ i++;
18299
+ continue;
18300
+ }
18301
+ if (c === '"') {
18302
+ const start = i;
18303
+ i++;
18304
+ let isClosed = false;
18305
+ while (i < n) {
18306
+ if (src[i] === "\\") {
18307
+ i += 2;
18308
+ } else if (src[i] === '"') {
18309
+ i++;
18310
+ isClosed = true;
18311
+ break;
18312
+ } else {
18313
+ i++;
18314
+ }
18315
+ }
18316
+ const rawString = src.slice(start, i);
18317
+ try {
18318
+ const validJsonString = isClosed ? rawString : rawString + '"';
18319
+ tokens.push({ t: 14 /* Str */, v: JSON.parse(validJsonString) });
18320
+ } catch {
18321
+ const stripped = rawString.replace(/^"|"$/g, "");
18322
+ tokens.push({ t: 14 /* Str */, v: stripped });
18323
+ }
18324
+ continue;
18325
+ }
18326
+ if (c === "'") {
18327
+ i++;
18328
+ let result = "";
18329
+ while (i < n) {
18330
+ if (src[i] === "\\") {
18331
+ i++;
18332
+ if (i < n) {
18333
+ const esc = src[i];
18334
+ if (esc === "'") result += "'";
18335
+ else if (esc === "\\") result += "\\";
18336
+ else if (esc === "n") result += "\n";
18337
+ else if (esc === "t") result += " ";
18338
+ else result += esc;
18339
+ i++;
18340
+ }
18341
+ } else if (src[i] === "'") {
18342
+ i++;
18343
+ break;
18344
+ } else {
18345
+ result += src[i];
18346
+ i++;
18347
+ }
18348
+ }
18349
+ tokens.push({ t: 14 /* Str */, v: result });
18350
+ continue;
18351
+ }
18352
+ if (c === "-") {
18353
+ const prev = tokens.length > 0 ? tokens[tokens.length - 1] : null;
18354
+ const afterValue = prev != null && (prev.t === 15 /* Num */ || prev.t === 14 /* Str */ || prev.t === 16 /* Ident */ || prev.t === 17 /* Type */ || prev.t === 2 /* RParen */ || prev.t === 4 /* RBrack */ || prev.t === 10 /* True */ || prev.t === 11 /* False */ || prev.t === 12 /* Null */ || prev.t === 18 /* StateVar */ || prev.t === 35 /* BuiltinCall */);
18355
+ if (!afterValue && i + 1 < n && src[i + 1] >= "0" && src[i + 1] <= "9") ; else {
18356
+ tokens.push({ t: 21 /* Minus */ });
18357
+ i++;
18358
+ continue;
18359
+ }
18360
+ }
18361
+ const isDigit = c >= "0" && c <= "9";
18362
+ const isNegDigit = c === "-" && i + 1 < n && src[i + 1] >= "0" && src[i + 1] <= "9";
18363
+ if (isDigit || isNegDigit) {
18364
+ const start = i;
18365
+ if (src[i] === "-") i++;
18366
+ while (i < n && src[i] >= "0" && src[i] <= "9") i++;
18367
+ if (i < n && src[i] === "." && i + 1 < n && src[i + 1] >= "0" && src[i + 1] <= "9") {
18368
+ i++;
18369
+ while (i < n && src[i] >= "0" && src[i] <= "9") i++;
18370
+ }
18371
+ if (i < n && (src[i] === "e" || src[i] === "E")) {
18372
+ i++;
18373
+ if (i < n && (src[i] === "+" || src[i] === "-")) i++;
18374
+ while (i < n && src[i] >= "0" && src[i] <= "9") i++;
18375
+ }
18376
+ tokens.push({ t: 15 /* Num */, v: +src.slice(start, i) });
18377
+ continue;
18378
+ }
18379
+ if (c === "$" && i + 1 < n && (src[i + 1] >= "a" && src[i + 1] <= "z" || src[i + 1] >= "A" && src[i + 1] <= "Z" || src[i + 1] === "_")) {
18380
+ const start = i;
18381
+ i++;
18382
+ while (i < n && (src[i] >= "a" && src[i] <= "z" || src[i] >= "A" && src[i] <= "Z" || src[i] >= "0" && src[i] <= "9" || src[i] === "_"))
18383
+ i++;
18384
+ tokens.push({ t: 18 /* StateVar */, v: src.slice(start, i) });
18385
+ continue;
18386
+ }
18387
+ const isAlpha = c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c === "_";
18388
+ if (isAlpha) {
18389
+ const start = i;
18390
+ while (i < n && (src[i] >= "a" && src[i] <= "z" || src[i] >= "A" && src[i] <= "Z" || src[i] >= "0" && src[i] <= "9" || src[i] === "_"))
18391
+ i++;
18392
+ const word = src.slice(start, i);
18393
+ if (word === "true") {
18394
+ tokens.push({ t: 10 /* True */ });
18395
+ continue;
18396
+ }
18397
+ if (word === "false") {
18398
+ tokens.push({ t: 11 /* False */ });
18399
+ continue;
18400
+ }
18401
+ if (word === "null") {
18402
+ tokens.push({ t: 12 /* Null */ });
18403
+ continue;
18404
+ }
18405
+ const kind = c >= "A" && c <= "Z" ? 17 /* Type */ : 16 /* Ident */;
18406
+ tokens.push({ t: kind, v: word });
18407
+ continue;
18408
+ }
18409
+ if (c === "@" && i + 1 < n && (src[i + 1] >= "a" && src[i + 1] <= "z" || src[i + 1] >= "A" && src[i + 1] <= "Z" || src[i + 1] === "_")) {
18410
+ i++;
18411
+ const start = i;
18412
+ while (i < n && (src[i] >= "a" && src[i] <= "z" || src[i] >= "A" && src[i] <= "Z" || src[i] >= "0" && src[i] <= "9" || src[i] === "_"))
18413
+ i++;
18414
+ tokens.push({ t: 35 /* BuiltinCall */, v: src.slice(start, i) });
18415
+ continue;
18416
+ }
18417
+ i++;
18418
+ }
18419
+ tokens.push({ t: 13 /* EOF */ });
18420
+ return tokens;
18421
+ }
18422
+
18423
+ // src/genui/lang/parser/types.ts
18424
+ function isElementNode(value) {
18425
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
18426
+ const node = value;
18427
+ return node.type === "element" && typeof node.typeName === "string" && typeof node.props === "object" && node.props !== null && typeof node.partial === "boolean";
18428
+ }
18429
+
18430
+ // src/genui/lang/parser/materialize.ts
18431
+ function containsDynamicValue(v) {
18432
+ if (v == null || typeof v !== "object") return false;
18433
+ if (isASTNode(v)) return true;
18434
+ if (Array.isArray(v)) return v.some(containsDynamicValue);
18435
+ if (isElementNode(v)) {
18436
+ return Object.values(v.props).some(containsDynamicValue);
18437
+ }
18438
+ const obj = v;
18439
+ return Object.values(obj).some(containsDynamicValue);
18440
+ }
18441
+ function resolveRef(name, ctx, mode) {
18442
+ if (ctx.visited.has(name)) {
18443
+ ctx.unres.push(name);
18444
+ return mode === "expr" ? { k: "Ph", n: name } : null;
18445
+ }
18446
+ if (!ctx.syms.has(name)) {
18447
+ ctx.unres.push(name);
18448
+ return mode === "expr" ? { k: "Ph", n: name } : null;
18449
+ }
18450
+ const target = ctx.syms.get(name);
18451
+ ctx.unreached?.delete(name);
18452
+ if (target.k === "Comp" && isReservedCall(target.name)) {
18453
+ const refType = target.name === RESERVED_CALLS.Mutation ? "mutation" : "query";
18454
+ return { k: "RuntimeRef", n: name, refType };
18455
+ }
18456
+ ctx.visited.add(name);
18457
+ const prevStatementId = ctx.currentStatementId;
18458
+ ctx.currentStatementId = name;
18459
+ try {
18460
+ const result = mode === "value" ? materializeValue(target, ctx) : materializeExpr(target, ctx);
18461
+ if (mode === "value" && isElementNode(result)) {
18462
+ result.statementId = name;
18463
+ }
18464
+ return result;
18465
+ } finally {
18466
+ ctx.currentStatementId = prevStatementId;
18467
+ ctx.visited.delete(name);
18468
+ }
18469
+ }
18470
+ function materializeLazyBuiltin(node, ctx, scopedRefs) {
18471
+ if (!LAZY_BUILTINS.has(node.name) || node.args.length < 3) return null;
18472
+ const varArg = node.args[1];
18473
+ const varName = varArg.k === "Ref" ? varArg.n : varArg.k === "Str" ? varArg.v : null;
18474
+ if (!varName) return null;
18475
+ const nextScopedRefs = new Set(scopedRefs);
18476
+ nextScopedRefs.add(varName);
18477
+ const recursedArgs = node.args.map(
18478
+ (a, i) => i === 1 ? a : materializeExprInternal(a, ctx, nextScopedRefs)
18479
+ );
18480
+ return { ...node, args: recursedArgs };
18481
+ }
18482
+ function materializeExprInternal(node, ctx, scopedRefs) {
18483
+ switch (node.k) {
18484
+ case "Ref":
18485
+ return scopedRefs.has(node.n) ? node : resolveRef(node.n, ctx, "expr");
18486
+ case "Ph":
18487
+ return node;
18488
+ case "Comp": {
18489
+ const lazy2 = materializeLazyBuiltin(node, ctx, scopedRefs);
18490
+ if (lazy2) return lazy2;
18491
+ const recursedArgs = node.args.map((a) => materializeExprInternal(a, ctx, scopedRefs));
18492
+ if (isBuiltin(node.name) || isReservedCall(node.name)) {
18493
+ return { ...node, args: recursedArgs };
18494
+ }
18495
+ const def = ctx.cat?.get(node.name);
18496
+ if (def) {
18497
+ const mappedProps = {};
18498
+ for (let i = 0; i < def.params.length && i < recursedArgs.length; i++) {
18499
+ mappedProps[def.params[i].name] = recursedArgs[i];
18500
+ }
18501
+ return { ...node, args: recursedArgs, mappedProps };
18502
+ }
18503
+ ctx.errors.push({
18504
+ code: "unknown-component",
18505
+ component: node.name,
18506
+ path: "",
18507
+ message: `Unknown component "${node.name}" \u2014 not found in catalog or builtins`,
18508
+ statementId: ctx.currentStatementId
18509
+ });
18510
+ return { ...node, args: recursedArgs };
18511
+ }
18512
+ case "Arr":
18513
+ return { ...node, els: node.els.map((e) => materializeExprInternal(e, ctx, scopedRefs)) };
18514
+ case "Obj":
18515
+ return {
18516
+ ...node,
18517
+ entries: node.entries.map(
18518
+ ([k, v]) => [k, materializeExprInternal(v, ctx, scopedRefs)]
18519
+ )
18520
+ };
18521
+ case "BinOp":
18522
+ return {
18523
+ ...node,
18524
+ left: materializeExprInternal(node.left, ctx, scopedRefs),
18525
+ right: materializeExprInternal(node.right, ctx, scopedRefs)
18526
+ };
18527
+ case "UnaryOp":
18528
+ return { ...node, operand: materializeExprInternal(node.operand, ctx, scopedRefs) };
18529
+ case "Ternary":
18530
+ return {
18531
+ ...node,
18532
+ cond: materializeExprInternal(node.cond, ctx, scopedRefs),
18533
+ then: materializeExprInternal(node.then, ctx, scopedRefs),
18534
+ else: materializeExprInternal(node.else, ctx, scopedRefs)
18535
+ };
18536
+ case "Member":
18537
+ return { ...node, obj: materializeExprInternal(node.obj, ctx, scopedRefs) };
18538
+ case "Index":
18539
+ return {
18540
+ ...node,
18541
+ obj: materializeExprInternal(node.obj, ctx, scopedRefs),
18542
+ index: materializeExprInternal(node.index, ctx, scopedRefs)
18543
+ };
18544
+ case "Assign":
18545
+ return { ...node, value: materializeExprInternal(node.value, ctx, scopedRefs) };
18546
+ // Literals, StateRef, RuntimeRef — pass through unchanged
18547
+ default:
18548
+ return node;
18549
+ }
18550
+ }
18551
+ function materializeExpr(node, ctx) {
18552
+ return materializeExprInternal(node, ctx, /* @__PURE__ */ new Set());
18553
+ }
18554
+ function materializeValue(node, ctx) {
18555
+ switch (node.k) {
18556
+ // ── Ref resolution ───────────────────────────────────────────────────
18557
+ case "Ref":
18558
+ return resolveRef(node.n, ctx, "value");
18559
+ // ── Literals → plain values ──────────────────────────────────────────
18560
+ case "Str":
18561
+ return node.v;
18562
+ case "Num":
18563
+ return node.v;
18564
+ case "Bool":
18565
+ return node.v;
18566
+ case "Null":
18567
+ return null;
18568
+ case "Ph":
18569
+ return null;
18570
+ // ── Collections ──────────────────────────────────────────────────────
18571
+ case "Arr": {
18572
+ const items = [];
18573
+ for (const e of node.els) {
18574
+ if (e.k === "Ph") continue;
18575
+ const value = materializeValue(e, ctx);
18576
+ if (value === null && (e.k === "Comp" || e.k === "Ref")) continue;
18577
+ items.push(value);
18578
+ }
18579
+ return items;
18580
+ }
18581
+ case "Obj": {
18582
+ const o = {};
18583
+ for (const [k, v] of node.entries) o[k] = materializeValue(v, ctx);
18584
+ return o;
18585
+ }
18586
+ // ── Component nodes ──────────────────────────────────────────────────
18587
+ case "Comp": {
18588
+ const { name, args } = node;
18589
+ if (isBuiltin(name)) {
18590
+ const lazy2 = materializeLazyBuiltin(node, ctx, /* @__PURE__ */ new Set());
18591
+ if (lazy2) return lazy2;
18592
+ return { ...node, args: args.map((a) => materializeExpr(a, ctx)) };
18593
+ }
18594
+ if (isReservedCall(name)) {
18595
+ ctx.errors.push({
18596
+ code: "inline-reserved",
18597
+ component: name,
18598
+ path: "",
18599
+ message: `${name}() must be declared as a top-level statement, not used inline as a value`,
18600
+ statementId: ctx.currentStatementId
18601
+ });
18602
+ return null;
18603
+ }
18604
+ const def = ctx.cat?.get(name);
18605
+ const props = {};
18606
+ if (def) {
18607
+ for (let i = 0; i < def.params.length && i < args.length; i++) {
18608
+ props[def.params[i].name] = materializeValue(args[i], ctx);
18609
+ }
18610
+ if (args.length > def.params.length) {
18611
+ const excessCount = args.length - def.params.length;
18612
+ ctx.errors.push({
18613
+ code: "excess-args",
18614
+ component: name,
18615
+ path: "",
18616
+ message: `${name} takes ${def.params.length} arg(s), got ${args.length} (${excessCount} excess dropped)`,
18617
+ statementId: ctx.currentStatementId
18618
+ });
18619
+ }
18620
+ const missingRequired = def.params.filter(
18621
+ (p) => p.required && (!(p.name in props) || props[p.name] === null)
18622
+ );
18623
+ if (missingRequired.length) {
18624
+ const stillInvalid = missingRequired.filter((p) => {
18625
+ if (p.defaultValue !== void 0) {
18626
+ props[p.name] = p.defaultValue;
18627
+ return false;
18628
+ }
18629
+ return true;
18630
+ });
18631
+ if (stillInvalid.length) {
18632
+ for (const p of stillInvalid) {
18633
+ const isNull = p.name in props;
18634
+ ctx.errors.push({
18635
+ code: isNull ? "null-required" : "missing-required",
18636
+ component: name,
18637
+ path: `/${p.name}`,
18638
+ message: isNull ? `required field "${p.name}" cannot be null` : `missing required field "${p.name}"`,
18639
+ statementId: ctx.currentStatementId
18640
+ });
18641
+ }
18642
+ return null;
18643
+ }
18644
+ }
18645
+ } else if (!isBuiltin(name) && !isReservedCall(name)) {
18646
+ ctx.errors.push({
18647
+ code: "unknown-component",
18648
+ component: name,
18649
+ path: "",
18650
+ message: `Unknown component "${name}" \u2014 not found in catalog or builtins`,
18651
+ statementId: ctx.currentStatementId
18652
+ });
18653
+ return null;
18654
+ }
18655
+ const hasDynamicProps = Object.values(props).some((v) => containsDynamicValue(v));
18656
+ return { type: "element", typeName: name, props, partial: ctx.partial, hasDynamicProps };
18657
+ }
18658
+ // ── Runtime expression nodes → preserve as ASTNode, normalize children ─
18659
+ default: {
18660
+ if (isRuntimeExpr(node)) {
18661
+ return materializeExpr(node, ctx);
18662
+ }
18663
+ return node;
18664
+ }
18665
+ }
18666
+ }
18667
+
18668
+ // src/genui/lang/parser/statements.ts
18669
+ function autoClose(input) {
18670
+ const stack = [];
18671
+ let inStr = false;
18672
+ let esc = false;
18673
+ for (let i = 0; i < input.length; i++) {
18674
+ const c = input[i];
18675
+ if (esc) {
18676
+ esc = false;
18677
+ continue;
18678
+ }
18679
+ if (c === "\\" && inStr) {
18680
+ esc = true;
18681
+ continue;
18682
+ }
18683
+ if (inStr) {
18684
+ if (c === inStr) inStr = false;
18685
+ continue;
18686
+ }
18687
+ if (c === '"' || c === "'") {
18688
+ inStr = c;
18689
+ continue;
18690
+ }
18691
+ if (c === "(" || c === "[" || c === "{") stack.push(c);
18692
+ else if (c === ")" && stack[stack.length - 1] === "(") stack.pop();
18693
+ else if (c === "]" && stack[stack.length - 1] === "[") stack.pop();
18694
+ else if (c === "}" && stack[stack.length - 1] === "{") stack.pop();
18695
+ }
18696
+ const wasIncomplete = !!inStr || stack.length > 0;
18697
+ if (!wasIncomplete) return { text: input, wasIncomplete: false };
18698
+ let out = input;
18699
+ if (inStr) {
18700
+ if (esc) out += "\\";
18701
+ out += inStr;
18702
+ }
18703
+ for (let j = stack.length - 1; j >= 0; j--)
18704
+ out += stack[j] === "(" ? ")" : stack[j] === "[" ? "]" : "}";
18705
+ return { text: out, wasIncomplete: true };
18706
+ }
18707
+ function split(tokens) {
18708
+ const stmts = [];
18709
+ let pos = 0;
18710
+ while (pos < tokens.length) {
18711
+ while (pos < tokens.length && tokens[pos].t === 0 /* Newline */) pos++;
18712
+ if (pos >= tokens.length || tokens[pos].t === 13 /* EOF */) break;
18713
+ const tok = tokens[pos];
18714
+ if (tok.t !== 16 /* Ident */ && tok.t !== 17 /* Type */ && tok.t !== 18 /* StateVar */) {
18715
+ while (pos < tokens.length && tokens[pos].t !== 0 /* Newline */ && tokens[pos].t !== 13 /* EOF */) pos++;
18716
+ continue;
18717
+ }
18718
+ const id = tok.v;
18719
+ const idTokenType = tok.t;
18720
+ pos++;
18721
+ if (pos >= tokens.length || tokens[pos].t !== 9 /* Equals */) {
18722
+ while (pos < tokens.length && tokens[pos].t !== 0 /* Newline */ && tokens[pos].t !== 13 /* EOF */) pos++;
18723
+ continue;
18724
+ }
18725
+ pos++;
18726
+ const expr = [];
18727
+ let depth = 0;
18728
+ let ternaryDepth = 0;
18729
+ while (pos < tokens.length && tokens[pos].t !== 13 /* EOF */) {
18730
+ const tt = tokens[pos].t;
18731
+ if (tt === 0 /* Newline */ && depth <= 0 && ternaryDepth <= 0) {
18732
+ let peek = pos + 1;
18733
+ while (peek < tokens.length && tokens[peek].t === 0 /* Newline */) peek++;
18734
+ const nextT = peek < tokens.length ? tokens[peek].t : 13 /* EOF */;
18735
+ if (nextT === 34 /* Question */ || nextT === 8 /* Colon */ && ternaryDepth > 0) {
18736
+ pos++;
18737
+ continue;
18738
+ }
18739
+ break;
18740
+ }
18741
+ if (tt === 0 /* Newline */) {
18742
+ pos++;
18743
+ continue;
18744
+ }
18745
+ if (tt === 1 /* LParen */ || tt === 3 /* LBrack */ || tt === 5 /* LBrace */) depth++;
18746
+ else if ((tt === 2 /* RParen */ || tt === 4 /* RBrack */ || tt === 6 /* RBrace */) && depth > 0) depth--;
18747
+ else if (tt === 34 /* Question */ && depth === 0) ternaryDepth++;
18748
+ else if (tt === 8 /* Colon */ && depth === 0 && ternaryDepth > 0) ternaryDepth--;
18749
+ expr.push(tokens[pos++]);
18750
+ }
18751
+ if (expr.length) stmts.push({ id, idTokenType, tokens: expr });
18752
+ }
18753
+ return stmts;
18754
+ }
18755
+
18756
+ // src/genui/lang/parser/parser.ts
18757
+ function emptyResult(incomplete = true) {
18758
+ return {
18759
+ root: null,
18760
+ meta: {
18761
+ incomplete,
18762
+ unresolved: [],
18763
+ orphaned: [],
18764
+ statementCount: 0,
18765
+ errors: []
18766
+ },
18767
+ stateDeclarations: {},
18768
+ queryStatements: [],
18769
+ mutationStatements: []
18770
+ };
18771
+ }
18772
+ function collectQueryDeps(node) {
18773
+ if (!isASTNode(node)) return [];
18774
+ const refs = /* @__PURE__ */ new Set();
18775
+ walkAST(node, (current) => {
18776
+ if (current.k === "StateRef") refs.add(current.n);
18777
+ });
18778
+ return [...refs];
18779
+ }
18780
+ function classifyStatement(raw, expr) {
18781
+ if (expr.k === "Comp" && expr.name === RESERVED_CALLS.Query) {
18782
+ const deps = collectQueryDeps(expr.args[1]);
18783
+ return {
18784
+ kind: "query",
18785
+ id: raw.id,
18786
+ call: { callee: RESERVED_CALLS.Query, args: expr.args },
18787
+ expr,
18788
+ deps: deps.length > 0 ? deps : void 0
18789
+ };
18790
+ }
18791
+ if (expr.k === "Comp" && expr.name === RESERVED_CALLS.Mutation) {
18792
+ return {
18793
+ kind: "mutation",
18794
+ id: raw.id,
18795
+ call: { callee: RESERVED_CALLS.Mutation, args: expr.args },
18796
+ expr
18797
+ };
18798
+ }
18799
+ if (raw.idTokenType === 18 /* StateVar */) {
18800
+ return { kind: "state", id: raw.id, init: expr };
18801
+ }
18802
+ return { kind: "value", id: raw.id, expr };
18803
+ }
18804
+ function extractStatements(stmts, ctx) {
18805
+ const stateDeclarations = {};
18806
+ const queryStatements = [];
18807
+ const mutationStatements = [];
18808
+ for (const stmt of stmts) {
18809
+ switch (stmt.kind) {
18810
+ case "state":
18811
+ stateDeclarations[stmt.id] = materializeValue(stmt.init, ctx);
18812
+ break;
18813
+ case "query":
18814
+ queryStatements.push({
18815
+ statementId: stmt.id,
18816
+ toolAST: stmt.call.args[0] ?? null,
18817
+ argsAST: stmt.call.args[1] ?? null,
18818
+ defaultsAST: stmt.call.args[2] ?? null,
18819
+ refreshAST: stmt.call.args[3] ?? null,
18820
+ deps: stmt.deps,
18821
+ complete: true
18822
+ });
18823
+ break;
18824
+ case "mutation":
18825
+ mutationStatements.push({
18826
+ statementId: stmt.id,
18827
+ toolAST: stmt.call.args[0] ?? null,
18828
+ argsAST: stmt.call.args[1] ?? null
18829
+ });
18830
+ break;
18831
+ }
18832
+ }
18833
+ for (const stmt of stmts) {
18834
+ const nodes = stmt.kind === "state" ? [stmt.init] : stmt.kind === "value" ? [stmt.expr] : stmt.kind === "query" || stmt.kind === "mutation" ? stmt.call.args : [];
18835
+ for (const node of nodes) {
18836
+ for (const dep of collectQueryDeps(node)) {
18837
+ if (!(dep in stateDeclarations)) {
18838
+ stateDeclarations[dep] = null;
18839
+ }
18840
+ }
18841
+ }
18842
+ }
18843
+ return { stateDeclarations, queryStatements, mutationStatements };
18844
+ }
18845
+ var DEFAULT_ROOT_STATEMENT_ID = "root";
18846
+ function isComponentStatement(stmt) {
18847
+ return stmt.kind === "value" && stmt.expr.k === "Comp" && !isBuiltin(stmt.expr.name) && stmt.expr.name !== RESERVED_CALLS.Query && stmt.expr.name !== RESERVED_CALLS.Mutation;
18848
+ }
18849
+ function pickEntryId(stmtMap, typedStmts, firstId, rootName) {
18850
+ if (stmtMap.has(DEFAULT_ROOT_STATEMENT_ID)) return DEFAULT_ROOT_STATEMENT_ID;
18851
+ if (rootName && stmtMap.has(rootName)) return rootName;
18852
+ const preferredComponent = rootName ? typedStmts.find((stmt) => isComponentStatement(stmt) && stmt.expr.name === rootName) : void 0;
18853
+ if (preferredComponent) return preferredComponent.id;
18854
+ const firstComponent = typedStmts.find(isComponentStatement);
18855
+ return firstComponent?.id ?? firstId;
18856
+ }
18857
+ function buildResult(stmtMap, typedStmts, firstId, wasIncomplete, stmtCount, cat, rootName) {
18858
+ const entryId = pickEntryId(stmtMap, typedStmts, firstId, rootName);
18859
+ if (!stmtMap.has(entryId)) return emptyResult(wasIncomplete);
18860
+ const syms = /* @__PURE__ */ new Map();
18861
+ for (const [id, stmt] of stmtMap) {
18862
+ syms.set(id, stmt.kind === "state" ? stmt.init : stmt.expr);
18863
+ }
18864
+ const unres = [];
18865
+ const errors = [];
18866
+ const unreached = /* @__PURE__ */ new Set();
18867
+ for (const [id, stmt] of stmtMap) {
18868
+ if (id === entryId) continue;
18869
+ if (stmt.kind === "state" || stmt.kind === "query" || stmt.kind === "mutation") continue;
18870
+ unreached.add(id);
18871
+ }
18872
+ const ctx = {
18873
+ syms,
18874
+ cat,
18875
+ errors,
18876
+ unres,
18877
+ visited: /* @__PURE__ */ new Set(),
18878
+ partial: wasIncomplete,
18879
+ currentStatementId: entryId,
18880
+ unreached
18881
+ };
18882
+ const materialized = materializeValue(syms.get(entryId), ctx);
18883
+ const root = isElementNode(materialized) ? materialized : null;
18884
+ if (root) root.statementId = entryId;
18885
+ const { stateDeclarations, queryStatements, mutationStatements } = extractStatements(
18886
+ typedStmts,
18887
+ ctx
18888
+ );
18889
+ const orphaned = [...unreached];
18890
+ return {
18891
+ root,
18892
+ meta: {
18893
+ incomplete: wasIncomplete,
18894
+ unresolved: unres,
18895
+ orphaned,
18896
+ statementCount: stmtCount,
18897
+ errors
18898
+ },
18899
+ stateDeclarations,
18900
+ queryStatements,
18901
+ mutationStatements
18902
+ };
18903
+ }
18904
+ function skipString(input, start) {
18905
+ if (input[start] !== '"') return start;
18906
+ let i = start + 1;
18907
+ while (i < input.length) {
18908
+ const c = input[i];
18909
+ if (c === "\\") {
18910
+ i += 2;
18911
+ } else if (c === '"') {
18912
+ return i + 1;
18913
+ } else {
18914
+ i++;
18915
+ }
18916
+ }
18917
+ return i;
18918
+ }
18919
+ function stripFences(input) {
18920
+ const blocks = [];
18921
+ let i = 0;
18922
+ while (i < input.length) {
18923
+ let fenceStart = -1;
18924
+ while (i < input.length) {
18925
+ const nextI = skipString(input, i);
18926
+ if (nextI > i) {
18927
+ i = nextI;
18928
+ continue;
18929
+ }
18930
+ const c = input[i];
18931
+ if (c === "`" && i + 1 < input.length && input[i + 1] === "`" && i + 2 < input.length && input[i + 2] === "`") {
18932
+ fenceStart = i;
18933
+ break;
18934
+ }
18935
+ i++;
18936
+ }
18937
+ if (fenceStart === -1) break;
18938
+ let j = fenceStart + 3;
18939
+ while (j < input.length && input[j] !== "\n") j++;
18940
+ if (j >= input.length) {
18941
+ blocks.push(input.slice(fenceStart + 3).replace(/^[^\n]*\n?/, ""));
18942
+ i = input.length;
18943
+ break;
18944
+ }
18945
+ j++;
18946
+ let closePos = -1;
18947
+ let k = j;
18948
+ while (k < input.length) {
18949
+ const nextK = skipString(input, k);
18950
+ if (nextK > k) {
18951
+ k = nextK;
18952
+ continue;
18953
+ }
18954
+ const c = input[k];
18955
+ if (c === "`" && k + 1 < input.length && input[k + 1] === "`" && k + 2 < input.length && input[k + 2] === "`") {
18956
+ closePos = k;
18957
+ break;
18958
+ }
18959
+ k++;
18960
+ }
18961
+ if (closePos !== -1) {
18962
+ blocks.push(input.slice(j, closePos));
18963
+ i = closePos + 3;
18964
+ } else {
18965
+ blocks.push(input.slice(j));
18966
+ i = input.length;
18967
+ }
18968
+ }
18969
+ if (blocks.length > 0) return blocks.join("\n");
18970
+ if (input.startsWith("```")) {
18971
+ let j = 3;
18972
+ while (j < input.length && input[j] !== "\n") j++;
18973
+ const start = j < input.length ? j + 1 : 3;
18974
+ const body = input.slice(start);
18975
+ const trailingFence = body.lastIndexOf("```");
18976
+ if (trailingFence !== -1) {
18977
+ return body.slice(0, trailingFence);
18978
+ }
18979
+ return body;
18980
+ }
18981
+ return input;
18982
+ }
18983
+ function stripComments(input) {
18984
+ let inStr = false;
18985
+ return input.split("\n").map((line) => {
18986
+ for (let i = 0; i < line.length; i++) {
18987
+ const c = line[i];
18988
+ if (inStr) {
18989
+ if (c === "\\" && i + 1 < line.length) {
18990
+ i++;
18991
+ continue;
18992
+ }
18993
+ if (c === inStr) inStr = false;
18994
+ continue;
18995
+ }
18996
+ if (c === '"' || c === "'") {
18997
+ inStr = c;
18998
+ continue;
18999
+ }
19000
+ if (c === "/" && line[i + 1] === "/") {
19001
+ return line.substring(0, i).trimEnd();
19002
+ }
19003
+ if (c === "#") {
19004
+ return line.substring(0, i).trimEnd();
19005
+ }
19006
+ }
19007
+ return line;
19008
+ }).join("\n");
19009
+ }
19010
+ function preprocess(input) {
19011
+ return stripComments(stripFences(input.trim())).trim();
19012
+ }
19013
+ function parse(input, cat, rootName) {
19014
+ const trimmed = preprocess(input);
19015
+ if (!trimmed) return emptyResult();
19016
+ const { text, wasIncomplete } = autoClose(trimmed);
19017
+ const stmts = split(tokenize(text));
19018
+ if (!stmts.length) return emptyResult(wasIncomplete);
19019
+ const stmtMap = /* @__PURE__ */ new Map();
19020
+ let firstId = "";
19021
+ for (const s of stmts) {
19022
+ const expr = parseExpression(s.tokens);
19023
+ const stmt = classifyStatement(s, expr);
19024
+ stmtMap.set(s.id, stmt);
19025
+ if (!firstId) firstId = s.id;
19026
+ }
19027
+ const typedStmts = [...stmtMap.values()];
19028
+ return buildResult(stmtMap, typedStmts, firstId, wasIncomplete, stmtMap.size, cat, rootName);
19029
+ }
19030
+ function createStreamParser(cat, rootName) {
19031
+ let buf = "";
19032
+ let cleaned = "";
19033
+ let completedEnd = 0;
19034
+ const completedStmtMap = /* @__PURE__ */ new Map();
19035
+ let firstId = "";
19036
+ function addStmt(text) {
19037
+ const t = text.trim();
19038
+ if (!t) return;
19039
+ for (const s of split(tokenize(t))) {
19040
+ const expr = parseExpression(s.tokens);
19041
+ const stmt = classifyStatement(s, expr);
19042
+ completedStmtMap.set(s.id, stmt);
19043
+ if (!firstId) firstId = s.id;
19044
+ }
19045
+ }
19046
+ function refreshCleaned() {
19047
+ const next = preprocess(buf);
19048
+ if (!next.startsWith(cleaned.slice(0, completedEnd))) {
19049
+ completedEnd = 0;
19050
+ completedStmtMap.clear();
19051
+ firstId = "";
19052
+ }
19053
+ cleaned = next;
19054
+ }
19055
+ function scanNewCompleted() {
19056
+ let depth = 0, ternaryDepth = 0, inStr = false, esc = false;
19057
+ let stmtStart = completedEnd;
19058
+ for (let i = completedEnd; i < cleaned.length; i++) {
19059
+ const c = cleaned[i];
19060
+ if (esc) {
19061
+ esc = false;
19062
+ continue;
19063
+ }
19064
+ if (c === "\\" && inStr) {
19065
+ esc = true;
19066
+ continue;
19067
+ }
19068
+ if (inStr) {
19069
+ if (c === inStr) inStr = false;
19070
+ continue;
19071
+ }
19072
+ if (c === '"' || c === "'") {
19073
+ inStr = c;
19074
+ continue;
19075
+ }
19076
+ if (c === "(" || c === "[" || c === "{") depth++;
19077
+ else if (c === ")" || c === "]" || c === "}") depth = Math.max(0, depth - 1);
19078
+ else if (c === "?" && depth === 0) ternaryDepth++;
19079
+ else if (c === ":" && depth === 0 && ternaryDepth > 0) ternaryDepth--;
19080
+ else if (c === "\n" && depth <= 0 && ternaryDepth <= 0) {
19081
+ let peek = i + 1;
19082
+ while (peek < cleaned.length && (cleaned[peek] === " " || cleaned[peek] === " " || cleaned[peek] === "\r" || cleaned[peek] === "\n"))
19083
+ peek++;
19084
+ if (peek < cleaned.length && (cleaned[peek] === "?" || cleaned[peek] === ":" && ternaryDepth > 0)) {
19085
+ continue;
19086
+ }
19087
+ const t = cleaned.slice(stmtStart, i).trim();
19088
+ if (t) addStmt(t);
19089
+ stmtStart = i + 1;
19090
+ completedEnd = i + 1;
19091
+ }
19092
+ }
19093
+ return stmtStart;
19094
+ }
19095
+ function currentResult() {
19096
+ refreshCleaned();
19097
+ const pendingStart = scanNewCompleted();
19098
+ const pendingText = cleaned.slice(pendingStart).trim();
19099
+ if (!pendingText) {
19100
+ if (completedStmtMap.size === 0) return emptyResult();
19101
+ return buildResult(
19102
+ completedStmtMap,
19103
+ [...completedStmtMap.values()],
19104
+ firstId,
19105
+ false,
19106
+ completedStmtMap.size,
19107
+ cat,
19108
+ rootName
19109
+ );
19110
+ }
19111
+ const { text: closed, wasIncomplete } = autoClose(pendingText);
19112
+ const stmts = split(tokenize(closed));
19113
+ if (!stmts.length) {
19114
+ if (completedStmtMap.size === 0) return emptyResult(wasIncomplete);
19115
+ return buildResult(
19116
+ completedStmtMap,
19117
+ [...completedStmtMap.values()],
19118
+ firstId,
19119
+ wasIncomplete,
19120
+ completedStmtMap.size,
19121
+ cat,
19122
+ rootName
19123
+ );
19124
+ }
19125
+ const allStmtMap = new Map(completedStmtMap);
19126
+ for (const s of stmts) {
19127
+ const expr = parseExpression(s.tokens);
19128
+ const stmt = classifyStatement(s, expr);
19129
+ allStmtMap.set(s.id, stmt);
19130
+ }
19131
+ const allTypedStmts = [...allStmtMap.values()];
19132
+ const fid = firstId || stmts[0].id;
19133
+ return buildResult(
19134
+ allStmtMap,
19135
+ allTypedStmts,
19136
+ fid,
19137
+ wasIncomplete,
19138
+ allStmtMap.size,
19139
+ cat,
19140
+ rootName
19141
+ );
19142
+ }
19143
+ function reset() {
19144
+ buf = "";
19145
+ cleaned = "";
19146
+ completedEnd = 0;
19147
+ completedStmtMap.clear();
19148
+ firstId = "";
19149
+ }
19150
+ return {
19151
+ push(chunk) {
19152
+ buf += chunk;
19153
+ return currentResult();
19154
+ },
19155
+ set(fullText) {
19156
+ if (fullText.length < buf.length || !fullText.startsWith(buf)) {
19157
+ reset();
19158
+ }
19159
+ const delta = fullText.slice(buf.length);
19160
+ if (delta) buf += delta;
19161
+ return currentResult();
19162
+ },
19163
+ getResult: currentResult
19164
+ };
19165
+ }
19166
+ function useGenUIProgram(text, catalog) {
19167
+ const parserRef = React14.useRef(
19168
+ null
19169
+ );
19170
+ if (!parserRef.current || parserRef.current.catalog !== catalog) {
19171
+ parserRef.current = { catalog, parser: createStreamParser(catalog, "root") };
19172
+ }
19173
+ const lastGoodRef = React14.useRef(null);
19174
+ return React14.useMemo(() => {
19175
+ const result = parserRef.current.parser.set(text);
19176
+ if (result.root) {
19177
+ lastGoodRef.current = result.root;
19178
+ }
19179
+ return { result, root: result.root ?? lastGoodRef.current };
19180
+ }, [text, catalog]);
19181
+ }
19182
+ var noop = () => {
19183
+ };
19184
+ function childKey(value, index) {
19185
+ if (isElementNode(value) && value.statementId) return `s:${value.statementId}`;
19186
+ return `i:${index}`;
19187
+ }
19188
+ var RenderDepthContext = React14.createContext(0);
19189
+ var MAX_DEPTH = 64;
19190
+ var GenUINode = React14.memo(function GenUINode2({
19191
+ node,
19192
+ components,
19193
+ onAction,
19194
+ isStreaming,
19195
+ onTelemetry
19196
+ }) {
19197
+ const depth = React14.useContext(RenderDepthContext);
19198
+ if (depth > MAX_DEPTH) {
19199
+ onTelemetry?.({ kind: "dropped-node", typeName: node.typeName });
19200
+ return null;
19201
+ }
19202
+ const renderer = components[node.typeName];
19203
+ if (!renderer) {
19204
+ onTelemetry?.({ kind: "unknown-component", typeName: node.typeName });
19205
+ return null;
19206
+ }
19207
+ const render = (value) => {
19208
+ if (value == null) return null;
19209
+ if (isElementNode(value)) {
19210
+ return /* @__PURE__ */ jsxRuntime.jsx(RenderDepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsxRuntime.jsx(
19211
+ GenUINode2,
19212
+ {
19213
+ node: value,
19214
+ components,
19215
+ onAction,
19216
+ isStreaming,
19217
+ onTelemetry
19218
+ }
19219
+ ) });
19220
+ }
19221
+ if (Array.isArray(value)) {
19222
+ return value.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(React14__default.default.Fragment, { children: render(item) }, childKey(item, index)));
19223
+ }
19224
+ if (typeof value === "object" && isRuntimeExpr(value)) return null;
19225
+ if (typeof value === "string" || typeof value === "number") return String(value);
19226
+ return null;
19227
+ };
19228
+ return renderer({ node, ctx: { render, onAction, isStreaming } });
19229
+ });
19230
+ function GenUIView({
19231
+ root,
19232
+ components,
19233
+ onAction = noop,
19234
+ isStreaming = false,
19235
+ onTelemetry,
19236
+ placeholder = null
19237
+ }) {
19238
+ if (!root) return placeholder;
19239
+ return /* @__PURE__ */ jsxRuntime.jsx(
19240
+ GenUINode,
19241
+ {
19242
+ node: root,
19243
+ components,
19244
+ onAction,
19245
+ isStreaming,
19246
+ onTelemetry
19247
+ }
19248
+ );
19249
+ }
19250
+
19251
+ // src/genui/registry.ts
19252
+ var CIMPLIFY_GENUI_REGISTRY = {
19253
+ version: "3",
19254
+ components: [
19255
+ {
19256
+ name: "Stack",
19257
+ description: 'Layout container. direction: "column" (default) or "row"; gap in points (default 12)',
19258
+ params: [{ name: "children", required: true }, { name: "direction" }, { name: "gap" }]
19259
+ },
19260
+ {
19261
+ name: "Card",
19262
+ description: "Elevated surface grouping related content, with an optional title",
19263
+ params: [{ name: "children", required: true }, { name: "title" }]
19264
+ },
19265
+ {
19266
+ name: "TextContent",
19267
+ description: 'Text block. size: "display", "heading", "title", "body" (default), "label", "caption"',
19268
+ params: [{ name: "text", required: true }, { name: "size" }]
19269
+ },
19270
+ {
19271
+ name: "Stat",
19272
+ description: "Compact stat: small label over a bold value, optional sub line and tone",
19273
+ params: [
19274
+ { name: "label", required: true },
19275
+ { name: "value", required: true },
19276
+ { name: "sub" },
19277
+ { name: "tone" }
19278
+ ]
19279
+ },
19280
+ {
19281
+ name: "Metric",
19282
+ description: "KPI card with label, value, optional percent change and SF Symbol icon",
19283
+ params: [
19284
+ { name: "label", required: true },
19285
+ { name: "value", required: true },
19286
+ { name: "change" },
19287
+ { name: "icon" }
19288
+ ]
19289
+ },
19290
+ {
19291
+ name: "KeyValue",
19292
+ description: "Label/value row; set mono true for numeric values",
19293
+ params: [
19294
+ { name: "label", required: true },
19295
+ { name: "value", required: true },
19296
+ { name: "mono" }
19297
+ ]
19298
+ },
19299
+ {
19300
+ name: "Badge",
19301
+ description: "Small status chip. tone: neutral, positive, info, indigo, violet, warning, danger",
19302
+ params: [{ name: "label", required: true }, { name: "tone" }]
19303
+ },
19304
+ {
19305
+ name: "Callout",
19306
+ description: "Inline alert with title, optional message. tone: info (default), success, warning, danger, accent, neutral",
19307
+ params: [{ name: "title", required: true }, { name: "message" }, { name: "tone" }]
19308
+ },
19309
+ {
19310
+ name: "Button",
19311
+ description: 'Action button. action: "action:name" string or Action([...]) steps. variant: primary, cta, secondary (default), ghost, destructive',
19312
+ params: [
19313
+ { name: "label", required: true },
19314
+ { name: "action", required: true },
19315
+ { name: "variant" }
19316
+ ]
19317
+ },
19318
+ {
19319
+ name: "Buttons",
19320
+ description: 'Row (default) or column of Buttons; direction: "row" or "column"',
19321
+ params: [{ name: "children", required: true }, { name: "direction" }]
19322
+ },
19323
+ {
19324
+ name: "Divider",
19325
+ description: "Hairline separator",
19326
+ params: []
19327
+ },
19328
+ {
19329
+ name: "Table",
19330
+ description: "Data table: headers is an array of strings, rows an array of cell arrays",
19331
+ params: [
19332
+ { name: "headers", required: true },
19333
+ { name: "rows", required: true }
19334
+ ]
19335
+ },
19336
+ {
19337
+ name: "BarChart",
19338
+ description: "Bar chart: labels (x axis strings) and values (numbers), optional title",
19339
+ params: [
19340
+ { name: "labels", required: true },
19341
+ { name: "values", required: true },
19342
+ { name: "title" }
19343
+ ]
19344
+ },
19345
+ {
19346
+ name: "LineChart",
19347
+ description: "Line chart with area fill: labels and values, optional title",
19348
+ params: [
19349
+ { name: "labels", required: true },
19350
+ { name: "values", required: true },
19351
+ { name: "title" }
19352
+ ]
19353
+ },
19354
+ {
19355
+ name: "Money",
19356
+ description: "Formatted money amount, never abbreviated. currency: ISO code (default USD)",
19357
+ params: [{ name: "amount", required: true }, { name: "currency" }]
19358
+ },
19359
+ {
19360
+ name: "Image",
19361
+ description: "Remote image by URL with optional caption",
19362
+ params: [{ name: "url", required: true }, { name: "caption" }]
19363
+ },
19364
+ {
19365
+ name: "ListRow",
19366
+ description: "Entity row for orders/customers/products/invoices: initials avatar (or SF Symbol tile via symbol), title + subtitle, trailing value and badge with tone",
19367
+ params: [
19368
+ { name: "title", required: true },
19369
+ { name: "subtitle" },
19370
+ { name: "value" },
19371
+ { name: "badge" },
19372
+ { name: "tone" },
19373
+ { name: "symbol" }
19374
+ ]
19375
+ },
19376
+ {
19377
+ name: "Timeline",
19378
+ description: "Event history (order journey, payment trail): events is an array of {title, detail?, time?, tone?} objects, newest first",
19379
+ params: [{ name: "events", required: true }]
19380
+ },
19381
+ {
19382
+ name: "Progress",
19383
+ description: "Amount toward a bound (goal, stock cover, capacity): numeric value and target (default 100), optional detail caption and tone",
19384
+ params: [
19385
+ { name: "label", required: true },
19386
+ { name: "value", required: true },
19387
+ { name: "target" },
19388
+ { name: "detail" },
19389
+ { name: "tone" }
19390
+ ]
19391
+ },
19392
+ {
19393
+ name: "DonutChart",
19394
+ description: "Share of a whole (sales by channel, revenue by category): labels + values, optional title and center display string (e.g. the formatted total)",
19395
+ params: [
19396
+ { name: "labels", required: true },
19397
+ { name: "values", required: true },
19398
+ { name: "title" },
19399
+ { name: "center" }
19400
+ ]
19401
+ },
19402
+ {
19403
+ name: "StatusTrack",
19404
+ description: "Stage tracker (order fulfilment, invoice lifecycle): steps are stage names, current is the active step name or index",
19405
+ params: [
19406
+ { name: "steps", required: true },
19407
+ { name: "current", required: true }
19408
+ ]
19409
+ },
19410
+ {
19411
+ name: "LineItems",
19412
+ description: "Order/quote/invoice money block: items is an array of {qty?, name, amount} with display-ready amount strings, adjustments an array of {label, amount, tone?}, total the anchored display string",
19413
+ params: [
19414
+ { name: "items", required: true },
19415
+ { name: "total", required: true },
19416
+ { name: "adjustments" }
19417
+ ]
19418
+ },
19419
+ {
19420
+ name: "Grid",
19421
+ description: "Tile layout for Stat/Metric children, columns default 2",
19422
+ params: [{ name: "children", required: true }, { name: "columns" }]
19423
+ },
19424
+ {
19425
+ name: "Banner",
19426
+ description: "Hero-stat moment on a tonal wash: big value, label, optional percent delta. tone: positive (default), warning, danger, info, neutral",
19427
+ params: [
19428
+ { name: "value", required: true },
19429
+ { name: "label", required: true },
19430
+ { name: "delta" },
19431
+ { name: "tone" }
19432
+ ]
19433
+ },
19434
+ {
19435
+ name: "EmptyState",
19436
+ description: "Nothing-to-show state with an SF Symbol and optional message",
19437
+ params: [{ name: "title", required: true }, { name: "message" }, { name: "symbol" }]
19438
+ }
19439
+ ]
19440
+ };
19441
+
19442
+ // src/genui/manifest.ts
19443
+ function genUIManifest(registry) {
19444
+ return {
19445
+ version: registry.version,
19446
+ components: registry.components.map((component) => ({
19447
+ name: component.name,
19448
+ description: component.description,
19449
+ params: component.params.map((param) => ({
19450
+ name: param.name,
19451
+ required: param.required ?? false
19452
+ }))
19453
+ }))
19454
+ };
19455
+ }
19456
+ function encodeString(value) {
19457
+ return JSON.stringify(value).replace(/\//g, "\\/");
19458
+ }
19459
+ function canonicalize(value) {
19460
+ if (value === null) return "null";
19461
+ if (typeof value === "string") return encodeString(value);
19462
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
19463
+ if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
19464
+ const keys = Object.keys(value).sort();
19465
+ const entries = keys.map((key) => `${encodeString(key)}:${canonicalize(value[key])}`);
19466
+ return `{${entries.join(",")}}`;
19467
+ }
19468
+ function genUIManifestJson(manifest) {
19469
+ return canonicalize(manifest);
19470
+ }
19471
+ async function genUIFingerprint(manifest) {
19472
+ const bytes = new TextEncoder().encode(genUIManifestJson(manifest));
19473
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
19474
+ return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 16);
19475
+ }
19476
+
19477
+ Object.defineProperty(exports, "getVariantDisplayName", {
19478
+ enumerable: true,
19479
+ get: function () { return chunkT7Z25EY4_js.getVariantDisplayName; }
19480
+ });
19481
+ Object.defineProperty(exports, "messagePreview", {
19482
+ enumerable: true,
19483
+ get: function () { return chunkXREIZ56K_js.messagePreview; }
19484
+ });
19485
+ Object.defineProperty(exports, "splitGenUIContent", {
19486
+ enumerable: true,
19487
+ get: function () { return chunkXREIZ56K_js.splitGenUIContent; }
17244
19488
  });
17245
19489
  exports.AccommodationCard = AccommodationCard;
17246
19490
  exports.AccountContent = AccountContent;
@@ -17276,6 +19520,7 @@ exports.BundleProductCard = BundleProductCard;
17276
19520
  exports.BundleProductLayout = BundleProductLayout;
17277
19521
  exports.BundleSelector = BundleSelector;
17278
19522
  exports.Button = Button;
19523
+ exports.CIMPLIFY_GENUI_REGISTRY = CIMPLIFY_GENUI_REGISTRY;
17279
19524
  exports.CardImage = CardImage;
17280
19525
  exports.CardShell = CardShell;
17281
19526
  exports.CardVariant = CardVariant;
@@ -17289,6 +19534,7 @@ exports.CataloguePage = CataloguePage;
17289
19534
  exports.CatalogueTemplate = CatalogueTemplate;
17290
19535
  exports.CategoryFilter = CategoryFilter;
17291
19536
  exports.CategoryGrid = CategoryGrid;
19537
+ exports.ChatMarkdown = ChatMarkdown;
17292
19538
  exports.ChatWidget = ChatWidget;
17293
19539
  exports.CheckIcon = CheckIcon;
17294
19540
  exports.CheckoutPage = CheckoutPage;
@@ -17334,6 +19580,7 @@ exports.FeaturedCollectionLayout = FeaturedCollectionLayout;
17334
19580
  exports.FilterTabs = FilterTabs;
17335
19581
  exports.FoodProductCard = FoodProductCard;
17336
19582
  exports.FoodProductLayout = FoodProductLayout;
19583
+ exports.GenUIView = GenUIView;
17337
19584
  exports.HappeningCard = HappeningCard;
17338
19585
  exports.IdentityIcon = IdentityIcon;
17339
19586
  exports.IdentityOfframp = IdentityOfframp;
@@ -17419,9 +19666,17 @@ exports.WelcomeCard = WelcomeCard;
17419
19666
  exports.WholesaleProductCard = WholesaleProductCard;
17420
19667
  exports.WholesaleProductLayout = WholesaleProductLayout;
17421
19668
  exports.WishlistButton = WishlistButton;
19669
+ exports.clearOrdersCache = clearOrdersCache;
17422
19670
  exports.cn = cn;
17423
19671
  exports.defaultBoundaryKind = defaultBoundaryKind;
19672
+ exports.genUICatalog = genUICatalog;
19673
+ exports.genUIFingerprint = genUIFingerprint;
19674
+ exports.genUIManifest = genUIManifest;
19675
+ exports.genUIManifestJson = genUIManifestJson;
17424
19676
  exports.getBoundaryLabels = getBoundaryLabels;
19677
+ exports.isTerminalOrderStatus = isTerminalOrderStatus;
19678
+ exports.parseGenUIProgram = parse;
19679
+ exports.partitionMessages = partitionMessages;
17425
19680
  exports.prefetchProduct = prefetchProduct;
17426
19681
  exports.prefetchProducts = prefetchProducts;
17427
19682
  exports.resolveBoundaryKind = resolveBoundaryKind;
@@ -17455,6 +19710,7 @@ exports.useDeliveryOptions = useDeliveryOptions;
17455
19710
  exports.useElements = useElements;
17456
19711
  exports.useElementsReady = useElementsReady;
17457
19712
  exports.useFxRate = useFxRate;
19713
+ exports.useGenUIProgram = useGenUIProgram;
17458
19714
  exports.useLocations = useLocations;
17459
19715
  exports.useOptionalCimplify = useOptionalCimplify;
17460
19716
  exports.useOrder = useOrder;