@arbidocs/react 0.5.113 → 0.5.115

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 (29) hide show
  1. package/dist/artifacts/index.cjs +34 -34
  2. package/dist/calls/livekit/index.cjs +44 -44
  3. package/dist/chat/thread-binding.js +23 -1
  4. package/dist/chat/thread-binding.js.map +2 -2
  5. package/dist/chat/useAutoSendDraft.js +3 -3
  6. package/dist/chat/useAutoSendDraft.js.map +2 -2
  7. package/dist/chat/useThreadDocument.js +10 -6
  8. package/dist/chat/useThreadDocument.js.map +2 -2
  9. package/dist/{chunk-NDIKMOBJ.cjs → chunk-7C77IBQZ.cjs} +3 -3
  10. package/dist/{chunk-NDIKMOBJ.cjs.map → chunk-7C77IBQZ.cjs.map} +1 -1
  11. package/dist/{chunk-3JAEX57E.cjs → chunk-GFYDHBT3.cjs} +4 -4
  12. package/dist/{chunk-3JAEX57E.cjs.map → chunk-GFYDHBT3.cjs.map} +1 -1
  13. package/dist/{chunk-YMB6XUR2.cjs → chunk-GN5IJKTG.cjs} +5 -5
  14. package/dist/{chunk-YMB6XUR2.cjs.map → chunk-GN5IJKTG.cjs.map} +1 -1
  15. package/dist/{chunk-DI5KSVKY.cjs → chunk-PRQD7VPT.cjs} +24 -24
  16. package/dist/{chunk-DI5KSVKY.cjs.map → chunk-PRQD7VPT.cjs.map} +1 -1
  17. package/dist/{chunk-5TRUFWKT.cjs → chunk-RHVHNQBR.cjs} +6 -6
  18. package/dist/{chunk-5TRUFWKT.cjs.map → chunk-RHVHNQBR.cjs.map} +1 -1
  19. package/dist/{chunk-Z3W4XFWB.cjs → chunk-TTHJNRLY.cjs} +5 -5
  20. package/dist/{chunk-Z3W4XFWB.cjs.map → chunk-TTHJNRLY.cjs.map} +1 -1
  21. package/dist/document-tools/core.cjs +99 -99
  22. package/dist/document-tools/index.cjs +101 -101
  23. package/dist/index.cjs +1577 -1551
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.ts +2 -7
  26. package/dist/shell/index.cjs +39 -39
  27. package/dist/ui/index.cjs +13 -13
  28. package/dist/viewers/index.cjs +9 -9
  29. package/package.json +3 -3
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkGKGAPU6T_cjs = require('../chunk-GKGAPU6T.cjs');
4
- var chunkYMB6XUR2_cjs = require('../chunk-YMB6XUR2.cjs');
4
+ var chunkMXP4O4DI_cjs = require('../chunk-MXP4O4DI.cjs');
5
+ var chunkGN5IJKTG_cjs = require('../chunk-GN5IJKTG.cjs');
5
6
  var chunk3AADNIOK_cjs = require('../chunk-3AADNIOK.cjs');
6
7
  var chunkO32T7XRD_cjs = require('../chunk-O32T7XRD.cjs');
7
8
  require('../chunk-N73IMVFF.cjs');
8
- var chunkNDIKMOBJ_cjs = require('../chunk-NDIKMOBJ.cjs');
9
- var chunkVOFNX4P6_cjs = require('../chunk-VOFNX4P6.cjs');
10
- var chunkMXP4O4DI_cjs = require('../chunk-MXP4O4DI.cjs');
9
+ var chunk7C77IBQZ_cjs = require('../chunk-7C77IBQZ.cjs');
11
10
  require('../chunk-5NOZDH3F.cjs');
12
11
  require('../chunk-S6A6FSG7.cjs');
12
+ var chunkVOFNX4P6_cjs = require('../chunk-VOFNX4P6.cjs');
13
13
  var react = require('react');
14
14
  var reactQuery = require('@tanstack/react-query');
15
15
  var jsxRuntime = require('react/jsx-runtime');
@@ -275,19 +275,19 @@ function useArtifactText(docId, options) {
275
275
  ...DEFAULT_ARTIFACT_TEXT_RETRY,
276
276
  ...options?.retry
277
277
  };
