@arbidocs/react 0.5.23 → 0.5.25

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 (63) hide show
  1. package/dist/artifacts/index.cjs +9 -9
  2. package/dist/artifacts/index.js +3 -3
  3. package/dist/calls/livekit/index.cjs +48 -48
  4. package/dist/calls/livekit/index.js +3 -3
  5. package/dist/{chunk-4UDIA47U.cjs → chunk-2ERRXEOB.cjs} +15 -15
  6. package/dist/{chunk-4UDIA47U.cjs.map → chunk-2ERRXEOB.cjs.map} +1 -1
  7. package/dist/{chunk-LYGJVSNM.js → chunk-CIWI5UFT.js} +3 -3
  8. package/dist/{chunk-LYGJVSNM.js.map → chunk-CIWI5UFT.js.map} +1 -1
  9. package/dist/{chunk-KRAUMKBG.js → chunk-CMNZI4WQ.js} +5 -3
  10. package/dist/chunk-CMNZI4WQ.js.map +1 -0
  11. package/dist/{chunk-3WIBD44F.js → chunk-I4JYI6GY.js} +7 -4
  12. package/dist/chunk-I4JYI6GY.js.map +1 -0
  13. package/dist/{chunk-5YWIUUUT.cjs → chunk-KC474WVG.cjs} +12 -2
  14. package/dist/chunk-KC474WVG.cjs.map +1 -0
  15. package/dist/{chunk-2HVCNYFH.js → chunk-KOLCL4KV.js} +3 -3
  16. package/dist/{chunk-2HVCNYFH.js.map → chunk-KOLCL4KV.js.map} +1 -1
  17. package/dist/{chunk-I4WI3MNH.js → chunk-L2U4GOKU.js} +4 -4
  18. package/dist/{chunk-I4WI3MNH.js.map → chunk-L2U4GOKU.js.map} +1 -1
  19. package/dist/{chunk-KGCGA452.js → chunk-MB34NKBZ.js} +2 -2
  20. package/dist/{chunk-KGCGA452.js.map → chunk-MB34NKBZ.js.map} +1 -1
  21. package/dist/{chunk-FLAZSNC5.cjs → chunk-NV5G5RR5.cjs} +31 -31
  22. package/dist/{chunk-FLAZSNC5.cjs.map → chunk-NV5G5RR5.cjs.map} +1 -1
  23. package/dist/{chunk-CZP7FF3E.cjs → chunk-ONGNP4JM.cjs} +4 -4
  24. package/dist/{chunk-CZP7FF3E.cjs.map → chunk-ONGNP4JM.cjs.map} +1 -1
  25. package/dist/{chunk-TUKW4MCI.cjs → chunk-OQWNWK74.cjs} +20 -20
  26. package/dist/{chunk-TUKW4MCI.cjs.map → chunk-OQWNWK74.cjs.map} +1 -1
  27. package/dist/{chunk-YBIW7T66.cjs → chunk-TUPSNW3B.cjs} +7 -5
  28. package/dist/chunk-TUPSNW3B.cjs.map +1 -0
  29. package/dist/{chunk-MQ7LZWGP.js → chunk-VHGJG32Q.js} +3 -3
  30. package/dist/{chunk-MQ7LZWGP.js.map → chunk-VHGJG32Q.js.map} +1 -1
  31. package/dist/{chunk-NA3FJX37.js → chunk-Y3MTRA7D.js} +11 -3
  32. package/dist/chunk-Y3MTRA7D.js.map +1 -0
  33. package/dist/{chunk-QQ7SCJRY.cjs → chunk-YIUUTRMQ.cjs} +2 -2
  34. package/dist/{chunk-QQ7SCJRY.cjs.map → chunk-YIUUTRMQ.cjs.map} +1 -1
  35. package/dist/{chunk-7NHOKV7N.cjs → chunk-YMAZYYD5.cjs} +7 -3
  36. package/dist/chunk-YMAZYYD5.cjs.map +1 -0
  37. package/dist/document-tools/index.cjs +43 -43
  38. package/dist/document-tools/index.js +6 -6
  39. package/dist/index.cjs +959 -951
  40. package/dist/{index.d-BO71E6NO.d.cts → index.d-BLw5AN0H.d.cts} +2 -2
  41. package/dist/{index.d-BO71E6NO.d.ts → index.d-BLw5AN0H.d.ts} +2 -2
  42. package/dist/{index.d-DscWCwr2.d.cts → index.d-DklHLjcu.d.cts} +32 -3
  43. package/dist/{index.d-DscWCwr2.d.ts → index.d-DklHLjcu.d.ts} +32 -3
  44. package/dist/index.d.cts +10 -5
  45. package/dist/index.d.ts +10 -5
  46. package/dist/index.js +17 -17
  47. package/dist/shell/index.cjs +34 -34
  48. package/dist/shell/index.d.cts +1 -1
  49. package/dist/shell/index.d.ts +1 -1
  50. package/dist/shell/index.js +3 -3
  51. package/dist/ui/index.cjs +167 -159
  52. package/dist/ui/index.d.cts +1 -1
  53. package/dist/ui/index.d.ts +1 -1
  54. package/dist/ui/index.js +3 -3
  55. package/dist/viewers/index.cjs +2 -2
  56. package/dist/viewers/index.js +1 -1
  57. package/package.json +3 -3
  58. package/dist/chunk-3WIBD44F.js.map +0 -1
  59. package/dist/chunk-5YWIUUUT.cjs.map +0 -1
  60. package/dist/chunk-7NHOKV7N.cjs.map +0 -1
  61. package/dist/chunk-KRAUMKBG.js.map +0 -1
  62. package/dist/chunk-NA3FJX37.js.map +0 -1
  63. package/dist/chunk-YBIW7T66.cjs.map +0 -1
@@ -3,7 +3,7 @@
3
3
  var chunkVAMPYLQ4_cjs = require('./chunk-VAMPYLQ4.cjs');
4
4
  var chunkN73IMVFF_cjs = require('./chunk-N73IMVFF.cjs');
5
5
  var chunkZWFMFOGP_cjs = require('./chunk-ZWFMFOGP.cjs');
6
- var chunk5YWIUUUT_cjs = require('./chunk-5YWIUUUT.cjs');
6
+ var chunkKC474WVG_cjs = require('./chunk-KC474WVG.cjs');
7
7
  var chunkHJDR5HEO_cjs = require('./chunk-HJDR5HEO.cjs');
8
8
  var chunkS6A6FSG7_cjs = require('./chunk-S6A6FSG7.cjs');
9
9
  var chunkRCKA7BEF_cjs = require('./chunk-RCKA7BEF.cjs');
@@ -198,7 +198,7 @@ function NotificationBell({
198
198
  children: "Toasts are muted \u2014 everything still lands here."
199
199
  }
200
200
  ),
201
- visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3.5 py-10 text-center text-sm text-muted-foreground", children: emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(chunk5YWIUUUT_cjs.ScrollArea, { className: "max-h-[380px]", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { "data-testid": `${testId}-list`, children: visible.map((n) => {
201
+ visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3.5 py-10 text-center text-sm text-muted-foreground", children: emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(chunkKC474WVG_cjs.ScrollArea, { className: "max-h-[380px]", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { "data-testid": `${testId}-list`, children: visible.map((n) => {
202
202
  const Glyph = GLYPH[n.variant];
203
203
  return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
204
204
  "button",
@@ -225,7 +225,7 @@ function NotificationBell({
225
225
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
226
226
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium leading-snug text-foreground", children: n.title }),
227
227
  n.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-relaxed text-muted-foreground", children: n.description }),
228
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground/80", children: chunk5YWIUUUT_cjs.formatRelativeTime(new Date(n.ts).toISOString()) })
228
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground/80", children: chunkKC474WVG_cjs.formatRelativeTime(new Date(n.ts).toISOString()) })
229
229
  ] }),
230
230
  !n.read && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1.5 size-2 shrink-0 rounded-full bg-primary" })
231
231
  ]
@@ -258,6 +258,8 @@ function ArbiHost({
258
258
  const merged = chunkN73IMVFF_cjs.mergeHostConfig(parent, config);
259
259
  return merged[chunkN73IMVFF_cjs.OWN_SESSION_SLOT] ? merged : { ...merged, [chunkN73IMVFF_cjs.OWN_SESSION_SLOT]: ownSession };
260
260
  }, [parent, config, ownSession]);
261
+ const { vocabulary } = config;
262
+ if (vocabulary) chunkKC474WVG_cjs.configureEntityVocabulary(vocabulary);
261
263
  const Connection = config.connection?.Provider;
262
264
  return /* @__PURE__ */ jsxRuntime.jsx(chunkRCKA7BEF_cjs.ArbiHostContext.Provider, { value, children: Connection ? /* @__PURE__ */ jsxRuntime.jsx(Connection, { children }) : children });
263
265
  }
@@ -538,5 +540,5 @@ exports.toMessageMentions = toMessageMentions;
538
540
  exports.useOpenDocumentId = useOpenDocumentId;
539
541
  exports.useRegisterOpenDocument = useRegisterOpenDocument;
540
542
  exports.useTurnDocumentId = useTurnDocumentId;