278
- const enabled = (options?.enabled ?? true) && chunkNDIKMOBJ_cjs.isDocumentId(docId) && arbi.hasWorkspace;
278
+ const enabled = (options?.enabled ?? true) && chunk7C77IBQZ_cjs.isDocumentId(docId) && arbi.hasWorkspace;
279
279
  const query = reactQuery.useQuery({
280
280
  // Under the shared `parsedDoc` key, so a document's invalidation reaches it too.
281
281
  queryKey: [...chunkO32T7XRD_cjs.arbiQueryKeys.parsedDoc(docId ?? "", "marker"), "artifact-text"],
282
282
  queryFn: async () => {
283
- const { docId: plainId, version } = chunkNDIKMOBJ_cjs.parseVersionRef(docId);
283
+ const { docId: plainId, version } = chunk7C77IBQZ_cjs.parseVersionRef(docId);
284
284
  const parsed = await arbi.documents.getParsedContent(
285
285
  plainId,
286
286
  "marker",
287
287
  version ?? void 0
288
288
  );
289
289
  if (!parsed.chunks?.some((c) => c.content?.trim())) throw new NotParsedYetError();
290
- return chunkNDIKMOBJ_cjs.flattenChunks(parsed.chunks, { unescape: true });
290
+ return chunk7C77IBQZ_cjs.flattenChunks(parsed.chunks, { unescape: true });
291
291
  },
292
292
  enabled,
293
293
  retry: (failureCount, error) => !isRefusal(error) && failureCount < attempts,
@@ -325,17 +325,17 @@ function useArtifactText(docId, options) {
325
325
 
326
326
  // src/artifacts/useArtifactSession.ts
327
327
  function useArtifactVersions(workspaceId, docId) {
328
- const plainId = docId ? chunkNDIKMOBJ_cjs.parseVersionRef(docId).docId : null;
328
+ const plainId = docId ? chunk7C77IBQZ_cjs.parseVersionRef(docId).docId : null;
329
329
  const { data: documents } = chunkGKGAPU6T_cjs.useDocuments(workspaceId);
330
330
  const listed = react.useMemo(
331
331
  () => (documents ?? []).find((d) => d.external_id === plainId),
332
332
  [documents, plainId]
333
333
  );
334
- const { data: history } = chunkYMB6XUR2_cjs.useDocumentVersionList(plainId, {
334
+ const { data: history } = chunkGN5IJKTG_cjs.useDocumentVersionList(plainId, {
335
335
  enabled: !!plainId && documents !== void 0 && !listed
336
336
  });
337
337
  return react.useMemo(
338
- () => listed ? chunkNDIKMOBJ_cjs.documentVersions(listed) : chunkNDIKMOBJ_cjs.toArtifactVersions(plainId, history),
338
+ () => listed ? chunk7C77IBQZ_cjs.documentVersions(listed) : chunk7C77IBQZ_cjs.toArtifactVersions(plainId, history),
339
339
  [listed, history, plainId]
340
340
  );
341
341
  }
@@ -350,7 +350,7 @@ function useSaveArtifactVersion() {
350
350
  fileName,
351
351
  {
352
352
  wpType: wpType ?? "artifact",
353
- versionOf: versionOf ? chunkNDIKMOBJ_cjs.parseVersionRef(versionOf).docId : void 0,
353
+ versionOf: versionOf ? chunk7C77IBQZ_cjs.parseVersionRef(versionOf).docId : void 0,
354
354
  configExtId: configId ?? void 0
355
355
  }
356
356
  );
@@ -378,7 +378,7 @@ function useArtifactSession(options) {
378
378
  const [saved, setSaved] = react.useState(null);
379
379
  const adopted = saved && saved.forId === hostDocId ? saved : null;
380
380
  const docId = adopted?.id ?? hostDocId;
381
- const isLocal = !chunkNDIKMOBJ_cjs.isDocumentId(docId);
381
+ const isLocal = !chunk7C77IBQZ_cjs.isDocumentId(docId);
382
382
  const [ownCompareId, setOwnCompareId] = react.useState(null);
383
383
  const activeCompareId = compareId === void 0 ? ownCompareId : compareId;
384
384
  const changeCompare = react.useCallback(
@@ -394,7 +394,7 @@ function useArtifactSession(options) {
394
394
  enabled: !!activeCompareId
395
395
  });
396
396
  const saveVersion = useSaveArtifactVersion();
397
- const current = chunkNDIKMOBJ_cjs.findVersion(versions, docId);
397
+ const current = chunk7C77IBQZ_cjs.findVersion(versions, docId);
398
398
  const save = react.useCallback(
399
399
  async (content) => {
400
400
  const result = await saveVersion.mutateAsync({
@@ -410,7 +410,7 @@ function useArtifactSession(options) {
410
410
  );
411
411
  const handleSaved = react.useCallback(
412
412
  (result, content) => {
413
- if (!chunkNDIKMOBJ_cjs.isDocumentId(hostDocId) && result.docId)
413
+ if (!chunk7C77IBQZ_cjs.isDocumentId(hostDocId) && result.docId)
414
414
  setSaved({ forId: hostDocId, id: result.docId, text: content });
415
415
  onSaved?.(result, content);
416
416
  },
@@ -439,7 +439,7 @@ function useArtifactSession(options) {
439
439
  isLoading,
440
440
  status,
441
441
  versions,
442
- labelOf: (id) => chunkNDIKMOBJ_cjs.versionLabel(versions, id),
442
+ labelOf: (id) => chunk7C77IBQZ_cjs.versionLabel(versions, id),
443
443
  view: {
444
444
  content: session.baseline,
445
445
  isEditing: session.isEditing,
@@ -504,7 +504,7 @@ function useStreamedArtifact({
504
504
  const started = react.useRef(null);
505
505
  const content = artifact?.content ?? "";
506
506
  const title = artifact?.title ?? "Draft";
507
- const passThrough = !!artifact && chunkNDIKMOBJ_cjs.isDocumentId(artifact.doc_ext_id);
507
+ const passThrough = !!artifact && chunk7C77IBQZ_cjs.isDocumentId(artifact.doc_ext_id);
508
508
  const needsSave = settled && !!artifact && !passThrough && !!content.trim() && !!workspaceId;
509
509
  react.useEffect(() => {
510
510
  const key = `${attempt}:${content}`;
@@ -514,7 +514,7 @@ function useStreamedArtifact({
514
514
  let stored;
515
515
  if (clean) stored = clean(content);
516
516
  else {
517
- const report = chunkNDIKMOBJ_cjs.cleanDraftWithReport(content);
517
+ const report = chunk7C77IBQZ_cjs.cleanDraftWithReport(content);
518
518
  stored = report.text;
519
519
  setCleaned(report);
520
520
  onCleaned?.(report);
@@ -581,71 +581,71 @@ Object.defineProperty(exports, "revertRedlineRegion", {
581
581
  });
582
582
  Object.defineProperty(exports, "cleanDraftMarkdown", {
583
583
  enumerable: true,
584
- get: function () { return chunkNDIKMOBJ_cjs.cleanDraftMarkdown; }
584
+ get: function () { return chunk7C77IBQZ_cjs.cleanDraftMarkdown; }
585
585
  });
586
586
  Object.defineProperty(exports, "cleanDraftWithReport", {
587
587
  enumerable: true,
588
- get: function () { return chunkNDIKMOBJ_cjs.cleanDraftWithReport; }
588
+ get: function () { return chunk7C77IBQZ_cjs.cleanDraftWithReport; }
589
589
  });
590
590
  Object.defineProperty(exports, "documentVersions", {
591
591
  enumerable: true,
592
- get: function () { return chunkNDIKMOBJ_cjs.documentVersions; }
592
+ get: function () { return chunk7C77IBQZ_cjs.documentVersions; }
593
593
  });
594
594
  Object.defineProperty(exports, "findVersion", {
595
595
  enumerable: true,
596
- get: function () { return chunkNDIKMOBJ_cjs.findVersion; }
596
+ get: function () { return chunk7C77IBQZ_cjs.findVersion; }
597
597
  });
598
598
  Object.defineProperty(exports, "flattenChunks", {
599
599
  enumerable: true,
600
- get: function () { return chunkNDIKMOBJ_cjs.flattenChunks; }
600
+ get: function () { return chunk7C77IBQZ_cjs.flattenChunks; }
601
601
  });
602
602
  Object.defineProperty(exports, "isDocumentId", {
603
603
  enumerable: true,
604
- get: function () { return chunkNDIKMOBJ_cjs.isDocumentId; }
604
+ get: function () { return chunk7C77IBQZ_cjs.isDocumentId; }
605
605
  });
606
606
  Object.defineProperty(exports, "parseVersionRef", {
607
607
  enumerable: true,
608
- get: function () { return chunkNDIKMOBJ_cjs.parseVersionRef; }
608
+ get: function () { return chunk7C77IBQZ_cjs.parseVersionRef; }
609
609
  });
610
610
  Object.defineProperty(exports, "promoteBoldTitle", {
611
611
  enumerable: true,
612
- get: function () { return chunkNDIKMOBJ_cjs.promoteBoldTitle; }
612
+ get: function () { return chunk7C77IBQZ_cjs.promoteBoldTitle; }
613
613
  });
614
614
  Object.defineProperty(exports, "repairParsedStructure", {
615
615
  enumerable: true,
616
- get: function () { return chunkNDIKMOBJ_cjs.repairParsedStructure; }
616
+ get: function () { return chunk7C77IBQZ_cjs.repairParsedStructure; }
617
617
  });
618
618
  Object.defineProperty(exports, "repairParsedTitle", {
619
619
  enumerable: true,
620
- get: function () { return chunkNDIKMOBJ_cjs.repairParsedTitle; }
620
+ get: function () { return chunk7C77IBQZ_cjs.repairParsedTitle; }
621
621
  });
622
622
  Object.defineProperty(exports, "savedFromId", {
623
623
  enumerable: true,
624
- get: function () { return chunkNDIKMOBJ_cjs.savedFromId; }
624
+ get: function () { return chunk7C77IBQZ_cjs.savedFromId; }
625
625
  });
626
626
  Object.defineProperty(exports, "stripAgentPreamble", {
627
627
  enumerable: true,
628
- get: function () { return chunkNDIKMOBJ_cjs.stripAgentPreamble; }
628
+ get: function () { return chunk7C77IBQZ_cjs.stripAgentPreamble; }
629
629
  });
630
630
  Object.defineProperty(exports, "toArtifactVersions", {
631
631
  enumerable: true,
632
- get: function () { return chunkNDIKMOBJ_cjs.toArtifactVersions; }
632
+ get: function () { return chunk7C77IBQZ_cjs.toArtifactVersions; }
633
633
  });
634
634
  Object.defineProperty(exports, "unescapeMarkdown", {
635
635
  enumerable: true,
636
- get: function () { return chunkNDIKMOBJ_cjs.unescapeMarkdown; }
636
+ get: function () { return chunk7C77IBQZ_cjs.unescapeMarkdown; }
637
637
  });
638
638
  Object.defineProperty(exports, "unwrapCitationLinks", {
639
639
  enumerable: true,
640
- get: function () { return chunkNDIKMOBJ_cjs.unwrapCitationLinks; }
640
+ get: function () { return chunk7C77IBQZ_cjs.unwrapCitationLinks; }
641
641
  });
642
642
  Object.defineProperty(exports, "versionLabel", {
643
643
  enumerable: true,
644
- get: function () { return chunkNDIKMOBJ_cjs.versionLabel; }
644
+ get: function () { return chunk7C77IBQZ_cjs.versionLabel; }
645
645
  });
646
646
  Object.defineProperty(exports, "versionRef", {
647
647
  enumerable: true,
648
- get: function () { return chunkNDIKMOBJ_cjs.versionRef; }
648
+ get: function () { return chunk7C77IBQZ_cjs.versionRef; }
649
649
  });
650
650
  Object.defineProperty(exports, "normalizeMarkdown", {
651
651
  enumerable: true,
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunk5TRUFWKT_cjs = require('../../chunk-5TRUFWKT.cjs');
4
- require('../../chunk-YMB6XUR2.cjs');
3
+ var chunkRHVHNQBR_cjs = require('../../chunk-RHVHNQBR.cjs');
4
+ require('../../chunk-EEIYXVM4.cjs');
5
+ require('../../chunk-GN5IJKTG.cjs');
5
6
  var chunkO32T7XRD_cjs = require('../../chunk-O32T7XRD.cjs');
6
7
  var chunkRLSBRZ6Z_cjs = require('../../chunk-RLSBRZ6Z.cjs');
7
8
  require('../../chunk-N73IMVFF.cjs');
8
- require('../../chunk-NDIKMOBJ.cjs');
9
- require('../../chunk-VOFNX4P6.cjs');
10
- require('../../chunk-EEIYXVM4.cjs');
9
+ require('../../chunk-7C77IBQZ.cjs');
11
10
  require('../../chunk-5NOZDH3F.cjs');
12
11
  require('../../chunk-S6A6FSG7.cjs');
12
+ require('../../chunk-VOFNX4P6.cjs');
13
13
  var react = require('react');
14
14
  var livekitClient = require('livekit-client');
15
15
  var componentsReact = require('@livekit/components-react');
@@ -123,8 +123,8 @@ function useCallTranscriber({
123
123
  const arbi = chunkO32T7XRD_cjs.useArbi();
124
124
  const queryClient = reactQuery.useQueryClient();
125
125
  const profile = arbi.isLoggedIn ? arbi.user.profile() : null;
126
- const myProfileName = profile && chunk5TRUFWKT_cjs.toProfileView(profile).fullName || null;
127
- const deploymentAvailable = chunk5TRUFWKT_cjs.useCallTranscriptionAvailable();
126
+ const myProfileName = profile && chunkRHVHNQBR_cjs.toProfileView(profile).fullName || null;
127
+ const deploymentAvailable = chunkRHVHNQBR_cjs.useCallTranscriptionAvailable();
128
128
  const available = deploymentAvailable && !!callKey;
129
129
  const [state, setState] = react.useState(null);
130
130
  const [creatorExtId, setCreatorExtId] = react.useState(null);
@@ -167,7 +167,7 @@ function useCallTranscriber({
167
167
  };
168
168
  }, [available, callExtId]);
169
169
  react.useEffect(
170
- () => chunk5TRUFWKT_cjs.onCallEvent("call.transcription", (message) => {
170
+ () => chunkRHVHNQBR_cjs.onCallEvent("call.transcription", (message) => {
171
171
  if (message.call_ext_id === callExtId) applyState(message);
172
172
  }),
173
173
  [callExtId, applyState]
@@ -183,7 +183,7 @@ function useCallTranscriber({
183
183
  const persist = react.useCallback(
184
184
  (segment, speakerNeedsProxy) => {
185
185
  if (!callKey || persisted.current.has(segment.segmentId)) return;
186
- const role = chunk5TRUFWKT_cjs.transcriptPersistRole({
186
+ const role = chunkRHVHNQBR_cjs.transcriptPersistRole({
187
187
  myIdentity,
188
188
  canPost: canPost && (segment.speakerIdentity !== myIdentity || selfPosts.current),
189
189
  hasCallKey: true,
@@ -192,7 +192,7 @@ function useCallTranscriber({
192
192
  });
193
193
  if (!role) return;
194
194
  persisted.current.add(segment.segmentId);
195
- chunk5TRUFWKT_cjs.persistTranscriptSegment(arbi, queryClient, callExtId, callKey, segment).catch(
195
+ chunkRHVHNQBR_cjs.persistTranscriptSegment(arbi, queryClient, callExtId, callKey, segment).catch(
196
196
  (err) => {
197
197
  persisted.current.delete(segment.segmentId);
198
198
  if (role === "own" && err?.status === 403) {
@@ -212,7 +212,7 @@ function useCallTranscriber({
212
212
  );
213
213
  react.useEffect(() => {
214
214
  const onData = (payload, participant, _kind, topic, _encryption, participantIdentity) => {
215
- if (topic === chunk5TRUFWKT_cjs.CALL_TRANSCRIPTION_TOPIC) {
215
+ if (topic === chunkRHVHNQBR_cjs.CALL_TRANSCRIPTION_TOPIC) {
216
216
  if (participant || participantIdentity) return;
217
217
  try {
218
218
  const next = browser.calls.transcriptionStateFrom(JSON.parse(new TextDecoder().decode(payload)));
@@ -221,10 +221,10 @@ function useCallTranscriber({
221
221
  }
222
222
  return;
223
223
  }
224
- if (topic !== chunk5TRUFWKT_cjs.CALL_CAPTION_TOPIC || !callKey) return;
224
+ if (topic !== chunkRHVHNQBR_cjs.CALL_CAPTION_TOPIC || !callKey) return;
225
225
  const identity = participant?.identity ?? participantIdentity;
226
226
  if (!identity || identity === myIdentity) return;
227
- void chunk5TRUFWKT_cjs.decodeCaptionPacket(payload, callKey).then((packet) => {
227
+ void chunkRHVHNQBR_cjs.decodeCaptionPacket(payload, callKey).then((packet) => {
228
228
  if (!packet || packet.identity !== identity) return;
229
229
  const name = participant?.name || packet.name || identity;
230
230
  const t = Math.min(packet.t, Date.now());
@@ -264,7 +264,7 @@ function useCallTranscriber({
264
264
  })) {
265
265
  return;
266
266
  }
267
- const segmentId = chunk5TRUFWKT_cjs.newSegmentId();
267
+ const segmentId = chunkRHVHNQBR_cjs.newSegmentId();
268
268
  const startedAt = new Date(segment.startedAt).toISOString();
269
269
  let text;
270
270
  try {
@@ -298,7 +298,7 @@ function useCallTranscriber({
298
298
  });
299
299
  try {
300
300
  await localParticipant.publishData(
301
- await chunk5TRUFWKT_cjs.encodeCaptionPacket(
301
+ await chunkRHVHNQBR_cjs.encodeCaptionPacket(
302
302
  {
303
303
  v: 1,
304
304
  segment_id: segmentId,
@@ -310,7 +310,7 @@ function useCallTranscriber({
310
310
  },
311
311
  callKey
312
312
  ),
313
- { reliable: true, topic: chunk5TRUFWKT_cjs.CALL_CAPTION_TOPIC }
313
+ { reliable: true, topic: chunkRHVHNQBR_cjs.CALL_CAPTION_TOPIC }
314
314
  );
315
315
  } catch (err) {
316
316
  console.warn("[calls] could not broadcast a caption", err);
@@ -425,14 +425,14 @@ function useCallRecorder({
425
425
  };
426
426
  }, [callExtId]);
427
427
  react.useEffect(
428
- () => chunk5TRUFWKT_cjs.onCallEvent("call.recording", (message) => {
428
+ () => chunkRHVHNQBR_cjs.onCallEvent("call.recording", (message) => {
429
429
  if (message.call_ext_id === callExtId) applyState(message);
430
430
  }),
431
431
  [callExtId, applyState]
432
432
  );
433
433
  react.useEffect(() => {
434
434
  const onData = (payload, participant, _kind, topic, _encryption, participantIdentity) => {
435
- if (topic !== chunk5TRUFWKT_cjs.CALL_RECORDING_TOPIC) return;
435
+ if (topic !== chunkRHVHNQBR_cjs.CALL_RECORDING_TOPIC) return;
436
436
  if (participant || participantIdentity) return;
437
437
  try {
438
438
  const next = browser.calls.recordingStateFrom(JSON.parse(new TextDecoder().decode(payload)));
@@ -453,7 +453,7 @@ function useCallRecorder({
453
453
  try {
454
454
  const row = call ?? await arbi.calls.get(callExtId);
455
455
  if (!row.workspace_locked && !row.chat_ext_id && callKey) {
456
- const ref = await chunk5TRUFWKT_cjs.ensureMeetingChat(arbi, queryClient, callExtId, callKey);
456
+ const ref = await chunkRHVHNQBR_cjs.ensureMeetingChat(arbi, queryClient, callExtId, callKey);
457
457
  if (ref.kind === "chat") setCall({ ...row, chat_ext_id: ref.chatExtId });
458
458
  }
459
459
  const answer = await arbi.calls.recording.start(callExtId, mode);
@@ -555,7 +555,7 @@ function useTrackUploader(recording, callKey, kind, mimeType) {
555
555
  const queryClient = reactQuery.useQueryClient();
556
556
  return react.useMemo(() => {
557
557
  if (!shouldCapture || !recordingExtId || !call) return null;
558
- return chunk5TRUFWKT_cjs.trackUploaderFor({
558
+ return chunkRHVHNQBR_cjs.trackUploaderFor({
559
559
  arbi,
560
560
  callExtId: call.external_id,
561
561
  recordingExtId,
@@ -563,7 +563,7 @@ function useTrackUploader(recording, callKey, kind, mimeType) {
563
563
  mimeType,
564
564
  recordingStartedAt: startedAt,
565
565
  linkVersion,
566
- conversationKey: () => chunk5TRUFWKT_cjs.conversationKeyForCall(arbi, queryClient, call, { callKey }),
566
+ conversationKey: () => chunkRHVHNQBR_cjs.conversationKeyForCall(arbi, queryClient, call, { callKey }),
567
567
  // The server stopped the recording at the quota (its state event says so too).
568
568
  onStopped: () => markStopped()
569
569
  });
@@ -612,10 +612,10 @@ function useInCallChat({
612
612
  react.useEffect(() => {
613
613
  if (!callKey) return;
614
614
  const onData = (payload, participant, _kind, topic, _encryption, participantIdentity) => {
615
- if (topic !== chunk5TRUFWKT_cjs.CALL_CHAT_TOPIC) return;
615
+ if (topic !== chunkRHVHNQBR_cjs.CALL_CHAT_TOPIC) return;
616
616
  const identity = participant?.identity ?? participantIdentity;
617
617
  if (!identity || identity === myIdentity) return;
618
- void chunk5TRUFWKT_cjs.decodeCallChatPacket(payload, callKey).then((packet) => {
618
+ void chunkRHVHNQBR_cjs.decodeCallChatPacket(payload, callKey).then((packet) => {
619
619
  if (!packet) return;
620
620
  const key = `${identity}:${packet.id}`;
621
621
  if (seen.current.has(key)) return;
@@ -645,7 +645,7 @@ function useInCallChat({
645
645
  if (!open || !canRead || historyRequested.current) return;
646
646
  historyRequested.current = true;
647
647
  setHistoryLoading(true);
648
- chunk5TRUFWKT_cjs.loadMeetingHistory(arbi, queryClient, callExtId).then((result) => {
648
+ chunkRHVHNQBR_cjs.loadMeetingHistory(arbi, queryClient, callExtId).then((result) => {
649
649
  if (!result) return;
650
650
  setMeetingChat(result.ref);
651
651
  setHistory(result.messages);
@@ -656,13 +656,13 @@ function useInCallChat({
656
656
  }, [open, canRead, callExtId]);
657
657
  const send = react.useCallback(
658
658
  async (raw) => {
659
- const text = raw.trim().slice(0, chunk5TRUFWKT_cjs.CALL_CHAT_MAX_CHARS);
659
+ const text = raw.trim().slice(0, chunkRHVHNQBR_cjs.CALL_CHAT_MAX_CHARS);
660
660
  if (!text || !callKey || readOnly) return;
661
- const id = chunk5TRUFWKT_cjs.newPacketId();
661
+ const id = chunkRHVHNQBR_cjs.newPacketId();
662
662
  const at = Date.now();
663
663
  await localParticipant.publishData(
664
- await chunk5TRUFWKT_cjs.encodeCallChatPacket({ v: 1, id, text, at }, callKey),
665
- { reliable: true, topic: chunk5TRUFWKT_cjs.CALL_CHAT_TOPIC }
664
+ await chunkRHVHNQBR_cjs.encodeCallChatPacket({ v: 1, id, text, at }, callKey),
665
+ { reliable: true, topic: chunkRHVHNQBR_cjs.CALL_CHAT_TOPIC }
666
666
  );
667
667
  setLive((prev) => [
668
668
  ...prev,
@@ -681,7 +681,7 @@ function useInCallChat({
681
681
  (prev) => prev.map((l) => l.id === id && l.senderIdentity === myIdentity ? { ...l, status } : l)
682
682
  );
683
683
  try {
684
- setMeetingChat(await chunk5TRUFWKT_cjs.persistMeetingMessage(arbi, queryClient, callExtId, callKey, text));
684
+ setMeetingChat(await chunkRHVHNQBR_cjs.persistMeetingMessage(arbi, queryClient, callExtId, callKey, text));
685
685
  mark("saved");
686
686
  } catch (err) {
687
687
  console.warn("[calls] could not keep the message in the meeting chat", err);
@@ -693,7 +693,7 @@ function useInCallChat({
693
693
  const openMeeting = react.useCallback(async () => {
694
694
  if (!callKey) return;
695
695
  try {
696
- const ref = meetingChat ?? await chunk5TRUFWKT_cjs.ensureMeetingChat(arbi, queryClient, callExtId, callKey);
696
+ const ref = meetingChat ?? await chunkRHVHNQBR_cjs.ensureMeetingChat(arbi, queryClient, callExtId, callKey);
697
697
  setMeetingChat(ref);
698
698
  openMeetingChat?.(ref);
699
699
  } catch (err) {
@@ -701,7 +701,7 @@ function useInCallChat({
701
701
  }
702
702
  }, [callExtId, callKey, meetingChat]);
703
703
  const lines = react.useMemo(
704
- () => chunk5TRUFWKT_cjs.mergeChatLines(history, live, {
704
+ () => chunkRHVHNQBR_cjs.mergeChatLines(history, live, {
705
705
  myIdentity,
706
706
  nameOf: (identity) => identity === myIdentity ? localParticipant.name || "You" : room.remoteParticipants.get(identity)?.name || null
707
707
  }),
@@ -760,7 +760,7 @@ function useWebinar({
760
760
  const n = ++questionsRead.current;
761
761
  try {
762
762
  const rows = await webinarApi().questions.list(callExtId, linkVersion);
763
- const opened = await Promise.all(rows.map((q) => chunk5TRUFWKT_cjs.openQuestion(q, callKey)));
763
+ const opened = await Promise.all(rows.map((q) => chunkRHVHNQBR_cjs.openQuestion(q, callKey)));
764
764
  if (n === questionsRead.current) setQuestions(opened);
765
765
  } catch (err) {
766
766
  console.warn("[calls] could not load the questions", err);
@@ -772,7 +772,7 @@ function useWebinar({
772
772
  }, [refresh, refreshQuestions]);
773
773
  react.useEffect(() => {
774
774
  if (!enabled) return;
775
- return chunk5TRUFWKT_cjs.onCallEvent("call.webinar", (m) => {
775
+ return chunkRHVHNQBR_cjs.onCallEvent("call.webinar", (m) => {
776
776
  if (m.call_ext_id !== callExtId) return;
777
777
  setState((s) => s ? { ...s, live: m.live, chat: m.chat } : s);
778
778
  });
@@ -781,8 +781,8 @@ function useWebinar({
781
781
  react.useEffect(() => {
782
782
  if (!enabled) return;
783
783
  const onData = (payload, participant, _kind, topic, _encryption, participantIdentity) => {
784
- if (topic !== chunk5TRUFWKT_cjs.CALL_WEBINAR_TOPIC) return;
785
- const packet = chunk5TRUFWKT_cjs.parseWebinarPacket(payload, !!(participant || participantIdentity));
784
+ if (topic !== chunkRHVHNQBR_cjs.CALL_WEBINAR_TOPIC) return;
785
+ const packet = chunkRHVHNQBR_cjs.parseWebinarPacket(payload, !!(participant || participantIdentity));
786
786
  if (!packet) return;
787
787
  switch (packet.type) {
788
788
  case "state":
@@ -803,7 +803,7 @@ function useWebinar({
803
803
  return;
804
804
  case "demoted":
805
805
  setStageCheck(false);
806
- chunk5TRUFWKT_cjs.markRejoining(callExtId);
806
+ chunkRHVHNQBR_cjs.markRejoining(callExtId);
807
807
  if (fallback.current) clearTimeout(fallback.current);
808
808
  fallback.current = setTimeout(() => void room.disconnect(), DEMOTE_REJOIN_FALLBACK_MS);
809
809
  return;
@@ -830,12 +830,12 @@ function useWebinar({
830
830
  [callExtId, linkVersion]
831
831
  );
832
832
  const stepDown = react.useCallback(async () => {
833
- chunk5TRUFWKT_cjs.markRejoining(callExtId);
833
+ chunkRHVHNQBR_cjs.markRejoining(callExtId);
834
834
  setStageCheck(false);
835
835
  try {
836
836
  await webinarApi().demote(callExtId, myIdentity, linkVersion);
837
837
  } catch (err) {
838
- chunk5TRUFWKT_cjs.markRejoining(callExtId, false);
838
+ chunkRHVHNQBR_cjs.markRejoining(callExtId, false);
839
839
  failed("leave the stage")(err);
840
840
  }
841
841
  }, [callExtId, myIdentity, linkVersion]);
@@ -895,7 +895,7 @@ function useWebinar({
895
895
  if (!callKey) throw new Error("This call has no key.");
896
896
  await webinarApi().questions.ask(
897
897
  callExtId,
898
- await chunk5TRUFWKT_cjs.sealQuestionText(text, callKey),
898
+ await chunkRHVHNQBR_cjs.sealQuestionText(text, callKey),
899
899
  linkVersion
900
900
  );
901
901
  }, "ask the question"),
@@ -909,7 +909,7 @@ function useWebinar({
909
909
  await webinarApi().questions.update(
910
910
  callExtId,
911
911
  id,
912
- { answer: await chunk5TRUFWKT_cjs.sealQuestionText(text, callKey) },
912
+ { answer: await chunkRHVHNQBR_cjs.sealQuestionText(text, callKey) },
913
913
  linkVersion
914
914
  );
915
915
  }, "answer the question"),
@@ -939,15 +939,15 @@ function useWebinar({
939
939
  function useHostMuteNotice(callExtId) {
940
940
  const room = componentsReact.useRoomContext();
941
941
  react.useEffect(() => {
942
- const notifyMuted = chunk5TRUFWKT_cjs.createMutedNotifier((text) => chunkRLSBRZ6Z_cjs.notify.info(text));
942
+ const notifyMuted = chunkRHVHNQBR_cjs.createMutedNotifier((text) => chunkRLSBRZ6Z_cjs.notify.info(text));
943
943
  const onData = (payload, participant, _kind, topic, _encryption, participantIdentity) => {
944
- if (topic !== chunk5TRUFWKT_cjs.CALL_MODERATION_TOPIC) return;
944
+ if (topic !== chunkRHVHNQBR_cjs.CALL_MODERATION_TOPIC) return;
945
945
  if (participant || participantIdentity) return;
946
- const notice = chunk5TRUFWKT_cjs.mutedNoticeFromPacket(payload);
946
+ const notice = chunkRHVHNQBR_cjs.mutedNoticeFromPacket(payload);
947
947
  if (notice) notifyMuted(notice);
948
948
  };
949
949
  room.on(livekitClient.RoomEvent.DataReceived, onData);
950
- const offWs = chunk5TRUFWKT_cjs.onCallEvent("call.muted", (message) => {
950
+ const offWs = chunkRHVHNQBR_cjs.onCallEvent("call.muted", (message) => {
951
951
  if (message.callExtId === callExtId) notifyMuted(message);
952
952
  });
953
953
  return () => {
@@ -27,7 +27,29 @@ function cacheThreadBinding(queryClient, conversationId, binding) {
27
27
  (old) => old ? { ...old, ...fields } : old
28
28
  );
29
29
  }
30
- async function bindThreadDocument(arbi, queryClient, conversationId, documentId) {
30
+ const bindingWrites = /* @__PURE__ */ new WeakMap();
31
+ function bindThreadDocument(arbi, queryClient, conversationId, documentId) {
32
+ let writes = bindingWrites.get(queryClient);
33
+ if (!writes) {
34
+ writes = /* @__PURE__ */ new Map();
35
+ bindingWrites.set(queryClient, writes);
36
+ }
37
+ const previous = writes.get(conversationId);
38
+ const write = () => performBindingWrite(arbi, queryClient, conversationId, documentId);
39
+ const operation = previous ? previous.then(write, write) : write();
40
+ const tail = operation.then(
41
+ () => {
42
+ },
43
+ () => {
44
+ }
45
+ );
46
+ writes.set(conversationId, tail);
47
+ void tail.then(() => {
48
+ if (writes.get(conversationId) === tail) writes.delete(conversationId);
49
+ });
50
+ return operation;
51
+ }
52
+ async function performBindingWrite(arbi, queryClient, conversationId, documentId) {
31
53
  const before = threadBinding(queryClient, conversationId);
32
54
  if (before.documentId === documentId && !before.unavailable) return;
33
55
  cacheThreadBinding(queryClient, conversationId, { documentId, unavailable: false });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/chat/thread-binding.ts"],
4
- "sourcesContent": ["/**\n * A conversation's bound document in the query cache, and the writes that change it on the server.\n *\n * The server holds the binding (`./thread-document`); the cache is its mirror: the conversation's\n * row in the workspace's list (`bound_document_ext_id`, `bound_document_unavailable`), else its\n * threads response (a thread opened from a link, not listed yet). An attach or unbind shows at once\n * and is written with `PATCH /v1/conversation/{id}`; a failure puts the cache back. Another\n * member's or device's change arrives as `conversation.document_binding_changed`\n * (`./conversation-events`), which re-reads the conversation under this reader's access.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi, ConversationResponse, ThreadsResponse } from '@arbidocs/sdk/browser'\nimport { findConversation, patchConversation } from '../conversation-list'\nimport { getThreadsQueryKey } from './conversation-cache'\nimport {\n UNBOUND,\n bindingOfRow,\n forgetLegacyThreadDocuments,\n readLegacyThreadDocuments,\n type ThreadBinding,\n} from './thread-document'\n\n/** What this module needs of the session store (structural, like the rest of the chat engine). */\ninterface NewChatSession {\n getState(): { conversationId: string | null; newChatDocumentId: string | null }\n setNewChatDocumentId(documentId: string | null): void\n}\n\n/** A saved conversation's binding, from the cache (its list row, else its threads). */\nexport function threadBinding(\n queryClient: QueryClient,\n conversationId: string | null | undefined\n): ThreadBinding {\n if (!conversationId) return UNBOUND\n const row = findConversation(queryClient, conversationId)\n if (row) return bindingOfRow(row)\n const threads = queryClient.getQueryData<ThreadsResponse>(getThreadsQueryKey(conversationId))\n return bindingOfRow(threads ? { external_id: conversationId, ...threads } : null)\n}\n\n/** The document the open conversation is bound to: its saved binding, or the new chat's. */\nexport function boundDocumentOf(\n queryClient: QueryClient,\n state: ReturnType<NewChatSession['getState']>\n): string | null {\n return state.conversationId\n ? threadBinding(queryClient, state.conversationId).documentId\n : state.newChatDocumentId\n}\n\n/** Put a binding in the cache (the list rows and the threads response that hold the conversation). */\nexport function cacheThreadBinding(\n queryClient: QueryClient,\n conversationId: string,\n binding: ThreadBinding\n): void {\n const fields = {\n bound_document_ext_id: binding.documentId,\n bound_document_unavailable: binding.unavailable,\n }\n patchConversation(queryClient, conversationId, fields)\n queryClient.setQueryData<ThreadsResponse>(getThreadsQueryKey(conversationId), (old) =>\n old ? { ...old, ...fields } : old\n )\n}\n\n/**\n * Bind a saved conversation to a document, or (null) unbind it: shown at once, written to the\n * server. Rejects (with the cache put back) when the server refuses: a document of another\n * workspace, or one the caller cannot read.\n */\nexport async function bindThreadDocument(\n arbi: Pick<Arbi, 'conversations'>,\n queryClient: QueryClient,\n conversationId: string,\n documentId: string | null\n): Promise<void> {\n const before = threadBinding(queryClient, conversationId)\n if (before.documentId === documentId && !before.unavailable) return\n cacheThreadBinding(queryClient, conversationId, { documentId, unavailable: false })\n try {\n const saved: ConversationResponse = await arbi.conversations.update(conversationId, {\n bound_document_ext_id: documentId,\n })\n patchConversation(queryClient, conversationId, saved)\n cacheThreadBinding(queryClient, conversationId, bindingOfRow(saved))\n } catch (error) {\n cacheThreadBinding(queryClient, conversationId, before)\n throw error\n }\n}\n\n/**\n * A new chat got its server id: the document its first turn was sent with is now the\n * conversation's (the server bound it with that turn). Call it once the conversation's row is in\n * the list; `documentId` defaults to the session's new-chat binding.\n */\nexport function adoptNewChatDocument(\n session: NewChatSession,\n queryClient: QueryClient,\n conversationId: string,\n documentId: string | null = session.getState().newChatDocumentId\n): void {\n if (!documentId) return\n cacheThreadBinding(queryClient, conversationId, { documentId, unavailable: false })\n if (session.getState().newChatDocumentId === documentId) session.setNewChatDocumentId(null)\n}\n\n/**\n * Move the bindings this browser kept locally (before the server held them) to the server, for\n * the conversations of a workspace's list, then forget them here. A conversation the server\n * already binds keeps its server binding. Runs once per list it is given; the key is removed when\n * the last kept binding is moved.\n */\nexport async function migrateLegacyThreadDocuments(\n arbi: Pick<Arbi, 'conversations'>,\n queryClient: QueryClient,\n conversations: readonly ConversationResponse[]\n): Promise<void> {\n const legacy = readLegacyThreadDocuments()\n // Only rows from a server that holds bindings (they carry the field): never lose a kept one.\n const listed = conversations.filter(\n (c) => c.external_id in legacy && 'bound_document_unavailable' in c\n )\n if (listed.length === 0) return\n await Promise.all(\n listed.map(async (row) => {\n const server = bindingOfRow(row)\n if (server.documentId || server.unavailable) return\n try {\n await bindThreadDocument(arbi, queryClient, row.external_id, legacy[row.external_id])\n } catch {\n // The document is gone or not readable any more: nothing to keep.\n }\n })\n )\n forgetLegacyThreadDocuments(listed.map((c) => c.external_id))\n}\n"],
5
- "mappings": "AAaA,SAAS,kBAAkB,yBAAyB;AACpD,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AASA,SAAS,cACd,aACA,gBACe;AACf,MAAI,CAAC,eAAgB,QAAO;AAC5B,QAAM,MAAM,iBAAiB,aAAa,cAAc;AACxD,MAAI,IAAK,QAAO,aAAa,GAAG;AAChC,QAAM,UAAU,YAAY,aAA8B,mBAAmB,cAAc,CAAC;AAC5F,SAAO,aAAa,UAAU,EAAE,aAAa,gBAAgB,GAAG,QAAQ,IAAI,IAAI;AAClF;AAGO,SAAS,gBACd,aACA,OACe;AACf,SAAO,MAAM,iBACT,cAAc,aAAa,MAAM,cAAc,EAAE,aACjD,MAAM;AACZ;AAGO,SAAS,mBACd,aACA,gBACA,SACM;AACN,QAAM,SAAS;AAAA,IACb,uBAAuB,QAAQ;AAAA,IAC/B,4BAA4B,QAAQ;AAAA,EACtC;AACA,oBAAkB,aAAa,gBAAgB,MAAM;AACrD,cAAY;AAAA,IAA8B,mBAAmB,cAAc;AAAA,IAAG,CAAC,QAC7E,MAAM,EAAE,GAAG,KAAK,GAAG,OAAO,IAAI;AAAA,EAChC;AACF;AAOA,eAAsB,mBACpB,MACA,aACA,gBACA,YACe;AACf,QAAM,SAAS,cAAc,aAAa,cAAc;AACxD,MAAI,OAAO,eAAe,cAAc,CAAC,OAAO,YAAa;AAC7D,qBAAmB,aAAa,gBAAgB,EAAE,YAAY,aAAa,MAAM,CAAC;AAClF,MAAI;AACF,UAAM,QAA8B,MAAM,KAAK,cAAc,OAAO,gBAAgB;AAAA,MAClF,uBAAuB;AAAA,IACzB,CAAC;AACD,sBAAkB,aAAa,gBAAgB,KAAK;AACpD,uBAAmB,aAAa,gBAAgB,aAAa,KAAK,CAAC;AAAA,EACrE,SAAS,OAAO;AACd,uBAAmB,aAAa,gBAAgB,MAAM;AACtD,UAAM;AAAA,EACR;AACF;AAOO,SAAS,qBACd,SACA,aACA,gBACA,aAA4B,QAAQ,SAAS,EAAE,mBACzC;AACN,MAAI,CAAC,WAAY;AACjB,qBAAmB,aAAa,gBAAgB,EAAE,YAAY,aAAa,MAAM,CAAC;AAClF,MAAI,QAAQ,SAAS,EAAE,sBAAsB,WAAY,SAAQ,qBAAqB,IAAI;AAC5F;AAQA,eAAsB,6BACpB,MACA,aACA,eACe;AACf,QAAM,SAAS,0BAA0B;AAEzC,QAAM,SAAS,cAAc;AAAA,IAC3B,CAAC,MAAM,EAAE,eAAe,UAAU,gCAAgC;AAAA,EACpE;AACA,MAAI,OAAO,WAAW,EAAG;AACzB,QAAM,QAAQ;AAAA,IACZ,OAAO,IAAI,OAAO,QAAQ;AACxB,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,OAAO,cAAc,OAAO,YAAa;AAC7C,UAAI;AACF,cAAM,mBAAmB,MAAM,aAAa,IAAI,aAAa,OAAO,IAAI,WAAW,CAAC;AAAA,MACtF,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AAAA,EACH;AACA,8BAA4B,OAAO,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC;AAC9D;",
4
+ "sourcesContent": ["/**\n * A conversation's bound document in the query cache, and the writes that change it on the server.\n *\n * The server holds the binding (`./thread-document`); the cache is its mirror: the conversation's\n * row in the workspace's list (`bound_document_ext_id`, `bound_document_unavailable`), else its\n * threads response (a thread opened from a link, not listed yet). An attach or unbind shows at once\n * and is written with `PATCH /v1/conversation/{id}`; a failure puts the cache back. Another\n * member's or device's change arrives as `conversation.document_binding_changed`\n * (`./conversation-events`), which re-reads the conversation under this reader's access.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi, ConversationResponse, ThreadsResponse } from '@arbidocs/sdk/browser'\nimport { findConversation, patchConversation } from '../conversation-list'\nimport { getThreadsQueryKey } from './conversation-cache'\nimport {\n UNBOUND,\n bindingOfRow,\n forgetLegacyThreadDocuments,\n readLegacyThreadDocuments,\n type ThreadBinding,\n} from './thread-document'\n\n/** What this module needs of the session store (structural, like the rest of the chat engine). */\ninterface NewChatSession {\n getState(): { conversationId: string | null; newChatDocumentId: string | null }\n setNewChatDocumentId(documentId: string | null): void\n}\n\n/** A saved conversation's binding, from the cache (its list row, else its threads). */\nexport function threadBinding(\n queryClient: QueryClient,\n conversationId: string | null | undefined\n): ThreadBinding {\n if (!conversationId) return UNBOUND\n const row = findConversation(queryClient, conversationId)\n if (row) return bindingOfRow(row)\n const threads = queryClient.getQueryData<ThreadsResponse>(getThreadsQueryKey(conversationId))\n return bindingOfRow(threads ? { external_id: conversationId, ...threads } : null)\n}\n\n/** The document the open conversation is bound to: its saved binding, or the new chat's. */\nexport function boundDocumentOf(\n queryClient: QueryClient,\n state: ReturnType<NewChatSession['getState']>\n): string | null {\n return state.conversationId\n ? threadBinding(queryClient, state.conversationId).documentId\n : state.newChatDocumentId\n}\n\n/** Put a binding in the cache (the list rows and the threads response that hold the conversation). */\nexport function cacheThreadBinding(\n queryClient: QueryClient,\n conversationId: string,\n binding: ThreadBinding\n): void {\n const fields = {\n bound_document_ext_id: binding.documentId,\n bound_document_unavailable: binding.unavailable,\n }\n patchConversation(queryClient, conversationId, fields)\n queryClient.setQueryData<ThreadsResponse>(getThreadsQueryKey(conversationId), (old) =>\n old ? { ...old, ...fields } : old\n )\n}\n\n/**\n * Bind a saved conversation to a document, or (null) unbind it: shown at once, written to the\n * server. Rejects (with the cache put back) when the server refuses: a document of another\n * workspace, or one the caller cannot read.\n */\nconst bindingWrites = new WeakMap<QueryClient, Map<string, Promise<void>>>()\n\nexport function bindThreadDocument(\n arbi: Pick<Arbi, 'conversations'>,\n queryClient: QueryClient,\n conversationId: string,\n documentId: string | null\n): Promise<void> {\n let writes = bindingWrites.get(queryClient)\n if (!writes) {\n writes = new Map()\n bindingWrites.set(queryClient, writes)\n }\n const previous = writes.get(conversationId)\n const write = () => performBindingWrite(arbi, queryClient, conversationId, documentId)\n const operation = previous ? previous.then(write, write) : write()\n const tail = operation.then(\n () => {},\n () => {}\n )\n writes.set(conversationId, tail)\n void tail.then(() => {\n if (writes!.get(conversationId) === tail) writes!.delete(conversationId)\n })\n return operation\n}\n\nasync function performBindingWrite(\n arbi: Pick<Arbi, 'conversations'>,\n queryClient: QueryClient,\n conversationId: string,\n documentId: string | null\n): Promise<void> {\n const before = threadBinding(queryClient, conversationId)\n if (before.documentId === documentId && !before.unavailable) return\n cacheThreadBinding(queryClient, conversationId, { documentId, unavailable: false })\n try {\n const saved: ConversationResponse = await arbi.conversations.update(conversationId, {\n bound_document_ext_id: documentId,\n })\n patchConversation(queryClient, conversationId, saved)\n cacheThreadBinding(queryClient, conversationId, bindingOfRow(saved))\n } catch (error) {\n cacheThreadBinding(queryClient, conversationId, before)\n throw error\n }\n}\n\n/**\n * A new chat got its server id: the document its first turn was sent with is now the\n * conversation's (the server bound it with that turn). Call it once the conversation's row is in\n * the list; `documentId` defaults to the session's new-chat binding.\n */\nexport function adoptNewChatDocument(\n session: NewChatSession,\n queryClient: QueryClient,\n conversationId: string,\n documentId: string | null = session.getState().newChatDocumentId\n): void {\n if (!documentId) return\n cacheThreadBinding(queryClient, conversationId, { documentId, unavailable: false })\n if (session.getState().newChatDocumentId === documentId) session.setNewChatDocumentId(null)\n}\n\n/**\n * Move the bindings this browser kept locally (before the server held them) to the server, for\n * the conversations of a workspace's list, then forget them here. A conversation the server\n * already binds keeps its server binding. Runs once per list it is given; the key is removed when\n * the last kept binding is moved.\n */\nexport async function migrateLegacyThreadDocuments(\n arbi: Pick<Arbi, 'conversations'>,\n queryClient: QueryClient,\n conversations: readonly ConversationResponse[]\n): Promise<void> {\n const legacy = readLegacyThreadDocuments()\n // Only rows from a server that holds bindings (they carry the field): never lose a kept one.\n const listed = conversations.filter(\n (c) => c.external_id in legacy && 'bound_document_unavailable' in c\n )\n if (listed.length === 0) return\n await Promise.all(\n listed.map(async (row) => {\n const server = bindingOfRow(row)\n if (server.documentId || server.unavailable) return\n try {\n await bindThreadDocument(arbi, queryClient, row.external_id, legacy[row.external_id])\n } catch {\n // The document is gone or not readable any more: nothing to keep.\n }\n })\n )\n forgetLegacyThreadDocuments(listed.map((c) => c.external_id))\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,15 +1,15 @@
1
1
  import { useEffect } from "react";
2
2
  import { selectDraft, useArbiSessionState, useArbiSessionStore } from "../session/index.js";
3
- function useAutoSendDraft(sendDraft, ready = true) {
3
+ function useAutoSendDraft(sendDraft, ready = true, canSend) {
4
4
  const session = useArbiSessionStore();
5
5
  const autoSendDraft = useArbiSessionState((state) => state.autoSendDraft);
6
6
  useEffect(() => {
7
- if (!autoSendDraft || !ready) return;
7
+ if (!autoSendDraft || !ready || canSend && !canSend()) return;
8
8
  session.setAutoSendDraft(false);
9
9
  if (selectDraft(session.getState()).trim()) {
10
10
  sendDraft();
11
11
  }
12
- }, [autoSendDraft, ready, sendDraft, session]);
12
+ }, [autoSendDraft, ready, canSend, sendDraft, session]);
13
13
  }
14
14
  export {
15
15
  useAutoSendDraft
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/chat/useAutoSendDraft.ts"],
4
- "sourcesContent": ["/**\n * Fires the composer's send once when a quick-access surface (the workspace\n * home's ask bar) handed over a draft that should send on arrival \u2014 the user\n * already pressed Enter there; asking for a second Enter here would turn one\n * action into two.\n *\n * `ready` defers consumption: the flag stays set (and the effect re-runs when\n * `ready` flips) so the send can wait for the page's context to assemble \u2014\n * concretely, the workspace documents that useDocumentAutoAdd attaches to a\n * new chat. Sending before that seeding posts the question with no documents,\n * which answers from nothing. The CALL SITE must sit after useDocumentAutoAdd\n * in the component: effects run in declaration order, so that placement is\n * what guarantees the seeding effect has run by the time this one fires.\n *\n * One-shot: the flag is cleared before sending, so a failed send never\n * retries itself.\n */\n\nimport { useEffect } from 'react'\nimport { selectDraft, useArbiSessionState, useArbiSessionStore } from '../session'\n\nexport function useAutoSendDraft(sendDraft: () => void, ready: boolean = true) {\n const session = useArbiSessionStore()\n const autoSendDraft = useArbiSessionState((state) => state.autoSendDraft)\n useEffect(() => {\n if (!autoSendDraft || !ready) return\n session.setAutoSendDraft(false)\n if (selectDraft(session.getState()).trim()) {\n sendDraft()\n }\n }, [autoSendDraft, ready, sendDraft, session])\n}\n"],
5
- "mappings": "AAkBA,SAAS,iBAAiB;AAC1B,SAAS,aAAa,qBAAqB,2BAA2B;AAE/D,SAAS,iBAAiB,WAAuB,QAAiB,MAAM;AAC7E,QAAM,UAAU,oBAAoB;AACpC,QAAM,gBAAgB,oBAAoB,CAAC,UAAU,MAAM,aAAa;AACxE,YAAU,MAAM;AACd,QAAI,CAAC,iBAAiB,CAAC,MAAO;AAC9B,YAAQ,iBAAiB,KAAK;AAC9B,QAAI,YAAY,QAAQ,SAAS,CAAC,EAAE,KAAK,GAAG;AAC1C,gBAAU;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,eAAe,OAAO,WAAW,OAAO,CAAC;AAC/C;",
4
+ "sourcesContent": ["/**\n * Fires the composer's send once when a quick-access surface (the workspace\n * home's ask bar) handed over a draft that should send on arrival \u2014 the user\n * already pressed Enter there; asking for a second Enter here would turn one\n * action into two.\n *\n * `ready` defers consumption: the flag stays set (and the effect re-runs when\n * `ready` flips) so the send can wait for the page's context to assemble \u2014\n * concretely, the workspace documents that useDocumentAutoAdd attaches to a\n * new chat. Sending before that seeding posts the question with no documents,\n * which answers from nothing. The CALL SITE must sit after useDocumentAutoAdd\n * in the component: effects run in declaration order, so that placement is\n * what guarantees the seeding effect has run by the time this one fires.\n *\n * One-shot: the flag is cleared before sending, so a failed send never\n * retries itself.\n */\n\nimport { useEffect } from 'react'\nimport { selectDraft, useArbiSessionState, useArbiSessionStore } from '../session'\n\nexport function useAutoSendDraft(\n sendDraft: () => void,\n ready: boolean = true,\n canSend?: () => boolean\n) {\n const session = useArbiSessionStore()\n const autoSendDraft = useArbiSessionState((state) => state.autoSendDraft)\n useEffect(() => {\n if (!autoSendDraft || !ready || (canSend && !canSend())) return\n session.setAutoSendDraft(false)\n if (selectDraft(session.getState()).trim()) {\n sendDraft()\n }\n }, [autoSendDraft, ready, canSend, sendDraft, session])\n}\n"],
5
+ "mappings": "AAkBA,SAAS,iBAAiB;AAC1B,SAAS,aAAa,qBAAqB,2BAA2B;AAE/D,SAAS,iBACd,WACA,QAAiB,MACjB,SACA;AACA,QAAM,UAAU,oBAAoB;AACpC,QAAM,gBAAgB,oBAAoB,CAAC,UAAU,MAAM,aAAa;AACxE,YAAU,MAAM;AACd,QAAI,CAAC,iBAAiB,CAAC,SAAU,WAAW,CAAC,QAAQ,EAAI;AACzD,YAAQ,iBAAiB,KAAK;AAC9B,QAAI,YAAY,QAAQ,SAAS,CAAC,EAAE,KAAK,GAAG;AAC1C,gBAAU;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,eAAe,OAAO,SAAS,WAAW,OAAO,CAAC;AACxD;",
6
6
  "names": []
7
7
  }