541
- //# sourceMappingURL=chunk-YBIW7T66.cjs.map
542
- //# sourceMappingURL=chunk-YBIW7T66.cjs.map
543
+ //# sourceMappingURL=chunk-TUPSNW3B.cjs.map
544
+ //# sourceMappingURL=chunk-TUPSNW3B.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/search/session.ts","../src/notifications/Toaster.tsx","../src/notifications/NotificationBell.tsx","../src/host/ArbiHost.tsx","../src/chat/mentions.ts","../src/chat/open-document.ts","../src/chat/thread-document.ts"],"names":["createStore","storage","jsx","Sonner","CheckCircle2","XCircle","AlertTriangle","Info","useState","useNotify","selectUnread","DEFAULT_NOTIFY_TONE","jsxs","DropdownMenu","DropdownMenuTrigger","Bell","DropdownMenuContent","CheckCheck","cn","BellOff","DropdownMenuItem","X","ScrollArea","formatRelativeTime","useContext","ArbiHostContext","useMemo","mergeHostConfig","OWN_SESSION_SLOT","useRef","useEffect","useSyncExternalStore","parseVersionRef"],"mappings":";;;;;;;;;;;;;;;AA8BA,IAAM,KAAA,GAAyD;AAAA,EAC7D,KAAA,EAAO,EAAA;AAAA,EACP,SAAS,EAAC;AAAA,EACV,QAAA,EAAU,KAAA;AAAA,EACV,MAAA,EAAQ,MAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,OAAA,EAAS;AACX,CAAA;AAEO,SAAS,mBAAA,GAAqC;AACnD,EAAA,OAAOA,mBAAA,CAAgC,OAAO,EAAE,GAAG,OAAO,WAAA,EAAa,IAAA,EAAM,GAAA,EAAK,CAAA,EAAE,CAAE,CAAA;AACxF;AAGO,IAAM,sBAAqC,mBAAA;AAG3C,SAAS,kBAAA,CACd,WAAA,EACA,OAAA,GAAyB,mBAAA,EACnB;AACN,EAAA,OAAA,CAAQ,QAAA,CAAS,CAAC,CAAA,MAAO;AAAA,IACvB,GAAG,KAAA;AAAA,IACH,WAAA,EAAa,WAAA,KAAgB,MAAA,GAAY,CAAA,CAAE,WAAA,GAAc,WAAA;AAAA,IACzD,GAAA,EAAK,EAAE,GAAA,GAAM;AAAA,GACf,CAAE,CAAA;AACJ;AAMO,SAAS,aAAA,CACd,KAAA,EACA,WAAA,EACA,OAAA,GAAyB,mBAAA,EACnB;AACN,EAAA,kBAAA,CAAmB,aAAa,OAAO,CAAA;AACvC,EAAA,OAAA,CAAQ,QAAA,CAAS,EAAE,KAAA,EAAO,OAAA,EAAS,OAAO,CAAA;AAC5C;AAGO,SAAS,iBAAA,CAAkB,UAAyB,mBAAA,EAAoC;AAC7F,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,OAAA,CAAQ,QAAA,EAAS;AACrC,EAAA,IAAI,YAAY,IAAA,EAAM,OAAA,CAAQ,SAAS,EAAE,OAAA,EAAS,MAAM,CAAA;AACxD,EAAA,OAAO,OAAA;AACT;AAWO,SAAS,qBACd,GAAA,EACAC,QAAAA,GAA4D,UAAA,CAAW,YAAA,EACvE,UAAyB,mBAAA,EACb;AACZ,EAAA,IAAI,CAACA,QAAAA,EAAS,OAAO,MAAM;AAAA,EAAC,CAAA;AAC5B,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAMA,SAAQ,OAAA,CAAQ,GAAG,KAAK,MAAM,CAAA;AACvD,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,CAAM,KAAA,KAAU,YAAY,CAAC,OAAA,CAAQ,UAAS,CAAE,KAAA;AAClE,MAAA,OAAA,CAAQ,QAAA,CAAS,EAAE,KAAA,EAAO,KAAA,CAAM,OAAO,WAAA,EAAa,KAAA,CAAM,WAAA,IAAe,IAAA,EAAM,CAAA;AAAA,EACnF,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,OAAO,QAAQ,SAAA,CAAU,CAAC,EAAE,KAAA,EAAO,aAAY,KAAM;AACnD,IAAA,MAAM,OAAO,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,aAAa,CAAA;AAClD,IAAA,IAAI,SAAS,IAAA,EAAM;AACnB,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,IAAI;AACF,MAAAA,QAAAA,CAAQ,OAAA,CAAQ,GAAA,EAAK,IAAI,CAAA;AAAA,IAC3B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAC,CAAA;AACH;AClGA,IAAM,qBAAA,GAAsD;AAAA,EAC1D,UAAA,EAAY;AAAA,IACV,KAAA,EACE,qLAAA;AAAA,IACF,WAAA,EAAa,sCAAA;AAAA,IACb,YAAA,EAAc,kEAAA;AAAA,IACd,YAAA,EAAc;AAAA;AAElB,CAAA;AAEO,SAAS,OAAA,CAAQ,EAAE,YAAA,EAAc,GAAG,OAAM,EAAiB;AAChE,EAAA,uBACEC,cAAA;AAAA,IAACC,cAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,eAAA;AAAA,MACV,cAAc,YAAA,IAAgB,qBAAA;AAAA,MAC7B,GAAG;AAAA;AAAA,GACN;AAEJ;ACMA,IAAM,KAAA,GAA4C;AAAA,EAChD,OAAA,EAASC,wBAAA;AAAA,EACT,KAAA,EAAOC,mBAAA;AAAA,EACP,OAAA,EAASC,yBAAA;AAAA,EACT,IAAA,EAAMC;AACR,CAAA;AAGA,IAAM,UAAA,GAAa,GAAA;AAyCZ,SAAS,gBAAA,CAAiB;AAAA,EAC/B,aAAA;AAAA,EACA,UAAA;AAAA,EACA,oBAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA,GAAiB,KAAA;AAAA,EACjB,cAAA;AAAA,EACA,SAAA,GAAY,uBAAA;AAAA,EACZ,SAAA;AAAA,EACA,YAAA,GAAe,UAAA;AAAA,EACf,MAAA,GAAS,eAAA;AAAA,EACT,IAAA,GAAO,QAAA;AAAA,EACP,KAAA,GAAQ;AACV,CAAA,EAA0B;AACxB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIC,eAAS,KAAK,CAAA;AACtC,EAAA,MAAM,aAAA,GAAgBC,2BAAA,CAAU,CAAC,CAAA,KAAM,EAAE,aAAa,CAAA;AACtD,EAAA,MAAM,MAAA,GAASA,4BAAUC,8BAAY,CAAA;AACrC,EAAA,MAAM,WAAA,GAAcD,2BAAA,CAAU,CAAC,CAAA,KAAM,EAAE,WAAW,CAAA;AAClD,EAAA,MAAM,QAAA,GAAWA,2BAAA,CAAU,CAAC,CAAA,KAAM,EAAE,QAAQ,CAAA;AAC5C,EAAA,MAAM,KAAA,GAAQA,2BAAA,CAAU,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AACtC,EAAA,MAAM,QAAA,GAAWA,2BAAA,CAAU,CAAC,CAAA,KAAM,EAAE,QAAQ,CAAA;AAC5C,EAAA,MAAM,OAAO,CAAC,CAAA,KAAqB,iBAAiB,CAAC,CAAA,IAAKE,sCAAoB,CAAC,CAAA;AAM/E,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,OAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA;AAE3E,EAAA,uBACEC,eAAA,CAACC,8BAAA,EAAA,EAAa,IAAA,EAAY,YAAA,EAAc,OAAA,EACtC,QAAA,EAAA;AAAA,oBAAAX,cAAAA,CAACY,qCAAA,EAAA,EAAoB,OAAA,EAAO,IAAA,EACzB,0BACC,aAAA,CAAc;AAAA,MACZ,MAAA;AAAA,MACA,WAAW,CAAA,aAAA,EAAgB,MAAA,GAAS,CAAA,EAAA,EAAK,MAAM,YAAY,EAAE,CAAA,CAAA;AAAA,MAC7D;AAAA,KACD,CAAA,mBAEDF,eAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,kKAAA;AAAA,QACV,aAAA,EAAa,MAAA;AAAA,QACb,cAAY,CAAA,aAAA,EAAgB,MAAA,GAAS,CAAA,EAAA,EAAK,MAAM,YAAY,EAAE,CAAA,CAAA;AAAA,QAC9D,KAAA,EAAM,eAAA;AAAA,QAEN,QAAA,EAAA;AAAA,0BAAAV,cAAAA,CAACa,gBAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,CAAA;AAAA,UACxB,MAAA,GAAS,qBACRb,cAAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,4JAAA;AAAA,cACV,aAAA,EAAa,GAAG,MAAM,CAAA,MAAA,CAAA;AAAA,cAErB,QAAA,EAAA,MAAA,GAAS,IAAI,IAAA,GAAO;AAAA;AAAA;AACvB;AAAA;AAAA,KAEJ,EAEJ,CAAA;AAAA,oBACAU,eAAA;AAAA,MAACI,qCAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,IAAA;AAAA,QACA,UAAA,EAAY,CAAA;AAAA,QACZ,gBAAA,EAAkB,EAAA;AAAA,QAClB,SAAA,EAAU,gDAAA;AAAA,QACV,aAAA,EAAa,GAAG,MAAM,CAAA,MAAA,CAAA;AAAA,QACtB,qBAAA,EAAoB,EAAA;AAAA,QAEpB,QAAA,EAAA;AAAA,0BAAAJ,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,kGAAA,EACb,QAAA,EAAA;AAAA,4BAAAV,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uCAAA,EAAwC,QAAA,EAAA,eAAA,EAAa,CAAA;AAAA,4BAClEU,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8CAAA,EACZ,QAAA,EAAA;AAAA,cAAA,MAAA,GAAS,CAAA,oBACRA,eAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,SAAS,MAAM;AACb,oBAAA,WAAA,EAAY;AACZ,oBAAA,aAAA,IAAgB;AAAA,kBAClB,CAAA;AAAA,kBACA,SAAA,EAAU,yIAAA;AAAA,kBACV,aAAA,EAAa,GAAG,MAAM,CAAA,SAAA,CAAA;AAAA,kBAEtB,QAAA,EAAA;AAAA,oCAAAV,cAAAA,CAACe,sBAAA,EAAA,EAAW,SAAA,EAAU,UAAA,EAAW,CAAA;AAAA,oBAAE;AAAA;AAAA;AAAA,eACrC;AAAA,cAED,kCACCf,cAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,OAAA,EAAS,MAAM,QAAA,CAAS,CAAC,KAAK,CAAA;AAAA,kBAC9B,cAAA,EAAc,KAAA;AAAA,kBACd,KAAA,EAAO,QAAQ,sBAAA,GAAyB,oBAAA;AAAA,kBACxC,YAAA,EAAY,QAAQ,sBAAA,GAAyB,oBAAA;AAAA,kBAC7C,SAAA,EAAWgB,oBAAA;AAAA,oBACT,6GAAA;AAAA,oBACA,QAAQ,iBAAA,GAAoB;AAAA,mBAC9B;AAAA,kBACA,aAAA,EAAa,GAAG,MAAM,CAAA,KAAA,CAAA;AAAA,kBAEtB,QAAA,kBAAAhB,cAAAA,CAACiB,mBAAA,EAAA,EAAQ,SAAA,EAAU,UAAA,EAAW;AAAA;AAAA,eAChC;AAAA,8BAQFjB,cAAAA;AAAA,gBAACkB,kCAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,6KAAA;AAAA,kBACV,YAAA,EAAW,qBAAA;AAAA,kBACX,aAAA,EAAa,GAAG,MAAM,CAAA,MAAA,CAAA;AAAA,kBAEtB,QAAA,kBAAAlB,cAAAA,CAACmB,aAAA,EAAA,EAAE,SAAA,EAAU,UAAA,EAAW;AAAA;AAAA;AAC1B,aAAA,EACF;AAAA,WAAA,EACF,CAAA;AAAA,UACC,yBACCnB,cAAAA;AAAA,YAAC,GAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,uFAAA;AAAA,cACV,aAAA,EAAa,GAAG,MAAM,CAAA,WAAA,CAAA;AAAA,cACvB,QAAA,EAAA;AAAA;AAAA,WAED;AAAA,UAGD,OAAA,CAAQ,MAAA,KAAW,CAAA,mBAClBA,cAAAA,CAAC,SAAI,SAAA,EAAU,wDAAA,EAA0D,QAAA,EAAA,SAAA,EAAU,CAAA,mBAEnFA,cAAAA,CAACoB,gCAAW,SAAA,EAAU,eAAA,EACpB,QAAA,kBAAApB,cAAAA,CAAC,IAAA,EAAA,EAAG,aAAA,EAAa,CAAA,EAAG,MAAM,CAAA,KAAA,CAAA,EACvB,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM;AAClB,YAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,CAAA,CAAE,OAAO,CAAA;AAC7B,YAAA,uBACEA,eAAC,IAAA,EAAA,EACC,QAAA,kBAAAU,eAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,SAAS,MAAM;AACb,kBAAA,QAAA,CAAS,EAAE,EAAE,CAAA;AACb,kBAAA,IAAI,CAAC,CAAA,CAAE,IAAA,EAAM,UAAA,GAAa,EAAE,EAAE,CAAA;AAC9B,kBAAA,OAAA,CAAQ,KAAK,CAAA;AACb,kBAAA,IAAI,oBAAA,EAAsB;AACxB,oBAAA,oBAAA,CAAqB,CAAC,CAAA;AACtB,oBAAA;AAAA,kBACF;AAEA,kBAAA,IAAI,CAAA,CAAE,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,uBAAA,IAClB,CAAA,CAAE,IAAA,EAAM,UAAA,GAAa,CAAA,CAAE,IAAI,CAAA;AAAA,gBACtC,CAAA;AAAA,gBACA,SAAA,EAAWM,oBAAA;AAAA,kBACT,iHAAA;AAAA,kBACA,CAAC,EAAE,IAAA,IAAQ;AAAA,iBACb;AAAA,gBACA,aAAA,EAAa,GAAG,MAAM,CAAA,KAAA,CAAA;AAAA,gBACtB,wBAAsB,CAAA,CAAE,EAAA;AAAA,gBAExB,QAAA,EAAA;AAAA,kCAAAhB,cAAAA,CAAC,SAAM,SAAA,EAAWgB,oBAAA,CAAG,0BAA0B,IAAA,CAAK,CAAA,CAAE,OAAO,CAAC,CAAA,EAAG,CAAA;AAAA,kCACjEN,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,oCAAAV,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,kDAAA,EACV,YAAE,KAAA,EACL,CAAA;AAAA,oBACC,CAAA,CAAE,+BACDA,cAAAA,CAAC,OAAE,SAAA,EAAU,mEAAA,EACV,YAAE,WAAA,EACL,CAAA;AAAA,oCAEFA,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uCAAA,EACV,QAAA,EAAAqB,oCAAA,CAAmB,IAAI,IAAA,CAAK,CAAA,CAAE,EAAE,CAAA,CAAE,WAAA,EAAa,CAAA,EAClD;AAAA,mBAAA,EACF,CAAA;AAAA,kBACC,CAAC,CAAA,CAAE,IAAA,oBACFrB,cAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,gDAAA,EAAiD;AAAA;AAAA;AAAA,aAErE,EAAA,EAtCO,EAAE,EAuCX,CAAA;AAAA,UAEJ,CAAC,GACH,CAAA,EACF,CAAA;AAAA,UAED,SAAA;AAAA;AAAA,0BAGCA,cAAAA;AAAA,YAACkB,kCAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAS,SAAA;AAAA,cACT,SAAA,EAAU,8IAAA;AAAA,cACV,aAAA,EAAa,GAAG,MAAM,CAAA,SAAA,CAAA;AAAA,cAErB,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA;AAEJ,GAAA,EACF,CAAA;AAEJ;AC9OO,SAAS,QAAA,CAAgC;AAAA,EAC9C,MAAA;AAAA,EACA;AACF,CAAA,EAA8C;AAC5C,EAAA,MAAM,MAAA,GAASI,iBAAWC,iCAAe,CAAA;AAEzC,EAAA,MAAM,CAAC,UAAU,CAAA,GAAIjB,cAAAA,CAAS,OAAO,EAAE,OAAA,EAAS,MAAgB,CAAE,CAAA;AAClE,EAAA,MAAM,KAAA,GAAQkB,cAAQ,MAAM;AAC1B,IAAA,MAAM,MAAA,GAASC,iCAAA,CAAgB,MAAA,EAAQ,MAAM,CAAA;AAC7C,IAAA,OAAO,MAAA,CAAOC,kCAAgB,CAAA,GAAI,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,CAACA,kCAAgB,GAAG,UAAA,EAAW;AAAA,EACzF,CAAA,EAAG,CAAC,MAAA,EAAQ,MAAA,EAAQ,UAAU,CAAC,CAAA;AAE/B,EAAA,MAAM,EAAE,YAAW,GAAI,MAAA;AACvB,EAAA,IAAI,UAAA,8CAAsC,UAAU,CAAA;AACpD,EAAA,MAAM,UAAA,GAAc,OAA+C,UAAA,EAAY,QAAA;AAC/E,EAAA,uBACE1B,cAAAA,CAACuB,iCAAA,CAAgB,QAAA,EAAhB,EAAyB,KAAA,EACvB,QAAA,EAAA,UAAA,mBAAavB,cAAAA,CAAC,UAAA,EAAA,EAAY,QAAA,EAAS,CAAA,GAAgB,QAAA,EACtD,CAAA;AAEJ;;;ACvBA,IAAM,gBAAA,GAAmB,EAAA;AAMlB,SAAS,gBAAA,CACd,MACA,KAAA,EACyC;AACzC,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAClC,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,WAAA,CAAY,GAAG,CAAA;AACjC,EAAA,IAAI,EAAA,GAAK,GAAG,OAAO,IAAA;AACnB,EAAA,IAAI,EAAA,GAAK,CAAA,IAAK,CAAC,IAAA,CAAK,IAAA,CAAK,OAAO,EAAA,GAAK,CAAC,CAAC,CAAA,EAAG,OAAO,IAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,EAAA,GAAK,CAAC,CAAA;AACjC,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,gBAAA,IAAoB,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,IAAK,KAAA,CAAM,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,IAAA;AAC7F,EAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,KAAA,EAAM;AAC5B;AAGO,SAAS,uBAAA,CACd,YACA,KAAA,EACoB;AACpB,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AACnC,EAAA,IAAI,CAAC,CAAA,EAAG,OAAO,UAAA,CAAW,KAAA,EAAM;AAChC,EAAA,MAAM,SAAwD,EAAC;AAC/D,EAAA,KAAA,MAAW,KAAK,UAAA,EAAY;AAC1B,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,CAAM,WAAA,EAAY;AAClC,IAAA,IAAI,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA,EAAG,MAAA,CAAO,KAAK,EAAE,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,CAAA;AAAA,SAAA,IAC3C,MAAM,KAAA,CAAM,KAAK,EAAE,IAAA,CAAK,CAAC,SAAS,IAAA,CAAK,UAAA,CAAW,CAAC,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,EAAG,KAAA,EAAO,GAAG,CAAA;AAAA,SAAA,IAClF,CAAA,CAAE,WAAA,EAAa,WAAA,EAAY,CAAE,UAAA,CAAW,CAAC,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,EAAG,KAAA,EAAO,GAAG,CAAA;AAAA,EAClF;AACA,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,CAAC,CAAA;AAChE;AAGO,SAAS,aAAA,CACd,IAAA,EACA,KAAA,EACA,KAAA,EACA,KAAA,EACiC;AACjC,EAAA,MAAM,QAAA,GAAW,IAAI,KAAK,CAAA,CAAA,CAAA;AAC1B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,KAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAAA,IACxD,KAAA,EAAO,QAAQ,QAAA,CAAS;AAAA,GAC1B;AACF;AAGA,SAAS,WAAA,CAAY,MAAc,KAAA,EAAwC;AACzE,EAAA,MAAM,MAAA,GAAS,IAAI,KAAK,CAAA,CAAA;AACxB,EAAA,MAAM,SAAkC,EAAC;AACzC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,WAAS;AACP,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,IAAI,CAAA;AACnC,IAAA,IAAI,IAAI,CAAA,EAAG;AACX,IAAA,MAAM,GAAA,GAAM,IAAI,MAAA,CAAO,MAAA;AACvB,IAAA,MAAM,WAAA,GAAc,MAAM,CAAA,IAAK,UAAA,CAAW,KAAK,IAAA,CAAK,CAAA,GAAI,CAAC,CAAC,CAAA;AAC1D,IAAA,MAAM,SAAA,GAAY,QAAQ,IAAA,CAAK,MAAA,IAAU,CAAC,gBAAA,CAAiB,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA;AACzE,IAAA,IAAI,eAAe,SAAA,EAAW,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG,GAAG,CAAC,CAAA;AAClD,IAAA,IAAA,GAAO,GAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;AAMO,SAAS,eAAA,CACd,MACA,UAAA,EACoB;AACpB,EAAA,MAAM,QAAiC,EAAC;AACxC,EAAA,MAAM,QAAoD,EAAC;AAC3D,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,UAAU,EAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,KAAA,CAAM,MAAA,GAAS,CAAA,CAAE,MAAM,MAAM,CAAA;AAC/E,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,IAAI,CAAC,EAAE,KAAA,EAAO;AACd,IAAA,KAAA,MAAW,CAAC,MAAM,EAAE,CAAA,IAAK,YAAY,IAAA,EAAM,CAAA,CAAE,KAAK,CAAA,EAAG;AACnD,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,IAAA,GAAO,CAAA,IAAK,EAAA,GAAK,CAAC,CAAA,EAAG;AAChD,MAAA,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,EAAM,EAAE,CAAC,CAAA;AACrB,MAAA,IAAI,CAAC,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,CAAA,CAAE,EAAA,KAAO,CAAA,CAAE,EAAE,GAAG,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,EAAG,EAAA,EAAI,MAAM,CAAA;AAAA,IACrE;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,CAAC,CAAA;AACzD;AAGO,SAAS,kBAAkB,SAAA,EAAiE;AACjG,EAAA,OAAO,SAAA,CAAU,GAAA;AAAA,IAAI,CAAC,CAAA,KACpB,CAAA,CAAE,IAAA,KAAS,cAAc,EAAE,IAAA,EAAM,WAAA,EAAY,GAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,WAAA,EAAa,EAAE,EAAA;AAAG,GACrF;AACF;AAGO,IAAM,mBAAA,GAAsB;AAGnC,SAAS,eAAe,KAAA,EAAuB;AAC7C,EAAA,OAAO,MAAM,OAAA,CAAQ,UAAA,EAAY,CAAC,EAAA,KAAO,CAAA,EAAA,EAAK,EAAE,CAAA,CAAE,CAAA;AACpD;AAQO,SAAS,YAAA,CACd,OAAA,EACA,QAAA,EACA,eAAA,GAAyC,EAAC,EAClC;AACR,EAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,WAAW,CAAA,IAAK,CAAC,SAAS,OAAO,OAAA;AAC3D,EAAA,MAAM,UAAgD,EAAC;AACvD,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,MAAM,EAAA,GAAK,CAAA,CAAE,IAAA,KAAS,WAAA,GAAc,cAAc,CAAA,CAAE,WAAA;AACpD,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,MAAM,MAAA,GAAS,CAAA,CAAE,IAAA,KAAS,WAAA,GAAc,CAAC,CAAA,CAAE,KAAA,IAAS,EAAA,EAAI,GAAG,eAAe,CAAA,GAAI,CAAC,CAAA,CAAE,SAAS,EAAE,CAAA;AAC5F,IAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,IAAI,KAAA,UAAe,IAAA,CAAK,EAAE,KAAA,EAAO,EAAA,EAAI,CAAA;AAAA,EACnE;AACA,EAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,KAAA,CAAM,MAAA,GAAS,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA;AACtD,EAAA,MAAM,eAAkE,EAAC;AACzE,EAAA,KAAA,MAAW,EAAE,KAAA,EAAO,EAAA,EAAG,IAAK,OAAA,EAAS;AACnC,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,EAAE,KAAK,WAAA,CAAY,OAAA,EAAS,KAAK,CAAA,EAAG;AACpD,MAAA,IAAI,YAAA,CAAa,IAAA,CAAK,CAAC,CAAA,KAAM,IAAA,GAAO,EAAE,EAAA,IAAM,EAAA,GAAK,CAAA,CAAE,IAAI,CAAA,EAAG;AAC1D,MAAA,YAAA,CAAa,IAAA,CAAK;AAAA,QAChB,IAAA;AAAA,QACA,EAAA;AAAA,QACA,IAAA,EAAM,KAAK,cAAA,CAAe,KAAK,CAAC,CAAA,EAAA,EAAK,mBAAmB,GAAG,EAAE,CAAA,CAAA;AAAA,OAC9D,CAAA;AAAA,IACH;AAAA,EACF;AACA,EAAA,YAAA,CAAa,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,IAAA,GAAO,EAAE,IAAI,CAAA;AAC3C,EAAA,IAAI,GAAA,GAAM,OAAA;AACV,EAAA,KAAA,MAAW,CAAA,IAAK,YAAA,EAAc,GAAA,GAAM,GAAA,CAAI,MAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,GAAI,CAAA,CAAE,IAAA,GAAO,GAAA,CAAI,KAAA,CAAM,EAAE,EAAE,CAAA;AAClF,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,gBACd,IAAA,EAC0C;AAC1C,EAAA,IAAI,CAAC,IAAA,EAAM,UAAA,CAAW,mBAAmB,GAAG,OAAO,IAAA;AACnD,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,mBAAA,CAAoB,MAAM,CAAA;AAChD,EAAA,IAAI,CAAC,IAAI,OAAO,IAAA;AAChB,EAAA,OAAO,EAAE,IAAA,EAAM,EAAA,KAAO,WAAA,GAAc,WAAA,GAAc,QAAQ,EAAA,EAAG;AAC/D;AAGO,SAAS,cAAA,CAAe,KAAA,EAAe,cAAA,GAAiB,MAAA,EAAiB;AAC9E,EAAA,MAAM,IAAA,GAAO,MAAM,IAAA,EAAK;AACxB,EAAA,OAAO,CAAC,CAAC,IAAA,IAAQ,IAAA,CAAK,aAAY,KAAM,CAAA,CAAA,EAAI,cAAc,CAAA,CAAA,CAAG,WAAA,EAAY;AAC3E;ACnIO,SAAS,YAAY,GAAA,EAAmD;AAC7E,EAAA,OAAO,CAAC,CAAC,GAAA,KAAQ,GAAA,CAAI,OAAA,KAAY,UAAA,IAAc,CAAC,CAAC,GAAA,CAAI,SAAA,EAAW,WAAA,EAAY,CAAE,SAAS,OAAO,CAAA,CAAA;AAChG;AAMO,SAAS,mBAAmB,KAAA,EAA0C;AAC3E,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,WAAA,EAAa,cAAA,EAAgB,cAAa,GAAI,KAAA;AAC3E,EAAA,IAAI,CAAC,UAAA,IAAc,OAAA,IAAW,WAAA,IAAe,gBAAgB,OAAO,IAAA;AACpE,EAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,WAAA,CAAY,YAAY,GAAG,OAAO,IAAA;AAExD,EAAA,IAAI,YAAA,CAAa,WAAA,KAAgB,UAAA,EAAY,OAAO,IAAA;AACpD,EAAA,OAAO,UAAA;AACT;AAyBA,IAAI,UAAmB,EAAC;AACxB,IAAM,SAAA,uBAAgB,GAAA,EAAgB;AAEtC,SAAS,UAAU,QAAA,EAAkC;AACnD,EAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,EAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AACxC;AAEA,SAAS,IAAA,GAAO;AACd,EAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA;AAC9B;AAEA,IAAM,GAAA,GAAM,MAAyB,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAC,CAAA;AAMxD,SAAS,wBAAwB,YAAA,EAA8C;AACpF,EAAA,MAAM,MAAA,GAAS2B,aAAO,YAAY,CAAA;AAClC,EAAA,MAAM,EAAE,UAAA,EAAY,WAAA,EAAa,cAAA,EAAgB,SAAQ,GAAI,YAAA;AAC7D,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAA,CAAO,OAAA,GAAU,YAAA;AAAA,EACnB,CAAC,CAAA;AAED,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAY,IAAA,EAAK;AAAA,EACvB,GAAG,CAAC,UAAA,EAAY,WAAA,EAAa,cAAA,EAAgB,OAAO,CAAC,CAAA;AACrD,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AACjB,IAAA,MAAM,QAAe,EAAE,UAAA,EAAY,OAAA,EAAS,MAAM,OAAO,OAAA,EAAQ;AACjE,IAAA,OAAA,GAAU,CAAC,GAAG,OAAA,EAAS,KAAK,CAAA;AAC5B,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,MAAM;AACX,MAAA,OAAA,GAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,KAAK,CAAA;AAC3C,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AACjB;AAGO,SAAS,kBAAkB,OAAA,EAA0D;AAC1F,EAAA,MAAM,WAAA,GAAc,SAAS,WAAA,IAAe,IAAA;AAC5C,EAAA,OAAOC,0BAAA;AAAA,IACL,SAAA;AAAA,IACA,MAAM,cAAA,CAAe,EAAE,WAAA,EAAa,CAAA;AAAA,IACpC,MAAM;AAAA,GACR;AACF;AAGO,SAAS,eAAe,OAAA,EAA0D;AACvF,EAAA,MAAM,QAAQ,GAAA,EAAI;AAClB,EAAA,IAAI,CAAC,SAAS,CAAC,WAAA,CAAY,OAAO,OAAA,EAAS,WAAW,GAAG,OAAO,IAAA;AAChE,EAAA,OAAO,KAAA,CAAM,UAAA;AACf;AAEA,SAAS,WAAA,CAAY,OAAc,WAAA,EAAiD;AAClF,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,OAAA,EAAQ,CAAE,WAAA;AAC5B,EAAA,OAAO,CAAC,WAAA,IAAe,CAAC,GAAA,IAAO,GAAA,KAAQ,WAAA;AACzC;AAaA,SAAS,gBAAA,CAAiB;AAAA,EACxB,eAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA,EAA+E;AAE7E,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,OAAO,CAAA,CAAE,OAAA,EAAQ,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,KAAe,eAAe,CAAA;AACjF,IAAA,OAAO,EAAE,UAAA,EAAY,eAAA,EAAiB,KAAA,EAAM;AAAA,EAC9C;AAEA,EAAA,KAAA,IAAS,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC5C,IAAA,MAAM,KAAA,GAAQ,QAAQ,CAAC,CAAA;AACvB,IAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,WAAW,CAAA,EAAG;AACtC,IAAA,MAAM,EAAE,OAAA,EAAS,cAAA,EAAgB,MAAA,EAAO,GAAI,MAAM,OAAA,EAAQ;AAC1D,IAAA,IAAI,OAAA,IAAY,kBAAkB,MAAA,KAAW,cAAA;AAC3C,MAAA,OAAO,EAAE,UAAA,EAAY,KAAA,CAAM,UAAA,EAAY,KAAA,EAAM;AAAA,EACjD;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,kBAAkB,KAAA,EAAyC;AACzE,EAAA,MAAM,EAAE,eAAA,GAAkB,IAAA,EAAM,iBAAiB,IAAA,EAAM,WAAA,GAAc,MAAK,GAAI,KAAA;AAC9E,EAAA,OAAOA,0BAAA;AAAA,IACL,SAAA;AAAA,IACA,MAAM,iBAAiB,EAAE,eAAA,EAAiB,gBAAgB,WAAA,EAAa,GAAG,UAAA,IAAc,IAAA;AAAA,IACxF,MAAM;AAAA,GACR;AACF;AAOO,SAAS,oBAAoB,KAAA,EAAyC;AAC3E,EAAA,MAAM,MAAA,GAAS,iBAAiB,KAAK,CAAA;AACrC,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,MAAM,EAAE,UAAA,EAAY,KAAA,EAAM,GAAI,MAAA;AAC9B,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,EAAE,OAAA,EAAS,QAAA,EAAS,GAAI,MAAM,OAAA,EAAQ;AAC5C,IAAA,IAAI,WAAW,OAAA,KAAY,UAAA,IAAcC,iCAAA,CAAgB,OAAO,EAAE,KAAA,KAAU,UAAA;AAC1E,MAAA,QAAA,IAAW;AAAA,EACf;AACA,EAAA,OAAO,UAAA;AACT;;;ACrLO,IAAM,OAAA,GAAyB,EAAE,UAAA,EAAY,IAAA,EAAM,aAAa,KAAA;AAGhE,SAAS,aAAa,GAAA,EAAyD;AACpF,EAAA,IAAI,CAAC,KAAK,OAAO,OAAA;AACjB,EAAA,MAAM,UAAA,GAAa,IAAI,qBAAA,IAAyB,IAAA;AAChD,EAAA,OAAO,EAAE,UAAA,EAAY,WAAA,EAAa,CAAC,UAAA,IAAc,GAAA,CAAI,+BAA+B,IAAA,EAAK;AAC3F;AAGO,SAAS,sBAAA,CACd,eACA,UAAA,EACe;AACf,EAAA,IAAI,MAAA,GAAkC,IAAA;AACtC,EAAA,KAAA,MAAW,GAAA,IAAO,aAAA,IAAiB,EAAC,EAAG;AACrC,IAAA,IAAI,GAAA,CAAI,0BAA0B,UAAA,EAAY;AAC9C,IAAA,IAAI,CAAC,WAAW,GAAA,CAAI,UAAA,IAAc,OAAO,MAAA,CAAO,UAAA,IAAc,KAAK,MAAA,GAAS,GAAA;AAAA,EAC9E;AACA,EAAA,OAAO,QAAQ,WAAA,IAAe,IAAA;AAChC;AAOO,IAAM,2BAAA,GAA8B;AAE3C,SAAS,OAAA,GAA+B;AACtC,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,YAAA,KAAiB,WAAA,GAAc,KAAA,CAAA,GAAY,YAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,yBAAA,GAAoD;AAClE,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,KAAK,KAAA,CAAM,OAAA,IAAW,OAAA,CAAQ,2BAA2B,KAAK,MAAM,CAAA;AACnF,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAA;AAC9B,MAAA,KAAA,MAAW,CAAC,cAAA,EAAgB,UAAU,CAAA,IAAK,MAAA,CAAO,QAAQ,MAAM,CAAA;AAC9D,QAAA,IAAI,OAAO,UAAA,KAAe,QAAA,EAAU,GAAA,CAAI,cAAc,CAAA,GAAI,UAAA;AAAA,IAAA;AAAA,EAChE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,4BAA4B,eAAA,EAA0C;AACpF,EAAA,IAAI,eAAA,CAAgB,WAAW,CAAA,EAAG;AAClC,EAAA,MAAM,OAAO,yBAAA,EAA0B;AACvC,EAAA,eAAA,CAAgB,QAAQ,CAAC,EAAA,KAAO,OAAO,IAAA,CAAK,EAAE,CAAC,CAAA;AAC/C,EAAA,IAAI;AACF,IAAA,IAAI,MAAA,CAAO,KAAK,IAAI,CAAA,CAAE,WAAW,CAAA,EAAG,OAAA,EAAQ,EAAG,UAAA,CAAW,2BAA2B,CAAA;AAAA,kBACxE,EAAG,OAAA,CAAQ,6BAA6B,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,EAC3E,CAAA,CAAA,MAAQ;AAAA,EAER;AACF","file":"chunk-TUPSNW3B.cjs","sourcesContent":["/**\n * A search's state outside any component: the query last searched, its passages, and whether it\n * is running. A page that shows the shared session (`sharedSearchSession`) keeps its results when\n * it is left and opened again, another surface can hand it a query to run on arrival\n * ({@link requestSearch}), and {@link persistSearchSession} keeps the last query across reloads.\n */\nimport { createStore, type StoreApi } from 'zustand/vanilla'\nimport type { SearchChunk } from '@arbidocs/sdk/browser'\n\nexport type SearchStatus = 'idle' | 'running' | 'done' | 'error'\n\nexport interface SearchSessionState {\n /** The workspace the query and results belong to. */\n workspaceId: string | null\n /** The query last searched, or handed over to run. */\n query: string\n /** The last search's passages, best first. */\n results: SearchChunk[]\n /** A search has finished with results to show (cleared by {@link clearSearchSession}). */\n searched: boolean\n status: SearchStatus\n error: string | null\n /** A query handed over by {@link requestSearch}, run once by the page that shows the session. */\n pending: string | null\n /** Counts searches, so the reply to an older one never overwrites a newer one. */\n run: number\n}\n\nexport type SearchSession = StoreApi<SearchSessionState>\n\nconst EMPTY: Omit<SearchSessionState, 'workspaceId' | 'run'> = {\n query: '',\n results: [],\n searched: false,\n status: 'idle',\n error: null,\n pending: null,\n}\n\nexport function createSearchSession(): SearchSession {\n return createStore<SearchSessionState>(() => ({ ...EMPTY, workspaceId: null, run: 0 }))\n}\n\n/** The session a host's search page shows. */\nexport const sharedSearchSession: SearchSession = createSearchSession()\n\n/** Back to nothing searched (in `workspaceId` when given); a running search's reply is dropped. */\nexport function clearSearchSession(\n workspaceId?: string | null,\n session: SearchSession = sharedSearchSession\n): void {\n session.setState((s) => ({\n ...EMPTY,\n workspaceId: workspaceId === undefined ? s.workspaceId : workspaceId,\n run: s.run + 1,\n }))\n}\n\n/**\n * Hand a query to the search page, which runs it when it shows the session (the user already\n * asked once; the page must not wait for a second Enter).\n */\nexport function requestSearch(\n query: string,\n workspaceId: string | null,\n session: SearchSession = sharedSearchSession\n): void {\n clearSearchSession(workspaceId, session)\n session.setState({ query, pending: query })\n}\n\n/** The handed-over query, once: the next call returns null. */\nexport function takePendingSearch(session: SearchSession = sharedSearchSession): string | null {\n const { pending } = session.getState()\n if (pending !== null) session.setState({ pending: null })\n return pending\n}\n\ninterface SavedSearch {\n query?: string\n workspaceId?: string | null\n}\n\n/**\n * Keep the last query (and its workspace) in `storage` under `key`, so the search box shows it\n * after a reload. Results are not kept. Returns the unsubscribe.\n */\nexport function persistSearchSession(\n key: string,\n storage: Pick<Storage, 'getItem' | 'setItem'> | undefined = globalThis.localStorage,\n session: SearchSession = sharedSearchSession\n): () => void {\n if (!storage) return () => {}\n try {\n const saved = JSON.parse(storage.getItem(key) ?? 'null') as SavedSearch | null\n if (saved && typeof saved.query === 'string' && !session.getState().query)\n session.setState({ query: saved.query, workspaceId: saved.workspaceId ?? null })\n } catch {\n // Unreadable: start empty.\n }\n let last = ''\n return session.subscribe(({ query, workspaceId }) => {\n const next = JSON.stringify({ query, workspaceId })\n if (next === last) return\n last = next\n try {\n storage.setItem(key, next)\n } catch {\n // Storage full or blocked: the query is simply not kept.\n }\n })\n}\n","/**\n * Toaster — the one shared toast surface, built on sonner (the mature engine:\n * stacking, swipe-to-dismiss, a11y, timing). Mount once near the app root; any\n * code then calls `notify.*(...)` (or the re-exported `toast`) from anywhere.\n *\n * Firm-agnostic: every sonner `ToasterProps` passes through, so a consumer sets\n * its own `position` / `theme` / `toastOptions`. The defaults give a neutral\n * shadcn-token card that both apps can override.\n */\nimport { Toaster as Sonner, type ToasterProps } from 'sonner'\n\nexport type { ToasterProps }\n\nconst DEFAULT_TOAST_OPTIONS: ToasterProps['toastOptions'] = {\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-card group-[.toaster]:text-foreground group-[.toaster]:border group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:rounded-lg',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n },\n}\n\nexport function Toaster({ toastOptions, ...props }: ToasterProps) {\n return (\n <Sonner\n className=\"toaster group\"\n toastOptions={toastOptions ?? DEFAULT_TOAST_OPTIONS}\n {...props}\n />\n )\n}\n","/**\n * NotificationBell — the topbar notification centre: a bell with an unread badge\n * that opens a dropdown of recorded entries (newest first) with an unread dot,\n * relative time and optional deep-link. \"Mark all read\" clears the badge. Backed\n * by the shared {@link useNotify} store (the same one the <Toaster/> renders).\n *\n * Firm-agnostic: navigation is a callback (`onNavigate`), styling tracks semantic\n * tokens, and per-variant glyph colours are overridable via `toneClassNames`.\n */\nimport { useState, type ReactElement } from 'react'\nimport {\n Bell,\n BellOff,\n CheckCheck,\n CheckCircle2,\n AlertTriangle,\n XCircle,\n Info,\n X,\n} from 'lucide-react'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '../ui/dropdown-menu'\nimport { ScrollArea } from '../ui/scroll-area'\nimport { cn } from '../lib/utils'\nimport { formatRelativeTime } from '../lib/format-relative-time'\nimport {\n useNotify,\n selectUnread,\n DEFAULT_NOTIFY_TONE,\n type NotifyVariant,\n type AppNotification,\n} from './notify-store'\n\nconst GLYPH: Record<NotifyVariant, typeof Info> = {\n success: CheckCircle2,\n error: XCircle,\n warning: AlertTriangle,\n info: Info,\n}\n\n/** Entries the panel lists, newest first. */\nconst BELL_LIMIT = 100\n\n/** What a custom bell trigger needs to render itself. */\nexport interface NotificationBellTriggerState {\n /** Unread count (0 when none). */\n unread: number\n /** Accessible name, including the count: \"Notifications, 2 unread\". */\n ariaLabel: string\n testId: string\n}\n\nexport interface NotificationBellProps {\n /**\n * Replaces the default icon button with the host's own trigger (for example a labelled sidebar\n * row). It must forward its ref and rest props: it is mounted as the dropdown trigger.\n */\n renderTrigger?: (state: NotificationBellTriggerState) => ReactElement\n /** Called with an entry's `href` when it's clicked (e.g. router navigate). */\n onNavigate?: (href: string) => void\n /** Open this entry in the host notification centre instead of following its link. */\n onSelectNotification?: (notification: AppNotification) => void\n /** Called after an entry is locally marked read — the hook for a backend\n * bridge to propagate read state upstream (filter by the ids it owns). */\n onMarkRead?: (id: string) => void\n /** Called after \"Mark all read\" — same upstream-propagation hook. */\n onMarkAllRead?: () => void\n /** Show the store's toast mute switch in the header — the bell is where notification\n * behaviour is controlled. */\n showMuteToggle?: boolean\n /** Override per-variant glyph colours (e.g. brand emerald for success). */\n toneClassNames?: Partial<Record<NotifyVariant, string>>\n emptyText?: string\n /** Footer link to the app's full notification surface. Omit to hide. */\n onViewAll?: () => void\n viewAllLabel?: string\n testId?: string\n /** Where the panel opens relative to the bell (a sidebar-footer bell opens upward). */\n side?: 'top' | 'right' | 'bottom' | 'left'\n align?: 'start' | 'center' | 'end'\n}\n\nexport function NotificationBell({\n renderTrigger,\n onNavigate,\n onSelectNotification,\n onMarkRead,\n onMarkAllRead,\n showMuteToggle = false,\n toneClassNames,\n emptyText = \"You're all caught up.\",\n onViewAll,\n viewAllLabel = 'View all',\n testId = 'notifications',\n side = 'bottom',\n align = 'end',\n}: NotificationBellProps) {\n const [open, setOpen] = useState(false)\n const notifications = useNotify((s) => s.notifications)\n const unread = useNotify(selectUnread)\n const markAllRead = useNotify((s) => s.markAllRead)\n const markRead = useNotify((s) => s.markRead)\n const muted = useNotify((s) => s.muted)\n const setMuted = useNotify((s) => s.setMuted)\n const tone = (v: NotifyVariant) => toneClassNames?.[v] ?? DEFAULT_NOTIFY_TONE[v]\n\n // Ambient entries (routine session activity — \"Opening workspace…\") are kept\n // for the log but never surfaced in the bell panel: they never badge and are\n // always filtered out here. The panel is the recent history; a host's\n // notification page (`onViewAll`) holds the rest.\n const visible = notifications.filter((n) => !n.ambient).slice(0, BELL_LIMIT)\n\n return (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n {renderTrigger ? (\n renderTrigger({\n unread,\n ariaLabel: `Notifications${unread ? `, ${unread} unread` : ''}`,\n testId,\n })\n ) : (\n <button\n className=\"relative flex size-9 pointer-coarse:size-11 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n data-testid={testId}\n aria-label={`Notifications${unread ? `, ${unread} unread` : ''}`}\n title=\"Notifications\"\n >\n <Bell className=\"size-5\" />\n {unread > 0 && (\n <span\n className=\"absolute -right-0.5 -top-0.5 flex min-w-4 items-center justify-center rounded-full bg-primary px-1 text-xs font-semibold leading-4 text-primary-foreground\"\n data-testid={`${testId}-badge`}\n >\n {unread > 9 ? '9+' : unread}\n </span>\n )}\n </button>\n )}\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align={align}\n side={side}\n sideOffset={8}\n collisionPadding={12}\n className=\"w-60 rounded-lg border-border/60 p-0 shadow-lg\"\n data-testid={`${testId}-panel`}\n data-topbar-popover=\"\"\n >\n <div className=\"flex items-center justify-between gap-3 border-b border-border px-3.5 py-2.5 pointer-coarse:py-0\">\n <p className=\"text-sm font-semibold text-foreground\">Notifications</p>\n <div className=\"flex items-center gap-3 pointer-coarse:gap-1\">\n {unread > 0 && (\n <button\n onClick={() => {\n markAllRead()\n onMarkAllRead?.()\n }}\n className=\"flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:opacity-80 pointer-coarse:min-h-11 pointer-coarse:px-2\"\n data-testid={`${testId}-mark-all`}\n >\n <CheckCheck className=\"size-3.5\" /> Mark all read\n </button>\n )}\n {showMuteToggle && (\n <button\n onClick={() => setMuted(!muted)}\n aria-pressed={muted}\n title={muted ? 'Unmute notifications' : 'Mute notifications'}\n aria-label={muted ? 'Unmute notifications' : 'Mute notifications'}\n className={cn(\n 'flex size-6 items-center justify-center rounded-md transition-colors hover:bg-accent pointer-coarse:size-11',\n muted ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'\n )}\n data-testid={`${testId}-mute`}\n >\n <BellOff className=\"size-3.5\" />\n </button>\n )}\n {/* Explicit close — the dropdown otherwise only dismisses via\n tap-outside/Escape, which isn't discoverable on touch and (at\n mobile width, see blocks.css) the panel covers most\n of the screen so there's nothing to tap outside of. Radix\n closes a DropdownMenu on any item select by default, so a\n plain item with no other effect doubles as a close button. */}\n <DropdownMenuItem\n className=\"flex size-6 items-center justify-center rounded-md p-0 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus:bg-accent pointer-coarse:size-11\"\n aria-label=\"Close notifications\"\n data-testid={`${testId}-close`}\n >\n <X className=\"size-3.5\" />\n </DropdownMenuItem>\n </div>\n </div>\n {muted && (\n <p\n className=\"border-b border-border/60 bg-amber-500/10 px-3.5 py-1.5 text-xs text-muted-foreground\"\n data-testid={`${testId}-muted-note`}\n >\n Toasts are muted — everything still lands here.\n </p>\n )}\n\n {visible.length === 0 ? (\n <div className=\"px-3.5 py-10 text-center text-sm text-muted-foreground\">{emptyText}</div>\n ) : (\n <ScrollArea className=\"max-h-[380px]\">\n <ul data-testid={`${testId}-list`}>\n {visible.map((n) => {\n const Glyph = GLYPH[n.variant]\n return (\n <li key={n.id}>\n <button\n onClick={() => {\n markRead(n.id)\n if (!n.read) onMarkRead?.(n.id)\n setOpen(false)\n if (onSelectNotification) {\n onSelectNotification(n)\n return\n }\n // The specific action wins over the generic deep link.\n if (n.onSelect) n.onSelect()\n else if (n.href) onNavigate?.(n.href)\n }}\n className={cn(\n 'flex w-full items-start gap-3 border-b border-border/60 px-3.5 py-3 text-left transition-colors hover:bg-accent',\n !n.read && 'bg-accent/40'\n )}\n data-testid={`${testId}-item`}\n data-notification-id={n.id}\n >\n <Glyph className={cn('mt-0.5 size-4 shrink-0', tone(n.variant))} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium leading-snug text-foreground\">\n {n.title}\n </p>\n {n.description && (\n <p className=\"mt-0.5 line-clamp-2 text-xs leading-relaxed text-muted-foreground\">\n {n.description}\n </p>\n )}\n <p className=\"mt-1 text-xs text-muted-foreground/80\">\n {formatRelativeTime(new Date(n.ts).toISOString())}\n </p>\n </div>\n {!n.read && (\n <span className=\"mt-1.5 size-2 shrink-0 rounded-full bg-primary\" />\n )}\n </button>\n </li>\n )\n })}\n </ul>\n </ScrollArea>\n )}\n {onViewAll && (\n // A real menu item, not a bare button: selecting it must CLOSE the\n // dropdown on its way to the full surface.\n <DropdownMenuItem\n onClick={onViewAll}\n className=\"justify-center rounded-none border-t border-border px-3.5 py-2.5 text-xs font-medium text-primary focus:text-primary pointer-coarse:min-h-11\"\n data-testid={`${testId}-view-all`}\n >\n {viewAllLabel}\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n","/**\n * `<ArbiHost config>`: the one place a host app hands its configuration to every hook and kit.\n *\n * <ArbiHost config={{ arbi, session, documents, calendar, mail, account, … }}>\n * <App />\n * </ArbiHost>\n *\n * Every field is optional and has a default (see `ArbiHostConfig`); a kit reads its domain from\n * the config (`useArbiHost().documents`, `useHost().billing` in blocks). A nested `<ArbiHost>`\n * overrides only the fields it gives and inherits the rest (`environment` field by field), for a\n * subtree that opens projects in its own tabs, say. There is no other host provider: a new domain\n * is a new optional field, never a new provider.\n *\n * SDK-free (this module, ./context, ./merge and the entity vocabulary are all it reaches), so a\n * marketing site that only sets the blocks environment does not bundle the SDK.\n */\n\nimport { useContext, useMemo, useState, type ComponentType, type ReactNode } from 'react'\nimport { ArbiHostContext } from './context'\nimport { mergeHostConfig, OWN_SESSION_SLOT } from './merge'\nimport { configureEntityVocabulary, type EntityVocabulary } from '../entities/vocabulary'\n\n/** A sign-in layer mounted inside the host (`defaultHost` in `@arbidocs/blocks/connect`). */\nexport interface ArbiHostConnection {\n Provider: ComponentType<{ children: ReactNode }>\n}\n\nexport interface ArbiHostProps<Config extends object> {\n config: Config\n children?: ReactNode\n}\n\n/**\n * Provide the host configuration. Typed by the package it is imported from: `@arbidocs/react`'s\n * takes the react domains, `@arbidocs/blocks`' the blocks domains as well.\n */\nexport function ArbiHost<Config extends object>({\n config,\n children,\n}: ArbiHostProps<Config>): React.ReactElement {\n const parent = useContext(ArbiHostContext)\n // A top-level host without a session store gets its own, made on first use (useArbiSessionStore).\n const [ownSession] = useState(() => ({ current: null as unknown }))\n const value = useMemo(() => {\n const merged = mergeHostConfig(parent, config)\n return merged[OWN_SESSION_SLOT] ? merged : { ...merged, [OWN_SESSION_SLOT]: ownSession }\n }, [parent, config, ownSession])\n // The site's nouns are in place before any kit below renders a label.\n const { vocabulary } = config as { vocabulary?: EntityVocabulary }\n if (vocabulary) configureEntityVocabulary(vocabulary)\n const Connection = (config as { connection?: ArbiHostConnection }).connection?.Provider\n return (\n <ArbiHostContext.Provider value={value}>\n {Connection ? <Connection>{children}</Connection> : children}\n </ArbiHostContext.Provider>\n )\n}\n","/**\n * @mentions in chat text: pure helpers shared by the composer (autocomplete, extraction) and\n * the message renderer (chips). No React, no SDK.\n *\n * A mention lives in two places: the readable `@Label` text in the message content, and a\n * structured entry on the message (`{ type, user_ext_id, label }`) that the server reads to share\n * the conversation and notify. The composer only ever inserts `@<label>` for a known candidate,\n * so the structured list can be recovered from the text at send time ({@link extractMentions});\n * the renderer turns each stored mention back into a chip ({@link linkMentions}).\n */\n\n/** Who can be mentioned: a workspace member, or the assistant. */\nexport type MentionKind = 'user' | 'assistant'\n\n/** One entry of the mention autocomplete. */\nexport interface MentionCandidate {\n /** User external id (`usr-…`) for a person; any stable key (e.g. `assistant`) for the assistant. */\n id: string\n kind: MentionKind\n /** Inserted as `@<label>`. For people this must be the server's display name (given + family). */\n label: string\n /** Secondary line in the menu (email, role, …). */\n description?: string\n}\n\n/** The structured mention a message carries (the API's `MessageMention`). */\nexport interface MessageMentionRef {\n type: MentionKind\n user_ext_id?: string | null\n label?: string | null\n}\n\n/** Longest text after `@` that still counts as a query in progress. */\nconst MAX_QUERY_LENGTH = 40\n\n/**\n * The `@query` the caret is in, if any: the `@` must start the text or follow whitespace, and the\n * query may contain spaces (names do) but no newline. Returns the index of the `@` and the query.\n */\nexport function findMentionQuery(\n text: string,\n caret: number\n): { start: number; query: string } | null {\n const before = text.slice(0, caret)\n const at = before.lastIndexOf('@')\n if (at < 0) return null\n if (at > 0 && !/\\s/.test(before[at - 1])) return null\n const query = before.slice(at + 1)\n if (query.length > MAX_QUERY_LENGTH || query.includes('\\n') || query.startsWith(' ')) return null\n return { start: at, query }\n}\n\n/** Candidates matching a query: label prefix (or word-prefix) matches, prefix matches first. */\nexport function filterMentionCandidates(\n candidates: ReadonlyArray<MentionCandidate>,\n query: string\n): MentionCandidate[] {\n const q = query.trim().toLowerCase()\n if (!q) return candidates.slice()\n const scored: Array<{ c: MentionCandidate; score: number }> = []\n for (const c of candidates) {\n const label = c.label.toLowerCase()\n if (label.startsWith(q)) scored.push({ c, score: 0 })\n else if (label.split(/\\s+/).some((word) => word.startsWith(q))) scored.push({ c, score: 1 })\n else if (c.description?.toLowerCase().startsWith(q)) scored.push({ c, score: 2 })\n }\n return scored.sort((a, b) => a.score - b.score).map((s) => s.c)\n}\n\n/** Replace the `@query` at `start…caret` with `@<label> `; returns the new text and caret. */\nexport function insertMention(\n text: string,\n start: number,\n caret: number,\n label: string\n): { text: string; caret: number } {\n const inserted = `@${label} `\n return {\n text: text.slice(0, start) + inserted + text.slice(caret),\n caret: start + inserted.length,\n }\n}\n\n/** Every `[from, to)` range where `@<label>` occurs as a whole token. */\nfunction tokenRanges(text: string, label: string): Array<[number, number]> {\n const needle = `@${label}`\n const ranges: Array<[number, number]> = []\n let from = 0\n for (;;) {\n const i = text.indexOf(needle, from)\n if (i < 0) break\n const end = i + needle.length\n const startsToken = i === 0 || /\\s|\\(|\\[/.test(text[i - 1])\n const endsToken = end === text.length || !/[\\p{L}\\p{N}_]/u.test(text[end])\n if (startsToken && endsToken) ranges.push([i, end])\n from = end\n }\n return ranges\n}\n\n/**\n * The candidates mentioned in `text`, in order of first appearance. Longer labels win overlaps,\n * so `@Bob Smith` is Bob Smith, not a separate `@Bob`.\n */\nexport function extractMentions(\n text: string,\n candidates: ReadonlyArray<MentionCandidate>\n): MentionCandidate[] {\n const taken: Array<[number, number]> = []\n const found: Array<{ c: MentionCandidate; at: number }> = []\n const byLength = [...candidates].sort((a, b) => b.label.length - a.label.length)\n for (const c of byLength) {\n if (!c.label) continue\n for (const [from, to] of tokenRanges(text, c.label)) {\n if (taken.some(([a, b]) => from < b && to > a)) continue\n taken.push([from, to])\n if (!found.some((f) => f.c.id === c.id)) found.push({ c, at: from })\n }\n }\n return found.sort((a, b) => a.at - b.at).map((f) => f.c)\n}\n\n/** The API payload for mentioned candidates. */\nexport function toMessageMentions(mentioned: ReadonlyArray<MentionCandidate>): MessageMentionRef[] {\n return mentioned.map((c) =>\n c.kind === 'assistant' ? { type: 'assistant' } : { type: 'user', user_ext_id: c.id }\n )\n}\n\n/** Fragment prefix of the links {@link linkMentions} writes. */\nexport const MENTION_HREF_PREFIX = '#mention-'\n\n/** Escape the characters that would end a markdown link text early. */\nfunction escapeLinkText(label: string): string {\n return label.replace(/[[\\]\\\\]/g, (ch) => `\\\\${ch}`)\n}\n\n/**\n * Turn each stored mention's `@<label>` in `content` into a markdown link\n * `[@<label>](#mention-<id>)`, so a markdown renderer can draw it as a chip (see\n * {@link mentionFromHref}). Text that no longer matches (a renamed user) stays plain text.\n * `assistantLabels` lists other names the assistant may have been mentioned by.\n */\nexport function linkMentions(\n content: string,\n mentions: ReadonlyArray<MessageMentionRef> | null | undefined,\n assistantLabels: ReadonlyArray<string> = []\n): string {\n if (!mentions || mentions.length === 0 || !content) return content\n const targets: Array<{ label: string; id: string }> = []\n for (const m of mentions) {\n const id = m.type === 'assistant' ? 'assistant' : m.user_ext_id\n if (!id) continue\n const labels = m.type === 'assistant' ? [m.label ?? '', ...assistantLabels] : [m.label ?? '']\n for (const label of labels) if (label) targets.push({ label, id })\n }\n targets.sort((a, b) => b.label.length - a.label.length)\n const replacements: Array<{ from: number; to: number; text: string }> = []\n for (const { label, id } of targets) {\n for (const [from, to] of tokenRanges(content, label)) {\n if (replacements.some((r) => from < r.to && to > r.from)) continue\n replacements.push({\n from,\n to,\n text: `[@${escapeLinkText(label)}](${MENTION_HREF_PREFIX}${id})`,\n })\n }\n }\n replacements.sort((a, b) => b.from - a.from)\n let out = content\n for (const r of replacements) out = out.slice(0, r.from) + r.text + out.slice(r.to)\n return out\n}\n\n/** The mention a `#mention-…` href points at, or null for any other href. */\nexport function mentionFromHref(\n href: string | null | undefined\n): { kind: MentionKind; id: string } | null {\n if (!href?.startsWith(MENTION_HREF_PREFIX)) return null\n const id = href.slice(MENTION_HREF_PREFIX.length)\n if (!id) return null\n return { kind: id === 'assistant' ? 'assistant' : 'user', id }\n}\n\n/** A recipient alone is not a message. */\nexport function hasMessageBody(value: string, recipientLabel = 'ARBI'): boolean {\n const text = value.trim()\n return !!text && text.toLowerCase() !== `@${recipientLabel}`.toLowerCase()\n}\n","import { useEffect, useRef, useSyncExternalStore } from 'react'\nimport { parseVersionRef } from '../artifacts/versions'\n\n/**\n * Drafting mode: the documents open beside the chat, and which one a chat turn drafts in.\n *\n * A viewer registers the document it shows (`useRegisterOpenDocument`). Being open binds nothing:\n * a turn names a document (`active_artifact_ext_id`, read with `takeDocumentForTurn` as the\n * question is sent) only when its thread is bound to it (`./thread-document`: started from the\n * document, or attached in that thread), when the document was made in that thread, or when the\n * open document is ambient (an email draft open in the composer). The server then binds the live\n * document to the turn: a Word document is read on demand and edited as tracked changes in the\n * open editor, and what the assistant saves becomes a child version of it. The request carries a\n * reference, never the content.\n *\n * The named document is always the subject, also while one of its earlier versions is on screen\n * read-only: a version still names its document. Sending a turn then returns the viewer to the live\n * document (`showLive`), where the assistant's edits appear as they are made. (Pinning a specific\n * version as a source is a separate feature: it does not go through here.)\n *\n * A module-level registry (not React context), like `useChatSurface`, so a viewer and a chat agree\n * wherever they sit in the tree; the most recently opened document is on top and closing it hands\n * back to the one before. It is not the session state's viewing document (`useArbiSessionState`):\n * it holds what mounted viewers can draft in (saved documents only, with the callback that shows\n * the live one again), and a turn reads it outside React. A viewer on the session's viewing\n * document passes that as `shownId` (it may be a version reference, resolved here the same way as\n * `selectViewingDocumentId` does).\n */\n\n/** What a viewer knows about the document it shows. */\nexport interface SavedDocumentInput {\n /** The document (`doc-…`), never a version reference. */\n documentId: string | null | undefined\n /** An unsaved draft (client-minted id, no backend record). */\n isDraft: boolean\n /** Still streaming: nothing is persisted yet. */\n isStreaming: boolean\n /** An image, audio or video artifact: there is no text to draft in. */\n isBlobArtifact: boolean\n /** The loaded document record. */\n documentData:\n | { external_id?: string | null; wp_type?: string | null; file_name?: string | null }\n | null\n | undefined\n}\n\n/** The fields that decide where a document opens. */\nexport interface WordDocumentKind {\n file_name?: string | null\n wp_type?: string | null\n}\n\n/**\n * A document edited in the Word editor: a `.docx`, or a document the assistant wrote (an\n * artifact). The one rule for where a document opens (`openWordEditor` or `openDocument`) and\n * which documents a chat drafts in.\n */\nexport function opensInWord(doc: WordDocumentKind | null | undefined): boolean {\n return !!doc && (doc.wp_type === 'artifact' || !!doc.file_name?.toLowerCase().endsWith('.docx'))\n}\n\n/**\n * The saved, content-backed document a chat can draft in, or null. Only a saved artifact or Word\n * document counts: drafts, an artifact still streaming and blob artifacts do not.\n */\nexport function savedDocumentIdFor(input: SavedDocumentInput): string | null {\n const { documentId, isDraft, isStreaming, isBlobArtifact, documentData } = input\n if (!documentId || isDraft || isStreaming || isBlobArtifact) return null\n if (!documentData || !opensInWord(documentData)) return null\n // A stale record of the previously viewed document is not this one.\n if (documentData.external_id !== documentId) return null\n return documentId\n}\n\nexport interface OpenDocumentRegistration {\n /** The saved document the viewer shows (`doc-…`); null or empty registers nothing. */\n documentId: string | null | undefined\n /** What is on screen: the document itself, or one of its earlier versions (`doc-…@v2`). */\n shownId?: string | null\n /** Show the live document again. Called when a turn starts while an earlier version is shown. */\n showLive?: () => void\n /** The workspace the document belongs to; a chat in another workspace does not draft in it. */\n workspaceId?: string | null\n /** The thread the document was made in: that thread drafts in it without being bound to it. */\n conversationId?: string | null\n /**\n * Drafted in by whichever chat is beside it, bound or not (an email draft open in the composer:\n * the composer is a drafting surface of its own).\n */\n ambient?: boolean\n}\n\ninterface Entry {\n documentId: string\n current: () => OpenDocumentRegistration\n}\n\nlet entries: Entry[] = []\nconst listeners = new Set<() => void>()\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => listeners.delete(listener)\n}\n\nfunction emit() {\n listeners.forEach((l) => l())\n}\n\nconst top = (): Entry | undefined => entries[entries.length - 1]\n\n/**\n * Registers the document a viewer shows as the open document while the caller is mounted and\n * `documentId` is set. Pass `savedDocumentIdFor(...)`, or the id of a document known to be saved.\n */\nexport function useRegisterOpenDocument(registration: OpenDocumentRegistration): void {\n const latest = useRef(registration)\n const { documentId, workspaceId, conversationId, ambient } = registration\n useEffect(() => {\n latest.current = registration\n })\n // What decides which chat drafts in it changed (its record loaded): readers re-render.\n useEffect(() => {\n if (documentId) emit()\n }, [documentId, workspaceId, conversationId, ambient])\n useEffect(() => {\n if (!documentId) return\n const entry: Entry = { documentId, current: () => latest.current }\n entries = [...entries, entry]\n emit()\n return () => {\n entries = entries.filter((e) => e !== entry)\n emit()\n }\n }, [documentId])\n}\n\n/** The open document's id (the most recently opened), or null. Re-renders when it changes. */\nexport function useOpenDocumentId(options?: { workspaceId?: string | null }): string | null {\n const workspaceId = options?.workspaceId ?? null\n return useSyncExternalStore(\n subscribe,\n () => openDocumentId({ workspaceId }),\n () => null\n )\n}\n\n/** The open document's id (the most recently opened); with `workspaceId`, only one of it. */\nexport function openDocumentId(options?: { workspaceId?: string | null }): string | null {\n const entry = top()\n if (!entry || !inWorkspace(entry, options?.workspaceId)) return null\n return entry.documentId\n}\n\nfunction inWorkspace(entry: Entry, workspaceId: string | null | undefined): boolean {\n const own = entry.current().workspaceId\n return !workspaceId || !own || own === workspaceId\n}\n\n/** What a turn is about to be sent in: its conversation and the document its thread is bound to. */\nexport interface TurnDocumentInput {\n /** The thread's bound document (`threadDocumentId` / the session's `newChatDocumentId`). */\n boundDocumentId: string | null | undefined\n /** The conversation (null: a new chat). */\n conversationId: string | null | undefined\n /** The chat's workspace: an open document of another workspace is never picked up. */\n workspaceId?: string | null\n}\n\n/** The document a turn drafts in, and the open viewer showing it (if one is). */\nfunction pickTurnDocument({\n boundDocumentId,\n conversationId,\n workspaceId,\n}: TurnDocumentInput): { documentId: string; entry: Entry | undefined } | null {\n // A bound thread names its document on every turn, open or not.\n if (boundDocumentId) {\n const entry = [...entries].reverse().find((e) => e.documentId === boundDocumentId)\n return { documentId: boundDocumentId, entry }\n }\n // Unbound: only a document made in this thread, or an ambient one (an email draft).\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i]\n if (!inWorkspace(entry, workspaceId)) continue\n const { ambient, conversationId: madeIn } = entry.current()\n if (ambient || (conversationId && madeIn === conversationId))\n return { documentId: entry.documentId, entry }\n }\n return null\n}\n\n/** The document a turn sent now would draft in, or null. Re-renders as documents open and close. */\nexport function useTurnDocumentId(input: TurnDocumentInput): string | null {\n const { boundDocumentId = null, conversationId = null, workspaceId = null } = input\n return useSyncExternalStore(\n subscribe,\n () => pickTurnDocument({ boundDocumentId, conversationId, workspaceId })?.documentId ?? null,\n () => null\n )\n}\n\n/**\n * The document an assistant turn about to be sent drafts in, or null. Call it once per turn as the\n * question is sent: when an earlier version of the document is on screen, the viewer returns to the\n * live document, where the assistant's edits appear.\n */\nexport function takeDocumentForTurn(input: TurnDocumentInput): string | null {\n const picked = pickTurnDocument(input)\n if (!picked) return null\n const { documentId, entry } = picked\n if (entry) {\n const { shownId, showLive } = entry.current()\n if (shownId && shownId !== documentId && parseVersionRef(shownId).docId === documentId)\n showLive?.()\n }\n return documentId\n}\n","/**\n * A thread's document: the one document a conversation drafts in, part of the conversation.\n *\n * A thread is bound to a document only when it was started from it (\"Chat about this document\" in\n * the viewer) or the person attached it in that thread. Only that thread names it on its turns\n * (`active_artifact_ext_id`), on every turn and after a reload. A document merely open or docked\n * beside the chat binds nothing: a new chat (the ask bar, the new-chat button, the thread\n * launcher, home) starts unbound, so a question there never becomes an edit of whatever is open.\n *\n * The binding is the server's: the conversation's `bound_document_ext_id`, set by the first turn\n * (`bound_document_ext_id` on the turn that starts it) or by a PATCH, and read under each reader's\n * access (`bound_document_unavailable`: bound to a document this reader cannot open). It follows\n * the person to every device, and a shared thread's members all see it. The query cache holds it\n * (`./thread-binding`); a new chat's binding is the session's `newChatDocumentId` until its first\n * turn creates the conversation.\n *\n * This module is the light half (no query client, no SDK), so the shell entry can carry it.\n */\n\n/** What a conversation row says about its binding. */\nexport interface ThreadBindingRow {\n external_id: string\n bound_document_ext_id?: string | null\n bound_document_unavailable?: boolean | null\n updated_at?: string | null\n}\n\n/** A conversation's binding as this reader sees it. */\nexport interface ThreadBinding {\n /** The bound document, or null (unbound, or bound to one this reader cannot open). */\n documentId: string | null\n /** Bound to a document this reader cannot open (another member's private document, or deleted). */\n unavailable: boolean\n}\n\nexport const UNBOUND: ThreadBinding = { documentId: null, unavailable: false }\n\n/** A row's binding. */\nexport function bindingOfRow(row: ThreadBindingRow | null | undefined): ThreadBinding {\n if (!row) return UNBOUND\n const documentId = row.bound_document_ext_id ?? null\n return { documentId, unavailable: !documentId && row.bound_document_unavailable === true }\n}\n\n/** The most recently active conversation bound to a document, among `conversations`, or null. */\nexport function latestThreadOfDocument(\n conversations: readonly ThreadBindingRow[] | null | undefined,\n documentId: string\n): string | null {\n let latest: ThreadBindingRow | null = null\n for (const row of conversations ?? []) {\n if (row.bound_document_ext_id !== documentId) continue\n if (!latest || (row.updated_at ?? '') > (latest.updated_at ?? '')) latest = row\n }\n return latest?.external_id ?? null\n}\n\n// --------------------------------------------------------------------------------------------- //\n// Bindings this browser kept before the server held them (`localStorage`), moved to the server\n// once (`migrateLegacyThreadDocuments` in `./thread-binding`) and then forgotten.\n// --------------------------------------------------------------------------------------------- //\n\nexport const LEGACY_THREAD_DOCUMENTS_KEY = 'arbi-thread-documents'\n\nfunction storage(): Storage | undefined {\n try {\n return typeof localStorage === 'undefined' ? undefined : localStorage\n } catch {\n return undefined\n }\n}\n\n/** The bindings this browser kept locally (conversation id → document id); empty when none. */\nexport function readLegacyThreadDocuments(): Record<string, string> {\n const out: Record<string, string> = {}\n try {\n const parsed = JSON.parse(storage()?.getItem(LEGACY_THREAD_DOCUMENTS_KEY) ?? 'null') as unknown\n if (parsed && typeof parsed === 'object')\n for (const [conversationId, documentId] of Object.entries(parsed))\n if (typeof documentId === 'string') out[conversationId] = documentId\n } catch {\n // Damaged or blocked: nothing to move.\n }\n return out\n}\n\n/** Forget locally kept bindings (moved to the server); the key goes with the last of them. */\nexport function forgetLegacyThreadDocuments(conversationIds: readonly string[]): void {\n if (conversationIds.length === 0) return\n const rest = readLegacyThreadDocuments()\n conversationIds.forEach((id) => delete rest[id])\n try {\n if (Object.keys(rest).length === 0) storage()?.removeItem(LEGACY_THREAD_DOCUMENTS_KEY)\n else storage()?.setItem(LEGACY_THREAD_DOCUMENTS_KEY, JSON.stringify(rest))\n } catch {\n // Blocked: nothing more to do.\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { arbiMutationKeys, arbiQueryKeys } from './chunk-PBXJFMES.js';
2
- import { useArbi } from './chunk-KGCGA452.js';
2
+ import { useArbi } from './chunk-MB34NKBZ.js';
3
3
  import { create } from 'zustand';
4
4
  import { useCallback, useSyncExternalStore } from 'react';
5
5
  import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
@@ -528,5 +528,5 @@ function adjustTagCounts(qc, workspaceId, delta) {
528
528
  }
529
529
 
530
530
  export { DOCUMENTS_FIRST_PAGE_MEASURE, DOCUMENTS_FIRST_PAGE_SIZE, DOCUMENTS_PAGE_SIZE, FINISHED_DOCUMENT_STATUSES, IN_FLIGHT_DOCUMENT_STATUSES, SIMILARITY_THRESHOLD, adjustTagCounts, dropTagFromCachedDocuments, finishEntityExtraction, forgetDocuments, getCachedDocuments, invalidateTagData, invalidateTagTables, isDocumentsLoading, isRowNewer, isStaleTaskUpdate, patchCachedDocument, patchDocuments, patchWorkspaceTags, refreshDocuments, replayableTagMutations, resolveDocumentStatus, setCachedDocument, settledByRows, startEntityExtraction, stopDocumentsLoading, subscribeDocumentRows, upsertDocuments, useCreateTag, useDeleteTag, useDocument, useDocuments, useDocumentsById, useDocumentsLoading, useEntityExtractionDocIds, useExtractEntities, useInvalidateTagData, useIsCreatingTag, useSetTagValues, useSimilarDocuments, useTagKindSchema, useUpdateTag, useUpdateTagKindSchema };
531
- //# sourceMappingURL=chunk-MQ7LZWGP.js.map
532
- //# sourceMappingURL=chunk-MQ7LZWGP.js.map
531
+ //# sourceMappingURL=chunk-VHGJG32Q.js.map
532
+ //# sourceMappingURL=chunk-VHGJG32Q.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/documents/documents-cache.ts","../src/entity-extraction.ts","../src/tags.ts","../src/documents/documents-loader.ts","../src/documents/processing-order.ts","../src/documents/documents-data.ts"],"names":["update","tagOps","controller","openWorkspaceId","useQueryClient","useQuery"],"mappings":"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","file":"chunk-MQ7LZWGP.js","sourcesContent":["/**\n * The workspace documents list in the query cache: one entry per workspace\n * (`arbiQueryKeys.documents(workspaceId)`), read once (progressively, see `documents-loader.ts`)\n * and then kept current in place. Every write goes through {@link patchDocuments}, which also\n * tells row listeners (a grid that applies row transactions instead of re-diffing the whole list)\n * exactly which rows were added, changed or removed.\n *\n * A single document's own entry (`arbiQueryKeys.document(id)`, read by a viewer) is patched next to\n * the list by {@link setCachedDocument}, so a viewer never blanks while a write settles.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { components } from '@arbidocs/client'\nimport { arbiQueryKeys } from '../hooks'\n\n/** A document as the server lists it. */\nexport type WorkspaceDocument = components['schemas']['DocResponse']\n\n/** The rows one write added, changed and removed (removed: by id). */\nexport interface DocumentRowChange {\n workspaceId: string\n add: WorkspaceDocument[]\n update: WorkspaceDocument[]\n remove: string[]\n}\n\ntype RowListener = (change: DocumentRowChange) => void\n\nconst rowListeners = new Set<RowListener>()\n\n/**\n * Follow the row-level changes of every write to a workspace documents list (a grid applying them\n * as transactions). Returns the unsubscribe.\n */\nexport function subscribeDocumentRows(listener: RowListener): () => void {\n rowListeners.add(listener)\n return () => {\n rowListeners.delete(listener)\n }\n}\n\n/** The cached documents of a workspace (`undefined` before its list has been read). */\nexport function getCachedDocuments(\n qc: QueryClient,\n workspaceId: string | null | undefined\n): WorkspaceDocument[] | undefined {\n if (!workspaceId) return undefined\n return qc.getQueryData<WorkspaceDocument[]>(arbiQueryKeys.documents(workspaceId))\n}\n\n/** Every cached workspace documents list, with its workspace. */\nfunction cachedLists(qc: QueryClient): Array<[string, WorkspaceDocument[]]> {\n return qc\n .getQueriesData<WorkspaceDocument[]>({ queryKey: arbiQueryKeys.allDocuments() })\n .flatMap(([key, data]) =>\n typeof key[2] === 'string' && Array.isArray(data) ? [[key[2], data]] : []\n )\n}\n\n/** Diff two versions of a list by id. */\nfunction diffRows(\n workspaceId: string,\n before: WorkspaceDocument[],\n after: WorkspaceDocument[]\n): DocumentRowChange {\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n const add: WorkspaceDocument[] = []\n const update: WorkspaceDocument[] = []\n const seen = new Set<string>()\n for (const doc of after) {\n seen.add(doc.external_id)\n const previous = beforeById.get(doc.external_id)\n if (!previous) add.push(doc)\n else if (previous !== doc) update.push(doc)\n }\n const remove = [...beforeById.keys()].filter((id) => !seen.has(id))\n return { workspaceId, add, update, remove }\n}\n\n/**\n * Apply `reducer` to a workspace's documents list, or (no `workspaceId`) to every cached one: the\n * one place a list is written after it was read. Returning the same array is a no-op. Row\n * listeners get the diff; a document that moved to a new version makes the open version lists\n * re-read. A workspace whose list has not been read is left alone (its first read brings it).\n */\nexport function patchDocuments(\n qc: QueryClient,\n reducer: (documents: WorkspaceDocument[]) => WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n const lists: Array<[string, WorkspaceDocument[]]> = workspaceId\n ? (() => {\n const current = getCachedDocuments(qc, workspaceId)\n return current ? [[workspaceId, current] as [string, WorkspaceDocument[]]] : []\n })()\n : cachedLists(qc)\n for (const [id, before] of lists) {\n const after = reducer(before)\n if (after === before) continue\n qc.setQueryData(arbiQueryKeys.documents(id), after)\n const change = diffRows(id, before, after)\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n if (\n change.update.some(\n (doc) => doc.current_version !== beforeById.get(doc.external_id)?.current_version\n )\n )\n void qc.invalidateQueries({ queryKey: arbiQueryKeys.allDocumentVersions() })\n if (change.add.length || change.update.length || change.remove.length)\n for (const listener of rowListeners) listener(change)\n }\n}\n\n/** Put `doc` in its list in place, or at the end when the list does not hold it yet. */\nexport function upsertDocuments(\n qc: QueryClient,\n documents: WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n if (!documents.length) return\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const byWorkspace = new Map<string, WorkspaceDocument[]>()\n for (const doc of documents) {\n const ws = workspaceId ?? doc.workspace_ext_id\n byWorkspace.set(ws, [...(byWorkspace.get(ws) ?? []), doc])\n }\n for (const [ws, incoming] of byWorkspace) {\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n return [\n ...old.map((doc) => byId.get(doc.external_id) ?? doc),\n ...incoming.filter((doc) => !known.has(doc.external_id)),\n ]\n },\n ws\n )\n }\n}\n\n/** Write a document's own entry (what `useDocument` reads), keeping a viewer current. */\nexport function setCachedDocument(qc: QueryClient, doc: WorkspaceDocument): void {\n qc.setQueryData(arbiQueryKeys.document(doc.external_id), doc)\n}\n\n/** Apply `reducer` to a document's own entry, when one is cached. */\nexport function patchCachedDocument(\n qc: QueryClient,\n docId: string,\n reducer: (doc: WorkspaceDocument) => WorkspaceDocument\n): void {\n const current = qc.getQueryData<WorkspaceDocument | null>(arbiQueryKeys.document(docId))\n if (current) qc.setQueryData(arbiQueryKeys.document(docId), reducer(current))\n}\n\n/** A deleted tag leaves every cached document that carried it: the lists' rows and their entries. */\nexport function dropTagFromCachedDocuments(qc: QueryClient, tagId: string): void {\n const strip = (doc: WorkspaceDocument): WorkspaceDocument => {\n const doctags = doc.doctags?.filter((dt) => dt.tag_ext_id !== tagId)\n return doctags && doctags.length !== doc.doctags?.length ? { ...doc, doctags } : doc\n }\n const carriers: string[] = []\n patchDocuments(qc, (docs) => {\n const next = docs.map(strip)\n next.forEach((doc, i) => doc !== docs[i] && carriers.push(doc.external_id))\n return carriers.length ? next : docs\n })\n for (const id of carriers) patchCachedDocument(qc, id, strip)\n}\n\n/** Forget everything cached about deleted documents, so nothing re-reads them into a 404. */\nexport function forgetDocuments(qc: QueryClient, docIds: string[]): void {\n for (const id of docIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.document(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.documentVersions(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.parsedDocument(id) })\n }\n}\n","/**\n * The documents whose people and organisations are being found (`useExtractEntities`), from the\n * request until the live connection says the batch is done (`batch_complete`, `entity_extract`):\n * the package's WebSocket (`ArbiWebSocketProvider`) ends it, and a host on its own connection calls\n * `finishEntityExtraction` from its handler.\n */\n\nimport { create } from 'zustand'\n\nconst useEntityExtractionStore = create<{ docIds: readonly string[] }>(() => ({ docIds: [] }))\n\nfunction update(docIds: readonly string[], running: boolean): void {\n if (!docIds.length) return\n useEntityExtractionStore.setState((state) => {\n const ids = new Set(state.docIds)\n docIds.forEach((id) => (running ? ids.add(id) : ids.delete(id)))\n return { docIds: [...ids] }\n })\n}\n\n/** The documents an extraction was started on are running. */\nexport function startEntityExtraction(docIds: readonly string[]): void {\n update(docIds, true)\n}\n\n/** The extraction of these documents is done. */\nexport function finishEntityExtraction(docIds: readonly string[]): void {\n update(docIds, false)\n}\n\n/** The documents being extracted now. */\nexport function useEntityExtractionDocIds(): readonly string[] {\n return useEntityExtractionStore((state) => state.docIds)\n}\n","/**\n * Tags: the open workspace's tag list (`useTags()`), the writes (create, update, delete, values,\n * entity extraction), and tag kinds — a kind's fields in the workspace are the columns of a table\n * of its tags (`useTagKindSchema('issue')`), whose rows are the tag list filtered by kind with\n * links (`useTags(workspaceId, { kind, include })`).\n *\n * Everything is cached under the workspace's tags (`arbiQueryKeys.tags`). The whole list is kept\n * current in place: every write here patches it ({@link patchWorkspaceTags}, which a host also\n * uses for its own writes that move a tag's counts, e.g. applying it to documents) and refreshes\n * the filtered lists (the tables). Anything that invalidates the workspace's tags (a document batch\n * finishing, {@link useInvalidateTagData} after a doctag or fact change) refreshes them all.\n *\n * Creating a tag can be queued while offline and replayed after a reload: see `offline.ts`.\n *\n * Requires an `ArbiHost` (with an `arbi`) and a React Query client above it.\n */\n\nimport { useCallback } from 'react'\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { ArbiClient } from '@arbidocs/client'\nimport {\n tags as tagOps,\n type TagChange,\n type TagFieldDefinition,\n type TagKind,\n type TagKindSchema,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport { dropTagFromCachedDocuments } from './documents/documents-cache'\nimport { startEntityExtraction } from './entity-extraction'\nimport { arbiMutationKeys, arbiQueryKeys } from './hooks'\n\n/** The workspace open on `arbi`, or `null` (`getWorkspaceId()` throws when none is open). */\nfunction openWorkspaceId(arbi: ReturnType<typeof useArbi>): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * Apply `reducer` to a workspace's cached tag list (nothing cached: nothing to do). The list is\n * read once, then kept current by these patches; a host's own write that changes a tag (applying\n * it to documents moves its `doctag_count`) patches it here too.\n */\nexport function patchWorkspaceTags(\n qc: QueryClient,\n workspaceId: string,\n reducer: (tags: TagResponse[]) => TagResponse[]\n): void {\n const key = arbiQueryKeys.tags(workspaceId)\n const current = qc.getQueryData<TagResponse[]>(key)\n if (!current) return\n const next = reducer(current)\n if (next !== current) qc.setQueryData(key, next)\n}\n\n/** Refetch a workspace's tables of tags (its filtered lists), not the whole list. */\nexport function invalidateTagTables(qc: QueryClient, workspaceId: string): Promise<void> {\n return qc.invalidateQueries({ queryKey: arbiQueryKeys.tagLists(workspaceId) })\n}\n\n/** Refresh what a tag, doctag or fact change affects: the workspace's tags, tables and facts. */\nexport function invalidateTagData(qc: QueryClient, workspaceId: string): Promise<unknown> {\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.tags(workspaceId) }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n}\n\n/** {@link invalidateTagData} for the open workspace: call it after a doctag or fact write. */\nexport function useInvalidateTagData(): () => Promise<unknown> {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useCallback(() => {\n const workspaceId = openWorkspaceId(arbi)\n return workspaceId ? invalidateTagData(qc, workspaceId) : Promise.resolve()\n }, [arbi, qc])\n}\n\n/** What a new tag is: its name, and optionally kind, format, parent, values, sharing. */\nexport type CreateTagInput = Omit<Parameters<typeof tagOps.createTag>[1], 'workspaceId'>\n\n/** A created tag joins its workspace's list; the tables re-read. */\nfunction settleCreatedTag(qc: QueryClient, created: TagResponse): Promise<void> {\n const workspaceId = created.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.some((t) => t.external_id === created.external_id) ? old : [...old, created]\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/** A changed tag replaces its entry in the list; the tables re-read. */\nfunction settleChangedTag(qc: QueryClient, tag: TagResponse): Promise<void> {\n const workspaceId = tag.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.map((t) => (t.external_id === tag.external_id ? { ...t, ...tag } : t))\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/**\n * The tag writes a host may queue while offline and replay after a reload (`offline.ts`): each\n * key's request on a bare client, and what its success does to the cache.\n */\nexport const replayableTagMutations = [\n {\n mutationKey: arbiMutationKeys.createTag(),\n run: (client: ArbiClient, input: CreateTagInput) => tagOps.createTag(client, input),\n settle: (qc: QueryClient, created: TagResponse) => settleCreatedTag(qc, created),\n },\n] as const\n\n/**\n * Create a tag in the open workspace (`{ name, kind: 'issue' }`, `{ name, parentId }`, …): it is\n * added to the tag list and the tables re-read. Resolves with the new tag. Offline it is held and\n * sent on reconnect (a host that registers `registerArbiMutationDefaults` keeps it across reloads).\n */\nexport function useCreateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.createTag(),\n mutationFn: (input: CreateTagInput): Promise<TagResponse> => arbi.tags.create(input),\n onSuccess: (created) => settleCreatedTag(qc, created),\n })\n}\n\n/**\n * Whether a tag of this name (any case) is being created right now: a second create of the same\n * name (a double Enter) is skipped instead of making a duplicate.\n */\nexport function useIsCreatingTag(): (name: string) => boolean {\n const qc = useQueryClient()\n return useCallback(\n (name: string) => {\n const wanted = name.trim().toLowerCase()\n return (\n qc.getMutationCache().findAll({\n mutationKey: arbiMutationKeys.createTag(),\n predicate: (m) =>\n m.state.status === 'pending' &&\n (m.state.variables as CreateTagInput | undefined)?.name.trim().toLowerCase() === wanted,\n }).length > 0\n )\n },\n [qc]\n )\n}\n\n/** Change a tag (name, format, instruction, parent, sharing, values): patched in the list. */\nexport function useUpdateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({ tagId, change }: { tagId: string; change: TagChange }): Promise<TagResponse> =>\n arbi.tags.update(tagId, change),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/** Merge-patch a tag's values for its kind's fields (`null` clears one); its tables refresh. */\nexport function useSetTagValues() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({\n tagId,\n values,\n }: {\n tagId: string\n values: Record<string, unknown>\n }): Promise<TagResponse> => arbi.tags.setValues(tagId, values),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/**\n * Delete a tag: it leaves the list (its sub-tags move to the top level on the server, so the list\n * re-reads them), and the tables and facts re-read. A host that shows the tag on its own items\n * (documents' tags) follows `arbiMutationKeys.deleteTag()` to drop it there.\n */\nexport function useDeleteTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.deleteTag(),\n mutationFn: (tagId: string) => arbi.tags.delete(tagId),\n onSuccess: (_data, tagId) => {\n // Its pills come off the documents grid in place (and off any open document).\n dropTagFromCachedDocuments(qc, tagId)\n const workspaceId = openWorkspaceId(arbi)\n if (!workspaceId) return\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old\n .filter((t) => t.external_id !== tagId)\n .map((t) => (t.parent_ext_id === tagId ? { ...t, parent_ext_id: null } : t))\n )\n return Promise.all([\n invalidateTagTables(qc, workspaceId),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n },\n })\n}\n\n/**\n * Find the people and organisations documents name and link each to its entity tag. Accepted at\n * once with the documents' ids, which show as running (`useEntityExtractionDocIds`) until a\n * `batch_complete` (`entity_extract`) WebSocket message says they are done.\n */\nexport function useExtractEntities() {\n const arbi = useArbi()\n return useMutation({\n mutationKey: arbiMutationKeys.extractEntities(),\n mutationFn: (docIds: string[]) => arbi.tags.extractEntities(docIds),\n onSuccess: (data) => startEntityExtraction(data.doc_ext_ids),\n })\n}\n\n/**\n * A kind's fields in the open workspace (`'issue'`: its issue fields): the columns of a table of\n * that kind's tags. The built-in ones (`is_default`) until the workspace sets its own.\n */\nexport function useTagKindSchema(\n kind: TagKind | null | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const workspaceId = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.tagKind(workspaceId, kind ?? ''),\n queryFn: (): Promise<TagKindSchema> =>\n arbi.readInWorkspace(workspaceId, () => arbi.tagKinds.get(kind as TagKind)),\n enabled: (options?.enabled ?? true) && !!kind && !!workspaceId,\n })\n}\n\n/**\n * Set a kind's fields in full (a field with its `id` keeps its values; one without is new; one\n * left out is removed). The kind's schema and the workspace's tags refresh.\n */\nexport function useUpdateTagKindSchema() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTagKindSchema(),\n mutationFn: ({\n kind,\n fields,\n }: {\n kind: TagKind\n fields: TagFieldDefinition[]\n }): Promise<TagKindSchema> => arbi.tagKinds.update(kind, fields),\n onSuccess: (schema) => {\n const workspaceId = openWorkspaceId(arbi)\n if (!workspaceId) return\n qc.setQueryData(arbiQueryKeys.tagKind(workspaceId, schema.kind), schema)\n return invalidateTagData(qc, workspaceId)\n },\n })\n}\n","/**\n * Reading a workspace's documents progressively: the first page is the query's result, so the\n * list shows within a few hundred milliseconds even for 100k documents, and the remaining pages\n * are appended to the same cache entry in the background as they arrive. One background read per\n * workspace; opening another workspace stops the previous one. Whether a background read is\n * running is observable ({@link useDocumentsLoading}), for a \"still loading\" indicator.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { patchDocuments, type WorkspaceDocument } from './documents-cache'\n\n/** First page: small, so rows are on screen in a few hundred ms even in a large workspace. */\nexport const DOCUMENTS_FIRST_PAGE_SIZE = 500\n\n/** Later pages: larger, fewer round trips (the server caps a page at 10 000). */\nexport const DOCUMENTS_PAGE_SIZE = 2000\n\n/**\n * The time to the first page, as a `performance` measure of this name (a host reporting\n * performance can observe it).\n */\nexport const DOCUMENTS_FIRST_PAGE_MEASURE = 'arbi:document-list:page1'\nconst FIRST_PAGE_MEASURE = DOCUMENTS_FIRST_PAGE_MEASURE\nconst FIRST_PAGE_START = 'arbi:document-list:start'\n\nfunction mark(name: string): void {\n try {\n performance.mark(name)\n } catch {\n // No performance timeline here (an old runtime, a test): nothing to record.\n }\n}\n\nfunction measure(name: string, start: string): void {\n try {\n performance.measure(name, start)\n } catch {\n // The start mark is missing: nothing to record.\n }\n}\n\nconst backgroundReads = new Map<string, AbortController>()\nconst loadingListeners = new Set<() => void>()\n\nfunction emitLoading(): void {\n for (const listener of loadingListeners) listener()\n}\n\nfunction subscribeLoading(listener: () => void): () => void {\n loadingListeners.add(listener)\n return () => {\n loadingListeners.delete(listener)\n }\n}\n\n/** Whether a workspace's remaining document pages are being read in the background. */\nexport function isDocumentsLoading(): boolean {\n return backgroundReads.size > 0\n}\n\n/** True while the remaining pages of a documents list are still arriving. */\nexport function useDocumentsLoading(): boolean {\n return useSyncExternalStore(subscribeLoading, isDocumentsLoading, () => false)\n}\n\n/** Stop a workspace's background read (closing the workspace). */\nexport function stopDocumentsLoading(workspaceId: string): void {\n const controller = backgroundReads.get(workspaceId)\n if (!controller) return\n controller.abort()\n backgroundReads.delete(workspaceId)\n emitLoading()\n}\n\n/**\n * Read a workspace's documents: resolves with the first page and appends the rest to\n * `arbiQueryKeys.documents(workspaceId)` in the background. The query function of `useDocuments`.\n */\nexport async function loadDocuments(\n qc: QueryClient,\n arbi: Arbi,\n workspaceId: string,\n signal?: AbortSignal\n): Promise<WorkspaceDocument[]> {\n let stopped = false\n for (const [id, controller] of backgroundReads) {\n if (id === workspaceId) continue\n controller.abort()\n backgroundReads.delete(id)\n stopped = true\n }\n if (stopped) emitLoading()\n\n const controller = new AbortController()\n signal?.addEventListener('abort', () => controller.abort(), { once: true })\n // Named, not the session's open workspace: the pages are this workspace's whatever the server\n // session is in, so a list read across a workspace switch can never be another's.\n const pages = arbi.documents.listPaginated({\n workspaceId,\n pageSize: DOCUMENTS_PAGE_SIZE,\n firstPageSize: DOCUMENTS_FIRST_PAGE_SIZE,\n signal: controller.signal,\n })\n mark(FIRST_PAGE_START)\n const first = await pages.next()\n const firstPage = first.done ? [] : first.value\n measure(FIRST_PAGE_MEASURE, FIRST_PAGE_START)\n if (first.done || firstPage.length < DOCUMENTS_FIRST_PAGE_SIZE) return firstPage\n if (backgroundReads.has(workspaceId)) {\n controller.abort()\n return firstPage\n }\n\n backgroundReads.set(workspaceId, controller)\n emitLoading()\n void appendRemainingPages(qc, workspaceId, pages, controller.signal).finally(() => {\n if (backgroundReads.get(workspaceId) !== controller) return\n backgroundReads.delete(workspaceId)\n emitLoading()\n })\n return firstPage\n}\n\nasync function appendRemainingPages(\n qc: QueryClient,\n workspaceId: string,\n pages: AsyncGenerator<WorkspaceDocument[]>,\n signal: AbortSignal\n): Promise<void> {\n // Let the query store the first page before the second is appended to it.\n await Promise.resolve()\n try {\n for await (const page of pages) {\n if (signal.aborted) return\n // A write may already have added some of these (an upload finishing meanwhile).\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n const fresh = page.filter((doc) => !known.has(doc.external_id))\n return fresh.length ? [...old, ...fresh] : old\n },\n workspaceId\n )\n }\n } catch (error) {\n if (!signal.aborted) console.error(`Reading the documents of ${workspaceId} failed:`, error)\n }\n}\n\n/** Test-only: stop every background read. @internal */\nexport function resetDocumentsLoadingForTests(): void {\n for (const controller of backgroundReads.values()) controller.abort()\n backgroundReads.clear()\n emitLoading()\n}\n","/**\n * Which is newer: a document's live processing status or its row as last read?\n *\n * Every `task_update` carries `seq`, taken by the server from one sequence for all documents and\n * all of its instances, so a higher seq is a later event however the events arrive. A document row\n * carries `status_seq`: the seq of the last time its processing ended (a finished status written or\n * broadcast). The two compare:\n * - an event at or below the seq of the one already held is stale (overtaken), and is dropped;\n * - a row whose `status_seq` is above the live status's seq finished after it: the live status is\n * over (its final event was lost), and the row wins;\n * - a live status above the row's `status_seq` is newer than the row: the document is being\n * processed again (AI fields being filled) although the row still says it finished.\n *\n * Without the seqs (an optimistic \"queued\" set here, a server before them) the older rule stands:\n * a live in-flight status wins, then a finished row, then whatever was heard live.\n */\n\n/** Statuses after which a document's processing is over (`low-content`: indexed, little text). */\nexport const FINISHED_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'completed',\n 'low-content',\n 'failed',\n 'skipped',\n 'empty',\n])\n\n/** A live processing status and its order (`task_update.seq`). */\nexport interface SequencedTask {\n status: string\n seq?: number | null\n}\n\n/** A document row's status and the order of its last finished status (`status_seq`). */\nexport interface SequencedRow {\n status?: string | null\n status_seq?: number | null\n}\n\n/** Statuses of a document still being processed. */\nexport const IN_FLIGHT_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'uploading',\n 'queued',\n 'parsing',\n 'encrypting',\n 'indexing',\n 'analysing',\n])\n\nfunction ordered(value: number | null | undefined): value is number {\n return typeof value === 'number'\n}\n\n/** Whether `next` is older than (or the same event as) the live status already held. */\nexport function isStaleTaskUpdate(held: SequencedTask | undefined, next: SequencedTask): boolean {\n return !!held && ordered(held.seq) && ordered(next.seq) && next.seq <= held.seq\n}\n\n/**\n * Whether the row is newer than the live status: `true` / `false` when both are ordered, `undefined`\n * when they cannot be compared.\n */\nexport function isRowNewer(row: SequencedRow, task: SequencedTask): boolean | undefined {\n if (!ordered(row.status_seq) || !ordered(task.seq)) return undefined\n return row.status_seq > task.seq\n}\n\n/** The status a document shows now: its row's, or the live one when that is newer. */\nexport function resolveDocumentStatus(row: SequencedRow, task: SequencedTask | undefined): string {\n const rowStatus = (row.status ?? '').toLowerCase()\n const live = task?.status\n if (!task || !live) return rowStatus\n const rowNewer = isRowNewer(row, task)\n if (rowNewer !== undefined) return rowNewer ? rowStatus || live : live\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(live)) return live\n if (FINISHED_DOCUMENT_STATUSES.has(rowStatus)) return rowStatus\n return live\n}\n\n/**\n * The live statuses a read of `rows` ends: each in-flight one whose row has since finished. Ordered,\n * the row must be newer (so a reprocess the row predates keeps its progress); unordered, a finished\n * row is enough (the older rule). Returns each such task with the row's status and order. Cheap when\n * nothing is in flight (it runs on every read of a list).\n */\nexport function settledByRows<T extends SequencedTask & { doc_ext_id: string }>(\n tasks: Readonly<Record<string, T>>,\n rows: ReadonlyArray<SequencedRow & { external_id: string }>\n): T[] {\n const inFlight = new Map<string, T>()\n for (const task of Object.values(tasks))\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(task.status)) inFlight.set(task.doc_ext_id, task)\n if (!inFlight.size) return []\n const settled: T[] = []\n for (const row of rows) {\n const task = inFlight.get(row.external_id)\n if (!task) continue\n const rowStatus = (row.status ?? '').toLowerCase()\n if (!FINISHED_DOCUMENT_STATUSES.has(rowStatus) || isRowNewer(row, task) === false) continue\n settled.push({ ...task, status: rowStatus, seq: row.status_seq ?? task.seq })\n }\n return settled\n}\n","/**\n * Reading documents: a workspace's list (`useDocuments`, progressive, read once and then patched in\n * place), one document (`useDocument`, for a viewer), a set of documents by id, near-duplicate pairs\n * (`useSimilarDocuments`), and {@link refreshDocuments}, which re-reads just the documents an event\n * named and patches them into every cache that shows them.\n */\n\nimport { useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { invalidateTagTables, patchWorkspaceTags } from '../tags'\nimport {\n getCachedDocuments,\n setCachedDocument,\n upsertDocuments,\n type WorkspaceDocument,\n} from './documents-cache'\nimport { loadDocuments } from './documents-loader'\nimport { FINISHED_DOCUMENT_STATUSES, isRowNewer, type SequencedTask } from './processing-order'\n\nexport { FINISHED_DOCUMENT_STATUSES }\n\n/** The workspace open on `arbi`, or `null`. */\nfunction openWorkspaceId(arbi: Arbi): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * A workspace's documents (default: the open one). Read progressively: the first page is the\n * result, the remaining pages arrive in the background (`useDocumentsLoading`). After that the list\n * is never re-read on its own (mounting, focus, reconnecting): writes, processing events and\n * {@link refreshDocuments} patch it in place, as re-reading 100k documents is slow and tells\n * nothing new. Invalidating it re-reads it.\n */\nexport function useDocuments(workspaceId?: string | null, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const qc = useQueryClient()\n const workspace = workspaceId ?? openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspace),\n queryFn: ({ signal }) => {\n if (openWorkspaceId(arbi) !== workspace)\n return Promise.reject(new Error('The selected workspace changed.'))\n return loadDocuments(qc, arbi, workspace, signal)\n },\n enabled: (options?.enabled ?? true) && !!workspace && arbi.hasWorkspace,\n staleTime: Infinity,\n refetchOnMount: false,\n refetchOnReconnect: false,\n refetchOnWindowFocus: false,\n })\n}\n\n/** How often a document still being processed is re-read (`useDocument`'s `pollWhileProcessing`). */\nexport const DOCUMENT_STATUS_POLL_MS = 4000\n\n/** Re-read a document while it is processing (a viewer waiting for its pages). */\nfunction processingInterval(doc: WorkspaceDocument | null | undefined): number | false {\n return doc?.status && !FINISHED_DOCUMENT_STATUSES.has(doc.status)\n ? DOCUMENT_STATUS_POLL_MS\n : false\n}\n\n/**\n * One document (`null`: not found or not visible). `pollWhileProcessing` re-reads it every few\n * seconds until its processing is over. Writes here keep it current.\n */\nexport function useDocument(\n docId: string | null | undefined,\n options?: { enabled?: boolean; pollWhileProcessing?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.document(docId ?? ''),\n queryFn: async (): Promise<WorkspaceDocument | null> =>\n (await arbi.documents.get([docId as string]))[0] ?? null,\n enabled: (options?.enabled ?? true) && !!docId && arbi.isLoggedIn,\n refetchInterval: options?.pollWhileProcessing\n ? (query) => processingInterval(query.state.data)\n : false,\n })\n}\n\n/** Several documents by id, in one request (cited documents, a selection from elsewhere). */\nexport function useDocumentsById(docIds: string[], options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.documentsById(docIds),\n queryFn: () => arbi.documents.get(docIds),\n enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.isLoggedIn,\n })\n}\n\n/**\n * The similarity at or above which two documents count as near duplicates (the Related column).\n * The server keeps every pair above 0.75 but returns only those at or above what is asked.\n */\nexport const SIMILARITY_THRESHOLD = 0.98\n\n/** Near-duplicate document pairs in the open workspace, at or above {@link SIMILARITY_THRESHOLD}. */\nexport function useSimilarDocuments(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const workspace = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.similarDocuments(workspace, SIMILARITY_THRESHOLD),\n queryFn: () =>\n arbi.readInWorkspace(workspace, () =>\n arbi.documents.similar({ threshold: SIMILARITY_THRESHOLD })\n ),\n enabled: (options?.enabled ?? true) && !!workspace,\n })\n}\n\n// Each re-read gets a number; only the latest one issued for a document may write it. Events can\n// return out of order, and an older read must not undo tags a newer one applied.\nlet readSeq = 0\nconst latestReadByDoc = new Map<string, number>()\n\nexport interface RefreshDocumentsOptions {\n /** The processing the host last heard live for a document (`DocumentsSupport.processingTask`). */\n processingTask?: (docId: string) => SequencedTask | undefined\n}\n\n/**\n * Re-read `docIds` and patch them into the caches that show them: their workspace's list (added\n * when new), their own entries, and the tag list's document counts (tags the server applied, e.g.\n * AI fields). For events that name documents (a batch finished, a version saved, an upload): the\n * list is never re-read for them. A failed read leaves the caches as they were.\n */\nexport async function refreshDocuments(\n qc: QueryClient,\n arbi: Arbi,\n docIds: string[],\n options?: RefreshDocumentsOptions\n): Promise<WorkspaceDocument[]> {\n if (!docIds.length) return []\n const seq = ++readSeq\n for (const id of docIds) latestReadByDoc.set(id, seq)\n try {\n const read = await arbi.documents.get(docIds)\n const fresh = read\n .filter((doc) => latestReadByDoc.get(doc.external_id) === seq)\n .map((doc) => {\n // A finished status heard live wins over a read that predates it (the row may not be\n // committed yet), never over a row that finished after it.\n const live = options?.processingTask?.(doc.external_id)\n return live &&\n FINISHED_DOCUMENT_STATUSES.has(live.status) &&\n doc.status !== live.status &&\n isRowNewer(doc, live) !== true\n ? { ...doc, status: live.status }\n : doc\n })\n if (!fresh.length) return []\n reconcileTagCounts(qc, fresh)\n upsertDocuments(qc, fresh)\n for (const doc of fresh) setCachedDocument(qc, doc)\n return fresh\n } catch (error) {\n // Leave the caches as they were: re-reading the whole list would shrink it to its first page.\n console.error('Re-reading documents failed; the cached ones are kept:', error)\n return []\n } finally {\n for (const id of docIds) if (latestReadByDoc.get(id) === seq) latestReadByDoc.delete(id)\n }\n}\n\n/** Move each tag's document count by the tags the re-read documents gained or lost. */\nfunction reconcileTagCounts(qc: QueryClient, fresh: WorkspaceDocument[]): void {\n const byWorkspace = new Map<string, Map<string, number>>()\n for (const doc of fresh) {\n const cached = getCachedDocuments(qc, doc.workspace_ext_id)?.find(\n (d) => d.external_id === doc.external_id\n )\n const before = new Set((cached?.doctags ?? []).map((dt) => dt.tag_ext_id))\n const after = new Set((doc.doctags ?? []).map((dt) => dt.tag_ext_id))\n const delta = byWorkspace.get(doc.workspace_ext_id) ?? new Map<string, number>()\n for (const id of after) if (!before.has(id)) delta.set(id, (delta.get(id) ?? 0) + 1)\n for (const id of before) if (!after.has(id)) delta.set(id, (delta.get(id) ?? 0) - 1)\n byWorkspace.set(doc.workspace_ext_id, delta)\n }\n for (const [workspaceId, delta] of byWorkspace) adjustTagCounts(qc, workspaceId, delta)\n}\n\n/** Add `delta` (tag id → change) to the tags' document counts; the tag tables re-read. */\nexport function adjustTagCounts(\n qc: QueryClient,\n workspaceId: string,\n delta: Map<string, number>\n): void {\n if (![...delta.values()].some(Boolean)) return\n patchWorkspaceTags(qc, workspaceId, (tags) =>\n tags.map((tag) => {\n const change = delta.get(tag.external_id)\n return change ? { ...tag, doctag_count: Math.max(0, tag.doctag_count + change) } : tag\n })\n )\n void invalidateTagTables(qc, workspaceId)\n}\n"]}
1
+ {"version":3,"sources":["../src/documents/documents-cache.ts","../src/entity-extraction.ts","../src/tags.ts","../src/documents/documents-loader.ts","../src/documents/processing-order.ts","../src/documents/documents-data.ts"],"names":["update","tagOps","controller","openWorkspaceId","useQueryClient","useQuery"],"mappings":"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","file":"chunk-VHGJG32Q.js","sourcesContent":["/**\n * The workspace documents list in the query cache: one entry per workspace\n * (`arbiQueryKeys.documents(workspaceId)`), read once (progressively, see `documents-loader.ts`)\n * and then kept current in place. Every write goes through {@link patchDocuments}, which also\n * tells row listeners (a grid that applies row transactions instead of re-diffing the whole list)\n * exactly which rows were added, changed or removed.\n *\n * A single document's own entry (`arbiQueryKeys.document(id)`, read by a viewer) is patched next to\n * the list by {@link setCachedDocument}, so a viewer never blanks while a write settles.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { components } from '@arbidocs/client'\nimport { arbiQueryKeys } from '../hooks'\n\n/** A document as the server lists it. */\nexport type WorkspaceDocument = components['schemas']['DocResponse']\n\n/** The rows one write added, changed and removed (removed: by id). */\nexport interface DocumentRowChange {\n workspaceId: string\n add: WorkspaceDocument[]\n update: WorkspaceDocument[]\n remove: string[]\n}\n\ntype RowListener = (change: DocumentRowChange) => void\n\nconst rowListeners = new Set<RowListener>()\n\n/**\n * Follow the row-level changes of every write to a workspace documents list (a grid applying them\n * as transactions). Returns the unsubscribe.\n */\nexport function subscribeDocumentRows(listener: RowListener): () => void {\n rowListeners.add(listener)\n return () => {\n rowListeners.delete(listener)\n }\n}\n\n/** The cached documents of a workspace (`undefined` before its list has been read). */\nexport function getCachedDocuments(\n qc: QueryClient,\n workspaceId: string | null | undefined\n): WorkspaceDocument[] | undefined {\n if (!workspaceId) return undefined\n return qc.getQueryData<WorkspaceDocument[]>(arbiQueryKeys.documents(workspaceId))\n}\n\n/** Every cached workspace documents list, with its workspace. */\nfunction cachedLists(qc: QueryClient): Array<[string, WorkspaceDocument[]]> {\n return qc\n .getQueriesData<WorkspaceDocument[]>({ queryKey: arbiQueryKeys.allDocuments() })\n .flatMap(([key, data]) =>\n typeof key[2] === 'string' && Array.isArray(data) ? [[key[2], data]] : []\n )\n}\n\n/** Diff two versions of a list by id. */\nfunction diffRows(\n workspaceId: string,\n before: WorkspaceDocument[],\n after: WorkspaceDocument[]\n): DocumentRowChange {\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n const add: WorkspaceDocument[] = []\n const update: WorkspaceDocument[] = []\n const seen = new Set<string>()\n for (const doc of after) {\n seen.add(doc.external_id)\n const previous = beforeById.get(doc.external_id)\n if (!previous) add.push(doc)\n else if (previous !== doc) update.push(doc)\n }\n const remove = [...beforeById.keys()].filter((id) => !seen.has(id))\n return { workspaceId, add, update, remove }\n}\n\n/**\n * Apply `reducer` to a workspace's documents list, or (no `workspaceId`) to every cached one: the\n * one place a list is written after it was read. Returning the same array is a no-op. Row\n * listeners get the diff; a document that moved to a new version makes the open version lists\n * re-read. A workspace whose list has not been read is left alone (its first read brings it).\n */\nexport function patchDocuments(\n qc: QueryClient,\n reducer: (documents: WorkspaceDocument[]) => WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n const lists: Array<[string, WorkspaceDocument[]]> = workspaceId\n ? (() => {\n const current = getCachedDocuments(qc, workspaceId)\n return current ? [[workspaceId, current] as [string, WorkspaceDocument[]]] : []\n })()\n : cachedLists(qc)\n for (const [id, before] of lists) {\n const after = reducer(before)\n if (after === before) continue\n qc.setQueryData(arbiQueryKeys.documents(id), after)\n const change = diffRows(id, before, after)\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n if (\n change.update.some(\n (doc) => doc.current_version !== beforeById.get(doc.external_id)?.current_version\n )\n )\n void qc.invalidateQueries({ queryKey: arbiQueryKeys.allDocumentVersions() })\n if (change.add.length || change.update.length || change.remove.length)\n for (const listener of rowListeners) listener(change)\n }\n}\n\n/** Put `doc` in its list in place, or at the end when the list does not hold it yet. */\nexport function upsertDocuments(\n qc: QueryClient,\n documents: WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n if (!documents.length) return\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const byWorkspace = new Map<string, WorkspaceDocument[]>()\n for (const doc of documents) {\n const ws = workspaceId ?? doc.workspace_ext_id\n byWorkspace.set(ws, [...(byWorkspace.get(ws) ?? []), doc])\n }\n for (const [ws, incoming] of byWorkspace) {\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n return [\n ...old.map((doc) => byId.get(doc.external_id) ?? doc),\n ...incoming.filter((doc) => !known.has(doc.external_id)),\n ]\n },\n ws\n )\n }\n}\n\n/** Write a document's own entry (what `useDocument` reads), keeping a viewer current. */\nexport function setCachedDocument(qc: QueryClient, doc: WorkspaceDocument): void {\n qc.setQueryData(arbiQueryKeys.document(doc.external_id), doc)\n}\n\n/** Apply `reducer` to a document's own entry, when one is cached. */\nexport function patchCachedDocument(\n qc: QueryClient,\n docId: string,\n reducer: (doc: WorkspaceDocument) => WorkspaceDocument\n): void {\n const current = qc.getQueryData<WorkspaceDocument | null>(arbiQueryKeys.document(docId))\n if (current) qc.setQueryData(arbiQueryKeys.document(docId), reducer(current))\n}\n\n/** A deleted tag leaves every cached document that carried it: the lists' rows and their entries. */\nexport function dropTagFromCachedDocuments(qc: QueryClient, tagId: string): void {\n const strip = (doc: WorkspaceDocument): WorkspaceDocument => {\n const doctags = doc.doctags?.filter((dt) => dt.tag_ext_id !== tagId)\n return doctags && doctags.length !== doc.doctags?.length ? { ...doc, doctags } : doc\n }\n const carriers: string[] = []\n patchDocuments(qc, (docs) => {\n const next = docs.map(strip)\n next.forEach((doc, i) => doc !== docs[i] && carriers.push(doc.external_id))\n return carriers.length ? next : docs\n })\n for (const id of carriers) patchCachedDocument(qc, id, strip)\n}\n\n/** Forget everything cached about deleted documents, so nothing re-reads them into a 404. */\nexport function forgetDocuments(qc: QueryClient, docIds: string[]): void {\n for (const id of docIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.document(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.documentVersions(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.parsedDocument(id) })\n }\n}\n","/**\n * The documents whose people and organisations are being found (`useExtractEntities`), from the\n * request until the live connection says the batch is done (`batch_complete`, `entity_extract`):\n * the package's WebSocket (`ArbiWebSocketProvider`) ends it, and a host on its own connection calls\n * `finishEntityExtraction` from its handler.\n */\n\nimport { create } from 'zustand'\n\nconst useEntityExtractionStore = create<{ docIds: readonly string[] }>(() => ({ docIds: [] }))\n\nfunction update(docIds: readonly string[], running: boolean): void {\n if (!docIds.length) return\n useEntityExtractionStore.setState((state) => {\n const ids = new Set(state.docIds)\n docIds.forEach((id) => (running ? ids.add(id) : ids.delete(id)))\n return { docIds: [...ids] }\n })\n}\n\n/** The documents an extraction was started on are running. */\nexport function startEntityExtraction(docIds: readonly string[]): void {\n update(docIds, true)\n}\n\n/** The extraction of these documents is done. */\nexport function finishEntityExtraction(docIds: readonly string[]): void {\n update(docIds, false)\n}\n\n/** The documents being extracted now. */\nexport function useEntityExtractionDocIds(): readonly string[] {\n return useEntityExtractionStore((state) => state.docIds)\n}\n","/**\n * Tags: the open workspace's tag list (`useTags()`), the writes (create, update, delete, values,\n * entity extraction), and tag kinds — a kind's fields in the workspace are the columns of a table\n * of its tags (`useTagKindSchema('issue')`), whose rows are the tag list filtered by kind with\n * links (`useTags(workspaceId, { kind, include })`).\n *\n * Everything is cached under the workspace's tags (`arbiQueryKeys.tags`). The whole list is kept\n * current in place: every write here patches it ({@link patchWorkspaceTags}, which a host also\n * uses for its own writes that move a tag's counts, e.g. applying it to documents) and refreshes\n * the filtered lists (the tables). Anything that invalidates the workspace's tags (a document batch\n * finishing, {@link useInvalidateTagData} after a doctag or fact change) refreshes them all.\n *\n * Creating a tag can be queued while offline and replayed after a reload: see `offline.ts`.\n *\n * Requires an `ArbiHost` (with an `arbi`) and a React Query client above it.\n */\n\nimport { useCallback } from 'react'\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { ArbiClient } from '@arbidocs/client'\nimport {\n tags as tagOps,\n type TagChange,\n type TagFieldDefinition,\n type TagKind,\n type TagKindSchema,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport { dropTagFromCachedDocuments } from './documents/documents-cache'\nimport { startEntityExtraction } from './entity-extraction'\nimport { arbiMutationKeys, arbiQueryKeys } from './hooks'\n\n/** The workspace open on `arbi`, or `null` (`getWorkspaceId()` throws when none is open). */\nfunction openWorkspaceId(arbi: ReturnType<typeof useArbi>): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * Apply `reducer` to a workspace's cached tag list (nothing cached: nothing to do). The list is\n * read once, then kept current by these patches; a host's own write that changes a tag (applying\n * it to documents moves its `doctag_count`) patches it here too.\n */\nexport function patchWorkspaceTags(\n qc: QueryClient,\n workspaceId: string,\n reducer: (tags: TagResponse[]) => TagResponse[]\n): void {\n const key = arbiQueryKeys.tags(workspaceId)\n const current = qc.getQueryData<TagResponse[]>(key)\n if (!current) return\n const next = reducer(current)\n if (next !== current) qc.setQueryData(key, next)\n}\n\n/** Refetch a workspace's tables of tags (its filtered lists), not the whole list. */\nexport function invalidateTagTables(qc: QueryClient, workspaceId: string): Promise<void> {\n return qc.invalidateQueries({ queryKey: arbiQueryKeys.tagLists(workspaceId) })\n}\n\n/** Refresh what a tag, doctag or fact change affects: the workspace's tags, tables and facts. */\nexport function invalidateTagData(qc: QueryClient, workspaceId: string): Promise<unknown> {\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.tags(workspaceId) }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n}\n\n/** {@link invalidateTagData} for the open workspace: call it after a doctag or fact write. */\nexport function useInvalidateTagData(): () => Promise<unknown> {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useCallback(() => {\n const workspaceId = openWorkspaceId(arbi)\n return workspaceId ? invalidateTagData(qc, workspaceId) : Promise.resolve()\n }, [arbi, qc])\n}\n\n/** What a new tag is: its name, and optionally kind, format, parent, values, sharing. */\nexport type CreateTagInput = Omit<Parameters<typeof tagOps.createTag>[1], 'workspaceId'>\n\n/** A created tag joins its workspace's list; the tables re-read. */\nfunction settleCreatedTag(qc: QueryClient, created: TagResponse): Promise<void> {\n const workspaceId = created.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.some((t) => t.external_id === created.external_id) ? old : [...old, created]\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/** A changed tag replaces its entry in the list; the tables re-read. */\nfunction settleChangedTag(qc: QueryClient, tag: TagResponse): Promise<void> {\n const workspaceId = tag.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.map((t) => (t.external_id === tag.external_id ? { ...t, ...tag } : t))\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/**\n * The tag writes a host may queue while offline and replay after a reload (`offline.ts`): each\n * key's request on a bare client, and what its success does to the cache.\n */\nexport const replayableTagMutations = [\n {\n mutationKey: arbiMutationKeys.createTag(),\n run: (client: ArbiClient, input: CreateTagInput) => tagOps.createTag(client, input),\n settle: (qc: QueryClient, created: TagResponse) => settleCreatedTag(qc, created),\n },\n] as const\n\n/**\n * Create a tag in the open workspace (`{ name, kind: 'issue' }`, `{ name, parentId }`, …): it is\n * added to the tag list and the tables re-read. Resolves with the new tag. Offline it is held and\n * sent on reconnect (a host that registers `registerArbiMutationDefaults` keeps it across reloads).\n */\nexport function useCreateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.createTag(),\n mutationFn: (input: CreateTagInput): Promise<TagResponse> => arbi.tags.create(input),\n onSuccess: (created) => settleCreatedTag(qc, created),\n })\n}\n\n/**\n * Whether a tag of this name (any case) is being created right now: a second create of the same\n * name (a double Enter) is skipped instead of making a duplicate.\n */\nexport function useIsCreatingTag(): (name: string) => boolean {\n const qc = useQueryClient()\n return useCallback(\n (name: string) => {\n const wanted = name.trim().toLowerCase()\n return (\n qc.getMutationCache().findAll({\n mutationKey: arbiMutationKeys.createTag(),\n predicate: (m) =>\n m.state.status === 'pending' &&\n (m.state.variables as CreateTagInput | undefined)?.name.trim().toLowerCase() === wanted,\n }).length > 0\n )\n },\n [qc]\n )\n}\n\n/** Change a tag (name, format, instruction, parent, sharing, values): patched in the list. */\nexport function useUpdateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({ tagId, change }: { tagId: string; change: TagChange }): Promise<TagResponse> =>\n arbi.tags.update(tagId, change),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/** Merge-patch a tag's values for its kind's fields (`null` clears one); its tables refresh. */\nexport function useSetTagValues() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({\n tagId,\n values,\n }: {\n tagId: string\n values: Record<string, unknown>\n }): Promise<TagResponse> => arbi.tags.setValues(tagId, values),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/**\n * Delete a tag: it leaves the list (its sub-tags move to the top level on the server, so the list\n * re-reads them), and the tables and facts re-read. A host that shows the tag on its own items\n * (documents' tags) follows `arbiMutationKeys.deleteTag()` to drop it there.\n */\nexport function useDeleteTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.deleteTag(),\n mutationFn: (tagId: string) => arbi.tags.delete(tagId),\n onSuccess: (_data, tagId) => {\n // Its pills come off the documents grid in place (and off any open document).\n dropTagFromCachedDocuments(qc, tagId)\n const workspaceId = openWorkspaceId(arbi)\n if (!workspaceId) return\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old\n .filter((t) => t.external_id !== tagId)\n .map((t) => (t.parent_ext_id === tagId ? { ...t, parent_ext_id: null } : t))\n )\n return Promise.all([\n invalidateTagTables(qc, workspaceId),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n },\n })\n}\n\n/**\n * Find the people and organisations documents name and link each to its entity tag. Accepted at\n * once with the documents' ids, which show as running (`useEntityExtractionDocIds`) until a\n * `batch_complete` (`entity_extract`) WebSocket message says they are done.\n */\nexport function useExtractEntities() {\n const arbi = useArbi()\n return useMutation({\n mutationKey: arbiMutationKeys.extractEntities(),\n mutationFn: (docIds: string[]) => arbi.tags.extractEntities(docIds),\n onSuccess: (data) => startEntityExtraction(data.doc_ext_ids),\n })\n}\n\n/**\n * A kind's fields in the open workspace (`'issue'`: its issue fields): the columns of a table of\n * that kind's tags. The built-in ones (`is_default`) until the workspace sets its own.\n */\nexport function useTagKindSchema(\n kind: TagKind | null | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const workspaceId = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.tagKind(workspaceId, kind ?? ''),\n queryFn: (): Promise<TagKindSchema> =>\n arbi.readInWorkspace(workspaceId, () => arbi.tagKinds.get(kind as TagKind)),\n enabled: (options?.enabled ?? true) && !!kind && !!workspaceId,\n })\n}\n\n/**\n * Set a kind's fields in full (a field with its `id` keeps its values; one without is new; one\n * left out is removed). The kind's schema and the workspace's tags refresh.\n */\nexport function useUpdateTagKindSchema() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTagKindSchema(),\n mutationFn: ({\n kind,\n fields,\n }: {\n kind: TagKind\n fields: TagFieldDefinition[]\n }): Promise<TagKindSchema> => arbi.tagKinds.update(kind, fields),\n onSuccess: (schema) => {\n const workspaceId = openWorkspaceId(arbi)\n if (!workspaceId) return\n qc.setQueryData(arbiQueryKeys.tagKind(workspaceId, schema.kind), schema)\n return invalidateTagData(qc, workspaceId)\n },\n })\n}\n","/**\n * Reading a workspace's documents progressively: the first page is the query's result, so the\n * list shows within a few hundred milliseconds even for 100k documents, and the remaining pages\n * are appended to the same cache entry in the background as they arrive. One background read per\n * workspace; opening another workspace stops the previous one. Whether a background read is\n * running is observable ({@link useDocumentsLoading}), for a \"still loading\" indicator.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { patchDocuments, type WorkspaceDocument } from './documents-cache'\n\n/** First page: small, so rows are on screen in a few hundred ms even in a large workspace. */\nexport const DOCUMENTS_FIRST_PAGE_SIZE = 500\n\n/** Later pages: larger, fewer round trips (the server caps a page at 10 000). */\nexport const DOCUMENTS_PAGE_SIZE = 2000\n\n/**\n * The time to the first page, as a `performance` measure of this name (a host reporting\n * performance can observe it).\n */\nexport const DOCUMENTS_FIRST_PAGE_MEASURE = 'arbi:document-list:page1'\nconst FIRST_PAGE_MEASURE = DOCUMENTS_FIRST_PAGE_MEASURE\nconst FIRST_PAGE_START = 'arbi:document-list:start'\n\nfunction mark(name: string): void {\n try {\n performance.mark(name)\n } catch {\n // No performance timeline here (an old runtime, a test): nothing to record.\n }\n}\n\nfunction measure(name: string, start: string): void {\n try {\n performance.measure(name, start)\n } catch {\n // The start mark is missing: nothing to record.\n }\n}\n\nconst backgroundReads = new Map<string, AbortController>()\nconst loadingListeners = new Set<() => void>()\n\nfunction emitLoading(): void {\n for (const listener of loadingListeners) listener()\n}\n\nfunction subscribeLoading(listener: () => void): () => void {\n loadingListeners.add(listener)\n return () => {\n loadingListeners.delete(listener)\n }\n}\n\n/** Whether a workspace's remaining document pages are being read in the background. */\nexport function isDocumentsLoading(): boolean {\n return backgroundReads.size > 0\n}\n\n/** True while the remaining pages of a documents list are still arriving. */\nexport function useDocumentsLoading(): boolean {\n return useSyncExternalStore(subscribeLoading, isDocumentsLoading, () => false)\n}\n\n/** Stop a workspace's background read (closing the workspace). */\nexport function stopDocumentsLoading(workspaceId: string): void {\n const controller = backgroundReads.get(workspaceId)\n if (!controller) return\n controller.abort()\n backgroundReads.delete(workspaceId)\n emitLoading()\n}\n\n/**\n * Read a workspace's documents: resolves with the first page and appends the rest to\n * `arbiQueryKeys.documents(workspaceId)` in the background. The query function of `useDocuments`.\n */\nexport async function loadDocuments(\n qc: QueryClient,\n arbi: Arbi,\n workspaceId: string,\n signal?: AbortSignal\n): Promise<WorkspaceDocument[]> {\n let stopped = false\n for (const [id, controller] of backgroundReads) {\n if (id === workspaceId) continue\n controller.abort()\n backgroundReads.delete(id)\n stopped = true\n }\n if (stopped) emitLoading()\n\n const controller = new AbortController()\n signal?.addEventListener('abort', () => controller.abort(), { once: true })\n // Named, not the session's open workspace: the pages are this workspace's whatever the server\n // session is in, so a list read across a workspace switch can never be another's.\n const pages = arbi.documents.listPaginated({\n workspaceId,\n pageSize: DOCUMENTS_PAGE_SIZE,\n firstPageSize: DOCUMENTS_FIRST_PAGE_SIZE,\n signal: controller.signal,\n })\n mark(FIRST_PAGE_START)\n const first = await pages.next()\n const firstPage = first.done ? [] : first.value\n measure(FIRST_PAGE_MEASURE, FIRST_PAGE_START)\n if (first.done || firstPage.length < DOCUMENTS_FIRST_PAGE_SIZE) return firstPage\n if (backgroundReads.has(workspaceId)) {\n controller.abort()\n return firstPage\n }\n\n backgroundReads.set(workspaceId, controller)\n emitLoading()\n void appendRemainingPages(qc, workspaceId, pages, controller.signal).finally(() => {\n if (backgroundReads.get(workspaceId) !== controller) return\n backgroundReads.delete(workspaceId)\n emitLoading()\n })\n return firstPage\n}\n\nasync function appendRemainingPages(\n qc: QueryClient,\n workspaceId: string,\n pages: AsyncGenerator<WorkspaceDocument[]>,\n signal: AbortSignal\n): Promise<void> {\n // Let the query store the first page before the second is appended to it.\n await Promise.resolve()\n try {\n for await (const page of pages) {\n if (signal.aborted) return\n // A write may already have added some of these (an upload finishing meanwhile).\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n const fresh = page.filter((doc) => !known.has(doc.external_id))\n return fresh.length ? [...old, ...fresh] : old\n },\n workspaceId\n )\n }\n } catch (error) {\n if (!signal.aborted) console.error(`Reading the documents of ${workspaceId} failed:`, error)\n }\n}\n\n/** Test-only: stop every background read. @internal */\nexport function resetDocumentsLoadingForTests(): void {\n for (const controller of backgroundReads.values()) controller.abort()\n backgroundReads.clear()\n emitLoading()\n}\n","/**\n * Which is newer: a document's live processing status or its row as last read?\n *\n * Every `task_update` carries `seq`, taken by the server from one sequence for all documents and\n * all of its instances, so a higher seq is a later event however the events arrive. A document row\n * carries `status_seq`: the seq of the last time its processing ended (a finished status written or\n * broadcast). The two compare:\n * - an event at or below the seq of the one already held is stale (overtaken), and is dropped;\n * - a row whose `status_seq` is above the live status's seq finished after it: the live status is\n * over (its final event was lost), and the row wins;\n * - a live status above the row's `status_seq` is newer than the row: the document is being\n * processed again (AI fields being filled) although the row still says it finished.\n *\n * Without the seqs (an optimistic \"queued\" set here, a server before them) the older rule stands:\n * a live in-flight status wins, then a finished row, then whatever was heard live.\n */\n\n/** Statuses after which a document's processing is over (`low-content`: indexed, little text). */\nexport const FINISHED_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'completed',\n 'low-content',\n 'failed',\n 'skipped',\n 'empty',\n])\n\n/** A live processing status and its order (`task_update.seq`). */\nexport interface SequencedTask {\n status: string\n seq?: number | null\n}\n\n/** A document row's status and the order of its last finished status (`status_seq`). */\nexport interface SequencedRow {\n status?: string | null\n status_seq?: number | null\n}\n\n/** Statuses of a document still being processed. */\nexport const IN_FLIGHT_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'uploading',\n 'queued',\n 'parsing',\n 'encrypting',\n 'indexing',\n 'analysing',\n])\n\nfunction ordered(value: number | null | undefined): value is number {\n return typeof value === 'number'\n}\n\n/** Whether `next` is older than (or the same event as) the live status already held. */\nexport function isStaleTaskUpdate(held: SequencedTask | undefined, next: SequencedTask): boolean {\n return !!held && ordered(held.seq) && ordered(next.seq) && next.seq <= held.seq\n}\n\n/**\n * Whether the row is newer than the live status: `true` / `false` when both are ordered, `undefined`\n * when they cannot be compared.\n */\nexport function isRowNewer(row: SequencedRow, task: SequencedTask): boolean | undefined {\n if (!ordered(row.status_seq) || !ordered(task.seq)) return undefined\n return row.status_seq > task.seq\n}\n\n/** The status a document shows now: its row's, or the live one when that is newer. */\nexport function resolveDocumentStatus(row: SequencedRow, task: SequencedTask | undefined): string {\n const rowStatus = (row.status ?? '').toLowerCase()\n const live = task?.status\n if (!task || !live) return rowStatus\n const rowNewer = isRowNewer(row, task)\n if (rowNewer !== undefined) return rowNewer ? rowStatus || live : live\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(live)) return live\n if (FINISHED_DOCUMENT_STATUSES.has(rowStatus)) return rowStatus\n return live\n}\n\n/**\n * The live statuses a read of `rows` ends: each in-flight one whose row has since finished. Ordered,\n * the row must be newer (so a reprocess the row predates keeps its progress); unordered, a finished\n * row is enough (the older rule). Returns each such task with the row's status and order. Cheap when\n * nothing is in flight (it runs on every read of a list).\n */\nexport function settledByRows<T extends SequencedTask & { doc_ext_id: string }>(\n tasks: Readonly<Record<string, T>>,\n rows: ReadonlyArray<SequencedRow & { external_id: string }>\n): T[] {\n const inFlight = new Map<string, T>()\n for (const task of Object.values(tasks))\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(task.status)) inFlight.set(task.doc_ext_id, task)\n if (!inFlight.size) return []\n const settled: T[] = []\n for (const row of rows) {\n const task = inFlight.get(row.external_id)\n if (!task) continue\n const rowStatus = (row.status ?? '').toLowerCase()\n if (!FINISHED_DOCUMENT_STATUSES.has(rowStatus) || isRowNewer(row, task) === false) continue\n settled.push({ ...task, status: rowStatus, seq: row.status_seq ?? task.seq })\n }\n return settled\n}\n","/**\n * Reading documents: a workspace's list (`useDocuments`, progressive, read once and then patched in\n * place), one document (`useDocument`, for a viewer), a set of documents by id, near-duplicate pairs\n * (`useSimilarDocuments`), and {@link refreshDocuments}, which re-reads just the documents an event\n * named and patches them into every cache that shows them.\n */\n\nimport { useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { invalidateTagTables, patchWorkspaceTags } from '../tags'\nimport {\n getCachedDocuments,\n setCachedDocument,\n upsertDocuments,\n type WorkspaceDocument,\n} from './documents-cache'\nimport { loadDocuments } from './documents-loader'\nimport { FINISHED_DOCUMENT_STATUSES, isRowNewer, type SequencedTask } from './processing-order'\n\nexport { FINISHED_DOCUMENT_STATUSES }\n\n/** The workspace open on `arbi`, or `null`. */\nfunction openWorkspaceId(arbi: Arbi): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * A workspace's documents (default: the open one). Read progressively: the first page is the\n * result, the remaining pages arrive in the background (`useDocumentsLoading`). After that the list\n * is never re-read on its own (mounting, focus, reconnecting): writes, processing events and\n * {@link refreshDocuments} patch it in place, as re-reading 100k documents is slow and tells\n * nothing new. Invalidating it re-reads it.\n */\nexport function useDocuments(workspaceId?: string | null, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const qc = useQueryClient()\n const workspace = workspaceId ?? openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspace),\n queryFn: ({ signal }) => {\n if (openWorkspaceId(arbi) !== workspace)\n return Promise.reject(new Error('The selected workspace changed.'))\n return loadDocuments(qc, arbi, workspace, signal)\n },\n enabled: (options?.enabled ?? true) && !!workspace && arbi.hasWorkspace,\n staleTime: Infinity,\n refetchOnMount: false,\n refetchOnReconnect: false,\n refetchOnWindowFocus: false,\n })\n}\n\n/** How often a document still being processed is re-read (`useDocument`'s `pollWhileProcessing`). */\nexport const DOCUMENT_STATUS_POLL_MS = 4000\n\n/** Re-read a document while it is processing (a viewer waiting for its pages). */\nfunction processingInterval(doc: WorkspaceDocument | null | undefined): number | false {\n return doc?.status && !FINISHED_DOCUMENT_STATUSES.has(doc.status)\n ? DOCUMENT_STATUS_POLL_MS\n : false\n}\n\n/**\n * One document (`null`: not found or not visible). `pollWhileProcessing` re-reads it every few\n * seconds until its processing is over. Writes here keep it current.\n */\nexport function useDocument(\n docId: string | null | undefined,\n options?: { enabled?: boolean; pollWhileProcessing?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.document(docId ?? ''),\n queryFn: async (): Promise<WorkspaceDocument | null> =>\n (await arbi.documents.get([docId as string]))[0] ?? null,\n enabled: (options?.enabled ?? true) && !!docId && arbi.isLoggedIn,\n refetchInterval: options?.pollWhileProcessing\n ? (query) => processingInterval(query.state.data)\n : false,\n })\n}\n\n/** Several documents by id, in one request (cited documents, a selection from elsewhere). */\nexport function useDocumentsById(docIds: string[], options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.documentsById(docIds),\n queryFn: () => arbi.documents.get(docIds),\n enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.isLoggedIn,\n })\n}\n\n/**\n * The similarity at or above which two documents count as near duplicates (the Related column).\n * The server keeps every pair above 0.75 but returns only those at or above what is asked.\n */\nexport const SIMILARITY_THRESHOLD = 0.98\n\n/** Near-duplicate document pairs in the open workspace, at or above {@link SIMILARITY_THRESHOLD}. */\nexport function useSimilarDocuments(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const workspace = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.similarDocuments(workspace, SIMILARITY_THRESHOLD),\n queryFn: () =>\n arbi.readInWorkspace(workspace, () =>\n arbi.documents.similar({ threshold: SIMILARITY_THRESHOLD })\n ),\n enabled: (options?.enabled ?? true) && !!workspace,\n })\n}\n\n// Each re-read gets a number; only the latest one issued for a document may write it. Events can\n// return out of order, and an older read must not undo tags a newer one applied.\nlet readSeq = 0\nconst latestReadByDoc = new Map<string, number>()\n\nexport interface RefreshDocumentsOptions {\n /** The processing the host last heard live for a document (`DocumentsSupport.processingTask`). */\n processingTask?: (docId: string) => SequencedTask | undefined\n}\n\n/**\n * Re-read `docIds` and patch them into the caches that show them: their workspace's list (added\n * when new), their own entries, and the tag list's document counts (tags the server applied, e.g.\n * AI fields). For events that name documents (a batch finished, a version saved, an upload): the\n * list is never re-read for them. A failed read leaves the caches as they were.\n */\nexport async function refreshDocuments(\n qc: QueryClient,\n arbi: Arbi,\n docIds: string[],\n options?: RefreshDocumentsOptions\n): Promise<WorkspaceDocument[]> {\n if (!docIds.length) return []\n const seq = ++readSeq\n for (const id of docIds) latestReadByDoc.set(id, seq)\n try {\n const read = await arbi.documents.get(docIds)\n const fresh = read\n .filter((doc) => latestReadByDoc.get(doc.external_id) === seq)\n .map((doc) => {\n // A finished status heard live wins over a read that predates it (the row may not be\n // committed yet), never over a row that finished after it.\n const live = options?.processingTask?.(doc.external_id)\n return live &&\n FINISHED_DOCUMENT_STATUSES.has(live.status) &&\n doc.status !== live.status &&\n isRowNewer(doc, live) !== true\n ? { ...doc, status: live.status }\n : doc\n })\n if (!fresh.length) return []\n reconcileTagCounts(qc, fresh)\n upsertDocuments(qc, fresh)\n for (const doc of fresh) setCachedDocument(qc, doc)\n return fresh\n } catch (error) {\n // Leave the caches as they were: re-reading the whole list would shrink it to its first page.\n console.error('Re-reading documents failed; the cached ones are kept:', error)\n return []\n } finally {\n for (const id of docIds) if (latestReadByDoc.get(id) === seq) latestReadByDoc.delete(id)\n }\n}\n\n/** Move each tag's document count by the tags the re-read documents gained or lost. */\nfunction reconcileTagCounts(qc: QueryClient, fresh: WorkspaceDocument[]): void {\n const byWorkspace = new Map<string, Map<string, number>>()\n for (const doc of fresh) {\n const cached = getCachedDocuments(qc, doc.workspace_ext_id)?.find(\n (d) => d.external_id === doc.external_id\n )\n const before = new Set((cached?.doctags ?? []).map((dt) => dt.tag_ext_id))\n const after = new Set((doc.doctags ?? []).map((dt) => dt.tag_ext_id))\n const delta = byWorkspace.get(doc.workspace_ext_id) ?? new Map<string, number>()\n for (const id of after) if (!before.has(id)) delta.set(id, (delta.get(id) ?? 0) + 1)\n for (const id of before) if (!after.has(id)) delta.set(id, (delta.get(id) ?? 0) - 1)\n byWorkspace.set(doc.workspace_ext_id, delta)\n }\n for (const [workspaceId, delta] of byWorkspace) adjustTagCounts(qc, workspaceId, delta)\n}\n\n/** Add `delta` (tag id → change) to the tags' document counts; the tag tables re-read. */\nexport function adjustTagCounts(\n qc: QueryClient,\n workspaceId: string,\n delta: Map<string, number>\n): void {\n if (![...delta.values()].some(Boolean)) return\n patchWorkspaceTags(qc, workspaceId, (tags) =>\n tags.map((tag) => {\n const change = delta.get(tag.external_id)\n return change ? { ...tag, doctag_count: Math.max(0, tag.doctag_count + change) } : tag\n })\n )\n void invalidateTagTables(qc, workspaceId)\n}\n"]}
@@ -3,6 +3,14 @@ import * as React from 'react';
3
3
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
+ // src/entities/vocabulary.ts
7
+ var vocabulary = {};
8
+ function configureEntityVocabulary(next) {
9
+ vocabulary = next;
10
+ }
11
+ function vocabularyNoun(entityType) {
12
+ return vocabulary[entityType];
13
+ }
6
14
  var ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
7
15
  ScrollAreaPrimitive.Root,
8
16
  {
@@ -84,6 +92,6 @@ function formatRelativeTime(iso, options = {}) {
84
92
  return "";
85
93
  }
86
94
 
87
- export { ScrollArea, ScrollBar, formatRelativeTime };
88
- //# sourceMappingURL=chunk-NA3FJX37.js.map
89
- //# sourceMappingURL=chunk-NA3FJX37.js.map
95
+ export { ScrollArea, ScrollBar, configureEntityVocabulary, formatRelativeTime, vocabularyNoun };
96
+ //# sourceMappingURL=chunk-Y3MTRA7D.js.map
97
+ //# sourceMappingURL=chunk-Y3MTRA7D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/entities/vocabulary.ts","../src/ui/scroll-area.tsx","../src/lib/format-relative-time.ts"],"names":[],"mappings":"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","file":"chunk-Y3MTRA7D.js","sourcesContent":["/**\n * A site's own words for the entities (`ArbiHostConfig.vocabulary`): `{ PROJECT: 'Matter' }` makes\n * every kit say \"Matter\", \"Matters\", \"New matter\" where the defaults say \"Project\". The vertical\n * nouns live only in the site's config; the kits read them through `getEntityLabel` /\n * `entityNoun`, at render time, so the host's vocabulary is in place before any kit renders.\n *\n * Dependency-free (no icons), so `<ArbiHost>` can apply it without growing its import graph.\n */\n\n/** An entity's word: the singular (\"Matter\"), or each form where a derived one would be wrong. */\nexport type EntityNoun =\n string | { SINGULAR: string; PLURAL?: string; SHORT?: string; NEW?: string }\n\n/** A site's words, keyed by entity type (`PROJECT`, `WORKSPACE`, …). */\nexport type EntityVocabulary = Partial<Record<string, EntityNoun>>\n\nlet vocabulary: EntityVocabulary = {}\n\n/** Set the site's vocabulary (replacing any earlier one). `<ArbiHost>` calls it with `config.vocabulary`. */\nexport function configureEntityVocabulary(next: EntityVocabulary): void {\n vocabulary = next\n}\n\n/** The site's word for an entity type, if it has one. */\nexport function vocabularyNoun(entityType: string): EntityNoun | undefined {\n return vocabulary[entityType]\n}\n","import * as React from 'react'\nimport * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'\n\nimport { cn } from '../lib/utils'\n\nconst ScrollArea = React.forwardRef<\n React.ElementRef<typeof ScrollAreaPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>\n>(({ className, children, ...props }, ref) => (\n <ScrollAreaPrimitive.Root\n ref={ref}\n className={cn('relative overflow-hidden', className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport className=\"h-full w-full rounded-[inherit]\">\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n))\nScrollArea.displayName = ScrollAreaPrimitive.Root.displayName\n\nconst ScrollBar = React.forwardRef<\n React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,\n React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>\n>(({ className, orientation = 'vertical', ...props }, ref) => (\n <ScrollAreaPrimitive.ScrollAreaScrollbar\n ref={ref}\n orientation={orientation}\n className={cn(\n 'flex touch-none select-none transition-colors',\n orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-[1px]',\n orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-[1px]',\n className\n )}\n {...props}\n >\n <ScrollAreaPrimitive.ScrollAreaThumb className=\"relative flex-1 rounded-full bg-border\" />\n </ScrollAreaPrimitive.ScrollAreaScrollbar>\n))\nScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName\n\nexport { ScrollArea, ScrollBar }\n","/** The one relative-time formatter: the notification bell, the DM kit, thread lists, webinar\n * panels, workspace cards, connector syncs and studio widgets all use it (no type imports, so the\n * SDK-free `/shell` and `/ui` entries can use it). */\n\nconst FORMATTERS = new Map<Intl.RelativeTimeFormatStyle, Intl.RelativeTimeFormat>()\nconst DIVISIONS: Array<{ amount: number; unit: Intl.RelativeTimeFormatUnit }> = [\n { amount: 60, unit: 'seconds' },\n { amount: 60, unit: 'minutes' },\n { amount: 24, unit: 'hours' },\n { amount: 7, unit: 'days' },\n { amount: 4.34524, unit: 'weeks' },\n { amount: 12, unit: 'months' },\n { amount: Number.POSITIVE_INFINITY, unit: 'years' },\n]\n\nfunction formatter(style: Intl.RelativeTimeFormatStyle): Intl.RelativeTimeFormat {\n let f = FORMATTERS.get(style)\n if (!f) {\n f = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto', style })\n FORMATTERS.set(style, f)\n }\n return f\n}\n\nexport interface FormatRelativeTimeOptions {\n /** The reference instant in epoch milliseconds (default: now). */\n now?: number\n /** `long` (default): \"2 hours ago\"; `short`: \"2 hr. ago\", for tight rows; `compact`: \"2h ago\",\n * for status lines and dense widgets. */\n style?: Intl.RelativeTimeFormatStyle | 'compact'\n}\n\nconst COMPACT_UNITS: Array<[seconds: number, suffix: string]> = [\n [86_400, 'd'],\n [3_600, 'h'],\n [60, 'm'],\n]\n\n/** \"5m ago\", \"3h ago\", \"2d ago\", \"in 4h\"; \"just now\" under a minute. */\nfunction compact(seconds: number): string {\n const abs = Math.abs(seconds)\n if (abs < 60) return 'just now'\n for (const [size, suffix] of COMPACT_UNITS) {\n if (abs >= size) {\n const value = `${Math.round(abs / size)}${suffix}`\n return seconds < 0 ? `${value} ago` : `in ${value}`\n }\n }\n return 'just now'\n}\n\n/** Relative time of an ISO timestamp, past or future: \"2 hours ago\", \"in 3 days\", \"just now\".\n * Empty for an unparseable timestamp. */\nexport function formatRelativeTime(iso: string, options: FormatRelativeTimeOptions = {}): string {\n const then = Date.parse(iso)\n if (Number.isNaN(then)) return ''\n let duration = (then - (options.now ?? Date.now())) / 1000\n if (options.style === 'compact') return compact(duration)\n if (Math.abs(duration) < 45) return 'just now'\n for (const division of DIVISIONS) {\n if (Math.abs(duration) < division.amount) {\n return formatter(options.style ?? 'long').format(Math.round(duration), division.unit)\n }\n duration /= division.amount\n }\n return ''\n}\n"]}
@@ -22,5 +22,5 @@ function useDeploymentDomain() {
22
22
  exports.useArbi = useArbi;
23
23
  exports.useArbiHost = useArbiHost;
24
24
  exports.useDeploymentDomain = useDeploymentDomain;
25
- //# sourceMappingURL=chunk-QQ7SCJRY.cjs.map
26
- //# sourceMappingURL=chunk-QQ7SCJRY.cjs.map
25
+ //# sourceMappingURL=chunk-YIUUTRMQ.cjs.map
26
+ //# sourceMappingURL=chunk-YIUUTRMQ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/host/config.ts","../src/useArbi.ts"],"names":["useContext","ArbiHostContext"],"mappings":";;;;;AAiHO,SAAS,WAAA,GAA8B;AAC5C,EAAA,OAAOA,iBAAWC,iCAAe,CAAA;AACnC;;;AC5GO,SAAS,OAAA,GAAgB;AAC9B,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,WAAA,EAAY;AAC7B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC5E;AACA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,mBAAA,GAA0C;AACxD,EAAA,OAAO,WAAA,EAAY,CAAE,IAAA,EAAM,mBAAA,EAAoB;AACjD","file":"chunk-QQ7SCJRY.cjs","sourcesContent":["/**\n * What a host hands the `@arbidocs/react` hooks, as one configuration (`<ArbiHost config>`). Every\n * field is optional: without one the hooks use their own default. `@arbidocs/blocks` extends it\n * with the blocks domains (environment, billing, viewer, …).\n *\n * A field whose value lives in the host's state is a hook (`use…`), called by the hooks and kits\n * that need it, so the configuration itself stays one stable object for the host's life.\n */\n\nimport { useContext } from 'react'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport type { AccountClient } from '../account/client'\nimport type { CalendarSupport } from '../calendar/support'\nimport type { ComponentType } from 'react'\nimport type { MeetingChatRef } from '../calls/meeting-chat'\nimport type { ActiveCall } from '../calls/session'\nimport type { ArbiChatHost } from '../chat/host'\nimport type { DocumentsSupport } from '../documents/support'\nimport type { MailClient } from '../mail/client'\nimport type { ArbiSessionStore } from '../session/store'\nimport type { DictateContextValue } from '../ui/DictateContext'\nimport type { ArbiHostConnection } from './ArbiHost'\nimport { ArbiHostContext } from './context'\n\n/** The mail client, and whether mail is on for the signed-in user. */\nexport interface MailHost {\n client: MailClient\n /**\n * Whether mail reads run (signed in and entitled), and the server session the mailbox is\n * unlocked for: unlocking runs again when it changes (`null`: none yet, nothing is unlocked).\n * Absent: on, for one session.\n */\n useStatus?: () => { enabled: boolean; sessionKey: string | null }\n}\n\n/** The account client of the settings kits, and whether account reads run (signed in). */\nexport interface AccountHost {\n client: AccountClient\n /** Absent: always. */\n useEnabled?: () => boolean\n}\n\n/** A person in the call UI (a participant, a speaker, a host). */\nexport interface CallUserPillProps {\n /** Their LiveKit identity: the user ext id. */\n identity: string\n /** The call's name for them, for someone the host does not know. */\n name?: string | null\n size?: 'xs' | 'sm' | 'md' | 'lg'\n variant?: 'pill' | 'icon'\n /** Click opens a chat with them (off by default inside the call). */\n interactive?: boolean\n className?: string\n}\n\n/** Where the call panel goes in the host's layout. */\nexport type CallSlotMode = 'docked' | 'main'\n\n/** What the calls need from the host: navigation and layout are the host's. */\nexport interface CallsHost {\n /**\n * The host's switch for the call UI (call buttons, the ringer, upcoming calls), on top of the\n * server's: ARBI's Settings → Experimental toggle. Absent: on.\n */\n useEnabled?: () => boolean\n /**\n * Show a call's meeting chat: an end-to-end chat, or a workspace meeting thread. Absent: the\n * in-call \"Open meeting chat\" does nothing.\n */\n openMeetingChat?: (ref: MeetingChatRef) => void\n /**\n * Once connected, show the call's conversation (its chat and live transcript) beside the call.\n * Absent: nothing is shown.\n */\n showConversation?: (call: ActiveCall) => void | Promise<void>\n /**\n * The element whose box the shown call fills: the right-hand dock, or (a webinar's audience) the\n * main area. The host claims its slot while `shown` and calls `onLost` when another panel takes\n * it (the call then minimises). Absent: the call floats at the right edge.\n */\n useSlot?: (mode: CallSlotMode, shown: boolean, onLost: () => void) => HTMLElement | null\n /** How a person shows in the call UI. Absent: the plain user pill with the call's name. */\n UserPill?: ComponentType<CallUserPillProps>\n}\n\nexport interface ArbiHostConfig {\n /**\n * The SDK on the signed-in session. A host with its own login passes one on its session\n * (`new Arbi({ url, session })`); a blocks-only site gets one from `defaultHost`. A new instance (a\n * new session, a newly opened workspace) re-renders every hook.\n */\n arbi?: Arbi\n /** The session state the kits share. Absent: an in-memory one per top-level host. */\n session?: ArbiSessionStore\n /** Live processing, uploads and the host's document actions. Absent: the package's own. */\n documents?: DocumentsSupport\n /** The calendar kept on this device and account OAuth. Absent: online only, the user's connectors. */\n calendar?: CalendarSupport\n /** Absent: mail on the `arbi` session. */\n mail?: MailHost\n /** Absent: the account on the `arbi` session. */\n account?: AccountHost\n /** Absent: calls open no meeting chat from the room. */\n calls?: CallsHost\n /** Dictation for every `dictate` field. Absent: no mic button. */\n dictate?: DictateContextValue\n /** The sign-in layer of a blocks-only site (`defaultHost` in `@arbidocs/blocks/connect`). */\n connection?: ArbiHostConnection\n /** Where the chat engine's side effects go (documents shown, mail drafts, used-up quota). */\n chat?: ArbiChatHost\n}\n\n/** The host configuration in scope (`{}` outside an `<ArbiHost>`). */\nexport function useArbiHost(): ArbiHostConfig {\n return useContext(ArbiHostContext) as ArbiHostConfig\n}\n","/**\n * The `Arbi` of the host configuration (`<ArbiHost config={{ arbi }}>`).\n */\n\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbiHost } from './host/config'\n\nexport function useArbi(): Arbi {\n const { arbi } = useArbiHost()\n if (!arbi) {\n throw new Error('useArbi() needs an <ArbiHost> whose config has an `arbi`')\n }\n return arbi\n}\n\n/**\n * The deployment domain the user's keys are derived for, as the host's `Arbi` computes it\n * (`deploymentDomain`, else the API URL's hostname). `undefined` without one. The document tools\n * default their `deploymentDomain` (needed for e-signing) to it.\n */\nexport function useDeploymentDomain(): string | undefined {\n return useArbiHost().arbi?.getDeploymentDomain()\n}\n"]}
1
+ {"version":3,"sources":["../src/host/config.ts","../src/useArbi.ts"],"names":["useContext","ArbiHostContext"],"mappings":";;;;;AAuHO,SAAS,WAAA,GAA8B;AAC5C,EAAA,OAAOA,iBAAWC,iCAAe,CAAA;AACnC;;;AClHO,SAAS,OAAA,GAAgB;AAC9B,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,WAAA,EAAY;AAC7B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC5E;AACA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,mBAAA,GAA0C;AACxD,EAAA,OAAO,WAAA,EAAY,CAAE,IAAA,EAAM,mBAAA,EAAoB;AACjD","file":"chunk-YIUUTRMQ.cjs","sourcesContent":["/**\n * What a host hands the `@arbidocs/react` hooks, as one configuration (`<ArbiHost config>`). Every\n * field is optional: without one the hooks use their own default. `@arbidocs/blocks` extends it\n * with the blocks domains (environment, billing, viewer, …).\n *\n * A field whose value lives in the host's state is a hook (`use…`), called by the hooks and kits\n * that need it, so the configuration itself stays one stable object for the host's life.\n */\n\nimport { useContext } from 'react'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport type { AccountClient } from '../account/client'\nimport type { CalendarSupport } from '../calendar/support'\nimport type { ComponentType } from 'react'\nimport type { MeetingChatRef } from '../calls/meeting-chat'\nimport type { ActiveCall } from '../calls/session'\nimport type { ArbiChatHost } from '../chat/host'\nimport type { DocumentsSupport } from '../documents/support'\nimport type { MailClient } from '../mail/client'\nimport type { ArbiSessionStore } from '../session/store'\nimport type { DictateContextValue } from '../ui/DictateContext'\nimport type { EntityVocabulary } from '../entities/vocabulary'\nimport type { ArbiHostConnection } from './ArbiHost'\nimport { ArbiHostContext } from './context'\n\n/** The mail client, and whether mail is on for the signed-in user. */\nexport interface MailHost {\n client: MailClient\n /**\n * Whether mail reads run (signed in and entitled), and the server session the mailbox is\n * unlocked for: unlocking runs again when it changes (`null`: none yet, nothing is unlocked).\n * Absent: on, for one session.\n */\n useStatus?: () => { enabled: boolean; sessionKey: string | null }\n}\n\n/** The account client of the settings kits, and whether account reads run (signed in). */\nexport interface AccountHost {\n client: AccountClient\n /** Absent: always. */\n useEnabled?: () => boolean\n}\n\n/** A person in the call UI (a participant, a speaker, a host). */\nexport interface CallUserPillProps {\n /** Their LiveKit identity: the user ext id. */\n identity: string\n /** The call's name for them, for someone the host does not know. */\n name?: string | null\n size?: 'xs' | 'sm' | 'md' | 'lg'\n variant?: 'pill' | 'icon'\n /** Click opens a chat with them (off by default inside the call). */\n interactive?: boolean\n className?: string\n}\n\n/** Where the call panel goes in the host's layout. */\nexport type CallSlotMode = 'docked' | 'main'\n\n/** What the calls need from the host: navigation and layout are the host's. */\nexport interface CallsHost {\n /**\n * The host's switch for the call UI (call buttons, the ringer, upcoming calls), on top of the\n * server's: ARBI's Settings → Experimental toggle. Absent: on.\n */\n useEnabled?: () => boolean\n /**\n * Show a call's meeting chat: an end-to-end chat, or a workspace meeting thread. Absent: the\n * in-call \"Open meeting chat\" does nothing.\n */\n openMeetingChat?: (ref: MeetingChatRef) => void\n /**\n * Once connected, show the call's conversation (its chat and live transcript) beside the call.\n * Absent: nothing is shown.\n */\n showConversation?: (call: ActiveCall) => void | Promise<void>\n /**\n * The element whose box the shown call fills: the right-hand dock, or (a webinar's audience) the\n * main area. The host claims its slot while `shown` and calls `onLost` when another panel takes\n * it (the call then minimises). Absent: the call floats at the right edge.\n */\n useSlot?: (mode: CallSlotMode, shown: boolean, onLost: () => void) => HTMLElement | null\n /** How a person shows in the call UI. Absent: the plain user pill with the call's name. */\n UserPill?: ComponentType<CallUserPillProps>\n}\n\nexport interface ArbiHostConfig {\n /**\n * The SDK on the signed-in session. A host with its own login passes one on its session\n * (`new Arbi({ url, session })`); a blocks-only site gets one from `defaultHost`. A new instance (a\n * new session, a newly opened workspace) re-renders every hook.\n */\n arbi?: Arbi\n /** The session state the kits share. Absent: an in-memory one per top-level host. */\n session?: ArbiSessionStore\n /** Live processing, uploads and the host's document actions. Absent: the package's own. */\n documents?: DocumentsSupport\n /** The calendar kept on this device and account OAuth. Absent: online only, the user's connectors. */\n calendar?: CalendarSupport\n /** Absent: mail on the `arbi` session. */\n mail?: MailHost\n /** Absent: the account on the `arbi` session. */\n account?: AccountHost\n /** Absent: calls open no meeting chat from the room. */\n calls?: CallsHost\n /** Dictation for every `dictate` field. Absent: no mic button. */\n dictate?: DictateContextValue\n /** The sign-in layer of a blocks-only site (`defaultHost` in `@arbidocs/blocks/connect`). */\n connection?: ArbiHostConnection\n /** Where the chat engine's side effects go (documents shown, mail drafts, used-up quota). */\n chat?: ArbiChatHost\n /**\n * The site's words for the entities (`{ PROJECT: 'Matter' }`), read by every kit through\n * `getEntityLabel`. Absent: the registry's (\"Project\", \"Workspace\", \"Thread\", …).\n */\n vocabulary?: EntityVocabulary\n}\n\n/** The host configuration in scope (`{}` outside an `<ArbiHost>`). */\nexport function useArbiHost(): ArbiHostConfig {\n return useContext(ArbiHostContext) as ArbiHostConfig\n}\n","/**\n * The `Arbi` of the host configuration (`<ArbiHost config={{ arbi }}>`).\n */\n\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbiHost } from './host/config'\n\nexport function useArbi(): Arbi {\n const { arbi } = useArbiHost()\n if (!arbi) {\n throw new Error('useArbi() needs an <ArbiHost> whose config has an `arbi`')\n }\n return arbi\n}\n\n/**\n * The deployment domain the user's keys are derived for, as the host's `Arbi` computes it\n * (`deploymentDomain`, else the API URL's hostname). `undefined` without one. The document tools\n * default their `deploymentDomain` (needed for e-signing) to it.\n */\nexport function useDeploymentDomain(): string | undefined {\n return useArbiHost().arbi?.getDeploymentDomain()\n}\n"]}