@arbidocs/react 0.3.171 → 0.3.172

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.
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkZMTLGO3K_cjs = require('./chunk-ZMTLGO3K.cjs');
4
3
  var chunk5DV7FW6T_cjs = require('./chunk-5DV7FW6T.cjs');
4
+ var chunkRWCMW36I_cjs = require('./chunk-RWCMW36I.cjs');
5
5
  var React2 = require('react');
6
6
  var reactQuery = require('@tanstack/react-query');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -346,7 +346,7 @@ function agentStatusStyle(theme) {
346
346
  };
347
347
  }
348
348
  function AuthScreen({ theme, labels, onLogin }) {
349
- const arbi = chunkZMTLGO3K_cjs.useArbi();
349
+ const arbi = chunkRWCMW36I_cjs.useArbi();
350
350
  const [mode, setMode] = React2.useState("login");
351
351
  const [step, setStep] = React2.useState("email");
352
352
  const [email, setEmail] = React2.useState("");
@@ -603,7 +603,7 @@ var arbiQueryKeys = {
603
603
  userUsageToday: () => ["arbi", "userUsageToday"]
604
604
  };
605
605
  function useWorkspaces(options) {
606
- const arbi = chunkZMTLGO3K_cjs.useArbi();
606
+ const arbi = chunkRWCMW36I_cjs.useArbi();
607
607
  return reactQuery.useQuery({
608
608
  queryKey: arbiQueryKeys.workspaces(),
609
609
  queryFn: () => arbi.workspaces.list(),
@@ -611,7 +611,7 @@ function useWorkspaces(options) {
611
611
  });
612
612
  }
613
613
  function useDocuments(workspaceId, options) {
614
- const arbi = chunkZMTLGO3K_cjs.useArbi();
614
+ const arbi = chunkRWCMW36I_cjs.useArbi();
615
615
  return reactQuery.useQuery({
616
616
  queryKey: arbiQueryKeys.documents(workspaceId ?? ""),
617
617
  queryFn: () => arbi.documents.list(),
@@ -619,7 +619,7 @@ function useDocuments(workspaceId, options) {
619
619
  });
620
620
  }
621
621
  function useConversations(workspaceId, options) {
622
- const arbi = chunkZMTLGO3K_cjs.useArbi();
622
+ const arbi = chunkRWCMW36I_cjs.useArbi();
623
623
  return reactQuery.useQuery({
624
624
  queryKey: arbiQueryKeys.conversations(workspaceId ?? ""),
625
625
  queryFn: () => arbi.conversations.list(),
@@ -627,7 +627,7 @@ function useConversations(workspaceId, options) {
627
627
  });
628
628
  }
629
629
  function useTags(workspaceId, options) {
630
- const arbi = chunkZMTLGO3K_cjs.useArbi();
630
+ const arbi = chunkRWCMW36I_cjs.useArbi();
631
631
  return reactQuery.useQuery({
632
632
  queryKey: arbiQueryKeys.tags(workspaceId ?? ""),
633
633
  queryFn: () => arbi.tags.list(),
@@ -635,7 +635,7 @@ function useTags(workspaceId, options) {
635
635
  });
636
636
  }
637
637
  function useThumbnails(docIds, options) {
638
- const arbi = chunkZMTLGO3K_cjs.useArbi();
638
+ const arbi = chunkRWCMW36I_cjs.useArbi();
639
639
  return reactQuery.useQuery({
640
640
  queryKey: arbiQueryKeys.thumbnails(docIds),
641
641
  queryFn: () => arbi.documents.getThumbnails(docIds),
@@ -644,7 +644,7 @@ function useThumbnails(docIds, options) {
644
644
  });
645
645
  }
646
646
  function useParsedDocument(docId, stage = "final", options) {
647
- const arbi = chunkZMTLGO3K_cjs.useArbi();
647
+ const arbi = chunkRWCMW36I_cjs.useArbi();
648
648
  return reactQuery.useQuery({
649
649
  queryKey: arbiQueryKeys.parsedDoc(docId ?? "", stage),
650
650
  queryFn: () => arbi.documents.getParsedContent(docId, stage),
@@ -652,13 +652,13 @@ function useParsedDocument(docId, stage = "final", options) {
652
652
  });
653
653
  }
654
654
  function useAssistantQuery() {
655
- const arbi = chunkZMTLGO3K_cjs.useArbi();
655
+ const arbi = chunkRWCMW36I_cjs.useArbi();
656
656
  return reactQuery.useMutation({
657
657
  mutationFn: ({ question, ...options }) => arbi.assistant.query(question, options)
658
658
  });
659
659
  }
660
660
  function useAgents(options) {
661
- const arbi = chunkZMTLGO3K_cjs.useArbi();
661
+ const arbi = chunkRWCMW36I_cjs.useArbi();
662
662
  return reactQuery.useQuery({
663
663
  queryKey: arbiQueryKeys.agents(),
664
664
  queryFn: () => arbi.agents.list(),
@@ -666,13 +666,13 @@ function useAgents(options) {
666
666
  });
667
667
  }
668
668
  function useDeleteAgents() {
669
- const arbi = chunkZMTLGO3K_cjs.useArbi();
669
+ const arbi = chunkRWCMW36I_cjs.useArbi();
670
670
  return reactQuery.useMutation({
671
671
  mutationFn: ({ agentExtIds }) => arbi.agents.delete(agentExtIds)
672
672
  });
673
673
  }
674
674
  function useSessions(options) {
675
- const arbi = chunkZMTLGO3K_cjs.useArbi();
675
+ const arbi = chunkRWCMW36I_cjs.useArbi();
676
676
  return reactQuery.useQuery({
677
677
  queryKey: arbiQueryKeys.sessions(),
678
678
  queryFn: () => arbi.sessions.list(),
@@ -680,7 +680,7 @@ function useSessions(options) {
680
680
  });
681
681
  }
682
682
  function useHealth(options) {
683
- const arbi = chunkZMTLGO3K_cjs.useArbi();
683
+ const arbi = chunkRWCMW36I_cjs.useArbi();
684
684
  return reactQuery.useQuery({
685
685
  queryKey: arbiQueryKeys.health(),
686
686
  queryFn: () => arbi.health.check(),
@@ -688,7 +688,7 @@ function useHealth(options) {
688
688
  });
689
689
  }
690
690
  function useTasks(options) {
691
- const arbi = chunkZMTLGO3K_cjs.useArbi();
691
+ const arbi = chunkRWCMW36I_cjs.useArbi();
692
692
  return reactQuery.useQuery({
693
693
  queryKey: arbiQueryKeys.tasks(),
694
694
  queryFn: () => arbi.tasks.list(),
@@ -696,7 +696,7 @@ function useTasks(options) {
696
696
  });
697
697
  }
698
698
  function useFacts(workspaceId, options) {
699
- const arbi = chunkZMTLGO3K_cjs.useArbi();
699
+ const arbi = chunkRWCMW36I_cjs.useArbi();
700
700
  return reactQuery.useQuery({
701
701
  queryKey: arbiQueryKeys.facts(workspaceId ?? ""),
702
702
  queryFn: () => arbi.facts.list({ pinnedOnly: options?.pinnedOnly }),
@@ -704,7 +704,7 @@ function useFacts(workspaceId, options) {
704
704
  });
705
705
  }
706
706
  function useConfigs(options) {
707
- const arbi = chunkZMTLGO3K_cjs.useArbi();
707
+ const arbi = chunkRWCMW36I_cjs.useArbi();
708
708
  return reactQuery.useQuery({
709
709
  queryKey: arbiQueryKeys.configs(),
710
710
  queryFn: () => arbi.agentConfig.list(),
@@ -712,7 +712,7 @@ function useConfigs(options) {
712
712
  });
713
713
  }
714
714
  function useActivity(options) {
715
- const arbi = chunkZMTLGO3K_cjs.useArbi();
715
+ const arbi = chunkRWCMW36I_cjs.useArbi();
716
716
  return reactQuery.useQuery({
717
717
  queryKey: arbiQueryKeys.activity(),
718
718
  queryFn: () => arbi.dm.listActivity({ limit: options?.limit, offset: options?.offset }),
@@ -720,7 +720,7 @@ function useActivity(options) {
720
720
  });
721
721
  }
722
722
  function useProjects(options) {
723
- const arbi = chunkZMTLGO3K_cjs.useArbi();
723
+ const arbi = chunkRWCMW36I_cjs.useArbi();
724
724
  return reactQuery.useQuery({
725
725
  queryKey: arbiQueryKeys.projects(),
726
726
  queryFn: () => arbi.projects.list(),
@@ -728,7 +728,7 @@ function useProjects(options) {
728
728
  });
729
729
  }
730
730
  function useProjectUsage(projectExtId, monthsBack = 0, options) {
731
- const arbi = chunkZMTLGO3K_cjs.useArbi();
731
+ const arbi = chunkRWCMW36I_cjs.useArbi();
732
732
  return reactQuery.useQuery({
733
733
  queryKey: arbiQueryKeys.projectUsage(projectExtId ?? "", monthsBack),
734
734
  queryFn: () => arbi.projects.usage(projectExtId, monthsBack),
@@ -736,7 +736,7 @@ function useProjectUsage(projectExtId, monthsBack = 0, options) {
736
736
  });
737
737
  }
738
738
  function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
739
- const arbi = chunkZMTLGO3K_cjs.useArbi();
739
+ const arbi = chunkRWCMW36I_cjs.useArbi();
740
740
  const enabled = (options?.enabled ?? true) && arbi.isLoggedIn;
741
741
  const results = reactQuery.useQueries({
742
742
  queries: projectExtIds.map((id) => ({
@@ -801,7 +801,7 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
801
801
  }, [signature]);
802
802
  }
803
803
  function useProjectInvoices(projectExtId, options) {
804
- const arbi = chunkZMTLGO3K_cjs.useArbi();
804
+ const arbi = chunkRWCMW36I_cjs.useArbi();
805
805
  return reactQuery.useQuery({
806
806
  queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ""),
807
807
  queryFn: () => arbi.projects.invoices(projectExtId),
@@ -809,7 +809,7 @@ function useProjectInvoices(projectExtId, options) {
809
809
  });
810
810
  }
811
811
  function useUserUsageToday(options) {
812
- const arbi = chunkZMTLGO3K_cjs.useArbi();
812
+ const arbi = chunkRWCMW36I_cjs.useArbi();
813
813
  return reactQuery.useQuery({
814
814
  queryKey: arbiQueryKeys.userUsageToday(),
815
815
  queryFn: () => arbi.user.usageToday(),
@@ -817,7 +817,7 @@ function useUserUsageToday(options) {
817
817
  });
818
818
  }
819
819
  function WorkspaceScreen({ theme, labels, onSelect }) {
820
- const arbi = chunkZMTLGO3K_cjs.useArbi();
820
+ const arbi = chunkRWCMW36I_cjs.useArbi();
821
821
  const { data: workspaces, isLoading } = useWorkspaces();
822
822
  const [mode, setMode] = React2.useState("select");
823
823
  const [selected, setSelected] = React2.useState("");
@@ -1054,7 +1054,7 @@ function citeChunkStyle(theme) {
1054
1054
  };
1055
1055
  }
1056
1056
  function ChatView({ workspaceId, theme, labels }) {
1057
- const arbi = chunkZMTLGO3K_cjs.useArbi();
1057
+ const arbi = chunkRWCMW36I_cjs.useArbi();
1058
1058
  const { data: docs, refetch: refetchDocs } = useDocuments(workspaceId);
1059
1059
  const mutation = useAssistantQuery();
1060
1060
  const [messages, setMessages] = React2.useState([]);
@@ -1234,7 +1234,7 @@ function ChatView({ workspaceId, theme, labels }) {
1234
1234
  ] });
1235
1235
  }
1236
1236
  function ChatWidget({ theme, labels, initialWorkspaceId, width, height }) {
1237
- const arbi = chunkZMTLGO3K_cjs.useArbi();
1237
+ const arbi = chunkRWCMW36I_cjs.useArbi();
1238
1238
  const [screen, setScreen] = React2.useState("auth");
1239
1239
  const [workspaceId, setWorkspaceId] = React2.useState(initialWorkspaceId);
1240
1240
  const resolveWorkspace = React2.useCallback(async () => {
@@ -1324,7 +1324,7 @@ function ArbiChat({
1324
1324
  }),
1325
1325
  []
1326
1326
  );
1327
- return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(chunkZMTLGO3K_cjs.ArbiProvider, { url, children: /* @__PURE__ */ jsxRuntime.jsx(
1327
+ return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(chunkRWCMW36I_cjs.ArbiProvider, { url, children: /* @__PURE__ */ jsxRuntime.jsx(
1328
1328
  ArbiChatPanel,
1329
1329
  {
1330
1330
  workspaceId,
@@ -1492,7 +1492,7 @@ function useArbiWsContext() {
1492
1492
  return ctx;
1493
1493
  }
1494
1494
  function ArbiWebSocketProvider({ enabled = true, children }) {
1495
- const arbi = chunkZMTLGO3K_cjs.useArbi();
1495
+ const arbi = chunkRWCMW36I_cjs.useArbi();
1496
1496
  const subscribersRef = React2.useRef(/* @__PURE__ */ new Set());
1497
1497
  const setStatus = useArbiWsStore((s) => s.setStatus);
1498
1498
  const applyTaskUpdate = useArbiWsStore((s) => s.applyTaskUpdate);
@@ -1714,7 +1714,7 @@ function useAiTask() {
1714
1714
  };
1715
1715
  }
1716
1716
  function useSemanticSearch(docIds) {
1717
- const arbi = chunkZMTLGO3K_cjs.useArbi();
1717
+ const arbi = chunkRWCMW36I_cjs.useArbi();
1718
1718
  const [query, setQuery] = React2.useState("");
1719
1719
  const mutation = reactQuery.useMutation({
1720
1720
  mutationFn: async ({ query: q, mode }) => {
@@ -5528,7 +5528,7 @@ function groupConversations(notifications, myExtId) {
5528
5528
  return conversations;
5529
5529
  }
5530
5530
  function useDirectMessages(options) {
5531
- const arbi = chunkZMTLGO3K_cjs.useArbi();
5531
+ const arbi = chunkRWCMW36I_cjs.useArbi();
5532
5532
  const queryClient = reactQuery.useQueryClient();
5533
5533
  const enabled = options?.enabled ?? arbi.isLoggedIn;
5534
5534
  const query = reactQuery.useQuery({
@@ -6937,7 +6937,7 @@ function DocumentCardMenu({
6937
6937
  canDelete = true,
6938
6938
  testId = "document-card-menu"
6939
6939
  }) {
6940
- const arbi = chunkZMTLGO3K_cjs.useArbi();
6940
+ const arbi = chunkRWCMW36I_cjs.useArbi();
6941
6941
  const queryClient = reactQuery.useQueryClient();
6942
6942
  const invalidateDocuments = () => {
6943
6943
  const workspaceId = arbi.getWorkspaceId();
@@ -7081,7 +7081,7 @@ function DocumentGallery({
7081
7081
  },
7082
7082
  [onOpenDocument, setViewingDocId]
7083
7083
  );
7084
- const arbi = chunkZMTLGO3K_cjs.useArbi();
7084
+ const arbi = chunkRWCMW36I_cjs.useArbi();
7085
7085
  const queryClient = reactQuery.useQueryClient();
7086
7086
  const [renamingId, setRenamingId] = React2__default.default.useState(null);
7087
7087
  const rename = reactQuery.useMutation({
@@ -7163,15 +7163,366 @@ function DocumentGallery({
7163
7163
  }
7164
7164
  );
7165
7165
  }
7166
+ var LEVEL_UPDATE_INTERVAL_MS = 50;
7167
+ function classifyMicError(err) {
7168
+ const name = err instanceof DOMException ? err.name : void 0;
7169
+ if (name === "NotAllowedError" || name === "SecurityError") {
7170
+ return "Microphone access is blocked. Allow microphone permission in your browser settings to use voice input.";
7171
+ }
7172
+ if (name === "NotFoundError" || name === "DevicesNotFoundError") {
7173
+ return "No microphone found on this device.";
7174
+ }
7175
+ if (!navigator.mediaDevices?.getUserMedia) {
7176
+ return "Voice input is not supported in this browser.";
7177
+ }
7178
+ return "Could not start recording. Please try again.";
7179
+ }
7180
+ function useAudioRecorder() {
7181
+ const [state, setState] = React2.useState("idle");
7182
+ const [level, setLevel] = React2.useState(0);
7183
+ const [elapsedMs, setElapsedMs] = React2.useState(0);
7184
+ const [blob, setBlob] = React2.useState(null);
7185
+ const [mimeType, setMimeType] = React2.useState(null);
7186
+ const [error, setError] = React2.useState(null);
7187
+ const mediaRecorderRef = React2.useRef(null);
7188
+ const chunksRef = React2.useRef([]);
7189
+ const streamRef = React2.useRef(null);
7190
+ const stateRef = React2.useRef("idle");
7191
+ stateRef.current = state;
7192
+ const segmentStartRef = React2.useRef(0);
7193
+ const accumulatedMsRef = React2.useRef(0);
7194
+ const audioContextRef = React2.useRef(null);
7195
+ const analyserRef = React2.useRef(null);
7196
+ const levelRafRef = React2.useRef(null);
7197
+ const stopMeter = React2.useCallback(() => {
7198
+ if (levelRafRef.current !== null) cancelAnimationFrame(levelRafRef.current);
7199
+ levelRafRef.current = null;
7200
+ analyserRef.current = null;
7201
+ void audioContextRef.current?.close().catch(() => {
7202
+ });
7203
+ audioContextRef.current = null;
7204
+ }, []);
7205
+ const startMeter = React2.useCallback((stream) => {
7206
+ const audioContext = new AudioContext();
7207
+ const source = audioContext.createMediaStreamSource(stream);
7208
+ const analyser = audioContext.createAnalyser();
7209
+ analyser.fftSize = 256;
7210
+ source.connect(analyser);
7211
+ audioContextRef.current = audioContext;
7212
+ analyserRef.current = analyser;
7213
+ const data = new Uint8Array(analyser.frequencyBinCount);
7214
+ let lastUpdate = 0;
7215
+ const tick = (t) => {
7216
+ const active = analyserRef.current;
7217
+ if (!active) return;
7218
+ if (t - lastUpdate >= LEVEL_UPDATE_INTERVAL_MS) {
7219
+ lastUpdate = t;
7220
+ active.getByteTimeDomainData(data);
7221
+ let sumSquares = 0;
7222
+ for (let i = 0; i < data.length; i++) {
7223
+ const centered = (data[i] - 128) / 128;
7224
+ sumSquares += centered * centered;
7225
+ }
7226
+ const rms = Math.sqrt(sumSquares / data.length);
7227
+ setLevel(Math.sqrt(Math.min(1, rms * 8)));
7228
+ setElapsedMs(accumulatedMsRef.current + (t - segmentStartRef.current));
7229
+ }
7230
+ levelRafRef.current = requestAnimationFrame(tick);
7231
+ };
7232
+ levelRafRef.current = requestAnimationFrame(tick);
7233
+ }, []);
7234
+ const stopTracks = React2.useCallback(() => {
7235
+ streamRef.current?.getTracks().forEach((t) => t.stop());
7236
+ streamRef.current = null;
7237
+ }, []);
7238
+ React2.useEffect(
7239
+ () => () => {
7240
+ stopTracks();
7241
+ stopMeter();
7242
+ },
7243
+ [stopTracks, stopMeter]
7244
+ );
7245
+ const start = React2.useCallback(async () => {
7246
+ if (stateRef.current === "recording" || stateRef.current === "paused") return;
7247
+ setError(null);
7248
+ try {
7249
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
7250
+ streamRef.current = stream;
7251
+ const mt = MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : "audio/mp4";
7252
+ const recorder = new MediaRecorder(stream, { mimeType: mt });
7253
+ chunksRef.current = [];
7254
+ recorder.ondataavailable = (e) => {
7255
+ if (e.data.size > 0) chunksRef.current.push(e.data);
7256
+ };
7257
+ mediaRecorderRef.current = recorder;
7258
+ setMimeType(mt);
7259
+ setBlob(null);
7260
+ accumulatedMsRef.current = 0;
7261
+ segmentStartRef.current = performance.now();
7262
+ recorder.start();
7263
+ setState("recording");
7264
+ startMeter(stream);
7265
+ } catch (err) {
7266
+ stopTracks();
7267
+ setError(classifyMicError(err));
7268
+ }
7269
+ }, [startMeter, stopTracks]);
7270
+ const pause = React2.useCallback(() => {
7271
+ const recorder = mediaRecorderRef.current;
7272
+ if (!recorder || recorder.state !== "recording") return;
7273
+ recorder.pause();
7274
+ accumulatedMsRef.current += performance.now() - segmentStartRef.current;
7275
+ stopMeter();
7276
+ setLevel(0);
7277
+ setState("paused");
7278
+ }, [stopMeter]);
7279
+ const resume = React2.useCallback(() => {
7280
+ const recorder = mediaRecorderRef.current;
7281
+ if (!recorder || recorder.state !== "paused") return;
7282
+ recorder.resume();
7283
+ segmentStartRef.current = performance.now();
7284
+ setState("recording");
7285
+ if (streamRef.current) startMeter(streamRef.current);
7286
+ }, [startMeter]);
7287
+ const stop = React2.useCallback(() => {
7288
+ const recorder = mediaRecorderRef.current;
7289
+ if (!recorder || recorder.state === "inactive") return;
7290
+ const finalElapsed = recorder.state === "paused" ? accumulatedMsRef.current : accumulatedMsRef.current + (performance.now() - segmentStartRef.current);
7291
+ stopMeter();
7292
+ recorder.onstop = () => {
7293
+ stopTracks();
7294
+ const finalBlob = chunksRef.current.length ? new Blob(chunksRef.current, { type: recorder.mimeType }) : null;
7295
+ setBlob(finalBlob);
7296
+ setElapsedMs(finalElapsed);
7297
+ setLevel(0);
7298
+ setState("stopped");
7299
+ };
7300
+ recorder.stop();
7301
+ }, [stopMeter, stopTracks]);
7302
+ const reset = React2.useCallback(() => {
7303
+ setState("idle");
7304
+ setBlob(null);
7305
+ setElapsedMs(0);
7306
+ setLevel(0);
7307
+ setMimeType(null);
7308
+ setError(null);
7309
+ }, []);
7310
+ return { state, level, elapsedMs, blob, mimeType, error, start, pause, resume, stop, reset };
7311
+ }
7312
+
7313
+ // src/documents/format-elapsed.ts
7314
+ function formatElapsed(ms) {
7315
+ const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
7316
+ const minutes = Math.floor(totalSeconds / 60);
7317
+ const seconds = totalSeconds % 60;
7318
+ return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
7319
+ }
7320
+ var BAR_WEIGHTS = [
7321
+ 0.25,
7322
+ 0.32,
7323
+ 0.48,
7324
+ 0.62,
7325
+ 0.82,
7326
+ 0.56,
7327
+ 0.92,
7328
+ 0.72,
7329
+ 1,
7330
+ 0.86,
7331
+ 0.62,
7332
+ 0.96,
7333
+ 0.76,
7334
+ 0.5,
7335
+ 0.84,
7336
+ 0.66,
7337
+ 0.42,
7338
+ 0.56,
7339
+ 0.36,
7340
+ 0.28,
7341
+ 0.22
7342
+ ];
7343
+ var MIN_BAR_PX = 3;
7344
+ var MAX_BAR_PX = 40;
7345
+ function MicWaveformIndicator({
7346
+ level,
7347
+ elapsedMs,
7348
+ paused = false
7349
+ }) {
7350
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3", "data-testid": "mic-waveform-indicator", children: [
7351
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7352
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [
7353
+ !paused && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75" }),
7354
+ /* @__PURE__ */ jsxRuntime.jsx(
7355
+ "span",
7356
+ {
7357
+ className: `relative inline-flex h-2 w-2 rounded-full ${paused ? "bg-muted-foreground" : "bg-red-500"}`
7358
+ }
7359
+ )
7360
+ ] }),
7361
+ /* @__PURE__ */ jsxRuntime.jsx(
7362
+ "span",
7363
+ {
7364
+ className: `text-xs font-semibold uppercase tracking-wide ${paused ? "text-muted-foreground" : "text-red-500"}`,
7365
+ children: paused ? "Paused" : "Rec"
7366
+ }
7367
+ ),
7368
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-xs tabular-nums text-muted-foreground", children: formatElapsed(elapsedMs) })
7369
+ ] }),
7370
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-10 items-end gap-[3px]", "data-testid": "mic-waveform-indicator-bars", children: BAR_WEIGHTS.map((weight, i) => /* @__PURE__ */ jsxRuntime.jsx(
7371
+ "span",
7372
+ {
7373
+ className: "w-1 rounded-full bg-secondary transition-[height] duration-75 ease-out",
7374
+ style: {
7375
+ height: Math.min(MAX_BAR_PX, Math.max(MIN_BAR_PX, level * weight * MAX_BAR_PX))
7376
+ }
7377
+ },
7378
+ i
7379
+ )) })
7380
+ ] });
7381
+ }
7382
+ function VoiceNoteRecorder({
7383
+ onSave,
7384
+ onDiscard,
7385
+ onError,
7386
+ title = "Voice note",
7387
+ isSaving = false
7388
+ }) {
7389
+ const recorder = useAudioRecorder();
7390
+ React2.useEffect(() => {
7391
+ if (recorder.error) onError?.(recorder.error);
7392
+ }, [recorder.error]);
7393
+ const handleSave = () => {
7394
+ if (!recorder.blob) return;
7395
+ void onSave(recorder.blob, recorder.mimeType);
7396
+ };
7397
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6 p-8", children: [
7398
+ recorder.state === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7399
+ /* @__PURE__ */ jsxRuntime.jsx(
7400
+ chunk5DV7FW6T_cjs.Button,
7401
+ {
7402
+ type: "button",
7403
+ size: "lg",
7404
+ className: "h-16 w-16 rounded-full p-0",
7405
+ onClick: () => void recorder.start(),
7406
+ "data-testid": "voice-note-record-button",
7407
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-6 w-6" })
7408
+ }
7409
+ ),
7410
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Press to start recording" })
7411
+ ] }),
7412
+ (recorder.state === "recording" || recorder.state === "paused") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7413
+ /* @__PURE__ */ jsxRuntime.jsx(
7414
+ MicWaveformIndicator,
7415
+ {
7416
+ level: recorder.level,
7417
+ elapsedMs: recorder.elapsedMs,
7418
+ paused: recorder.state === "paused"
7419
+ }
7420
+ ),
7421
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
7422
+ recorder.state === "recording" ? /* @__PURE__ */ jsxRuntime.jsxs(
7423
+ chunk5DV7FW6T_cjs.Button,
7424
+ {
7425
+ type: "button",
7426
+ variant: "outline",
7427
+ onClick: recorder.pause,
7428
+ "data-testid": "voice-note-pause-button",
7429
+ children: [
7430
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "mr-1.5 h-4 w-4" }),
7431
+ "Pause"
7432
+ ]
7433
+ }
7434
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
7435
+ chunk5DV7FW6T_cjs.Button,
7436
+ {
7437
+ type: "button",
7438
+ variant: "outline",
7439
+ onClick: recorder.resume,
7440
+ "data-testid": "voice-note-resume-button",
7441
+ children: [
7442
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "mr-1.5 h-4 w-4" }),
7443
+ "Resume"
7444
+ ]
7445
+ }
7446
+ ),
7447
+ /* @__PURE__ */ jsxRuntime.jsxs(chunk5DV7FW6T_cjs.Button, { type: "button", onClick: recorder.stop, "data-testid": "voice-note-stop-button", children: [
7448
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "mr-1.5 h-3.5 w-3.5 fill-current" }),
7449
+ "Stop"
7450
+ ] })
7451
+ ] })
7452
+ ] }),
7453
+ recorder.state === "stopped" && recorder.blob && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7454
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(chunkRWCMW36I_cjs.AudioViewer, { blob: recorder.blob, title }) }),
7455
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
7456
+ /* @__PURE__ */ jsxRuntime.jsxs(
7457
+ chunk5DV7FW6T_cjs.Button,
7458
+ {
7459
+ type: "button",
7460
+ variant: "outline",
7461
+ onClick: onDiscard,
7462
+ disabled: isSaving,
7463
+ "data-testid": "voice-note-discard-button",
7464
+ children: [
7465
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-1.5 h-4 w-4" }),
7466
+ "Discard"
7467
+ ]
7468
+ }
7469
+ ),
7470
+ /* @__PURE__ */ jsxRuntime.jsxs(
7471
+ chunk5DV7FW6T_cjs.Button,
7472
+ {
7473
+ type: "button",
7474
+ variant: "outline",
7475
+ onClick: recorder.reset,
7476
+ disabled: isSaving,
7477
+ "data-testid": "voice-note-record-again-button",
7478
+ children: [
7479
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "mr-1.5 h-4 w-4" }),
7480
+ "Record again"
7481
+ ]
7482
+ }
7483
+ ),
7484
+ /* @__PURE__ */ jsxRuntime.jsxs(
7485
+ chunk5DV7FW6T_cjs.Button,
7486
+ {
7487
+ type: "button",
7488
+ onClick: handleSave,
7489
+ disabled: isSaving,
7490
+ "data-testid": "voice-note-save-button",
7491
+ children: [
7492
+ isSaving ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "mr-1.5 h-4 w-4" }),
7493
+ isSaving ? "Saving\u2026" : "Save"
7494
+ ]
7495
+ }
7496
+ )
7497
+ ] })
7498
+ ] })
7499
+ ] });
7500
+ }
7501
+
7502
+ // src/documents/has-video-track.ts
7503
+ function hasVideoTrack(blob) {
7504
+ return new Promise((resolve) => {
7505
+ const url = URL.createObjectURL(blob);
7506
+ const video = document.createElement("video");
7507
+ video.preload = "metadata";
7508
+ video.muted = true;
7509
+ const cleanup = () => {
7510
+ video.removeAttribute("src");
7511
+ video.load();
7512
+ URL.revokeObjectURL(url);
7513
+ };
7514
+ video.onloadedmetadata = () => {
7515
+ resolve(video.videoWidth > 0 && video.videoHeight > 0);
7516
+ cleanup();
7517
+ };
7518
+ video.onerror = () => {
7519
+ resolve(false);
7520
+ cleanup();
7521
+ };
7522
+ video.src = url;
7523
+ });
7524
+ }
7166
7525
 
7167
- Object.defineProperty(exports, "ArbiProvider", {
7168
- enumerable: true,
7169
- get: function () { return chunkZMTLGO3K_cjs.ArbiProvider; }
7170
- });
7171
- Object.defineProperty(exports, "useArbi", {
7172
- enumerable: true,
7173
- get: function () { return chunkZMTLGO3K_cjs.useArbi; }
7174
- });
7175
7526
  Object.defineProperty(exports, "AiMarkdown", {
7176
7527
  enumerable: true,
7177
7528
  get: function () { return chunk5DV7FW6T_cjs.AiMarkdown; }
@@ -7596,6 +7947,14 @@ Object.defineProperty(exports, "toggleVariants", {
7596
7947
  enumerable: true,
7597
7948
  get: function () { return chunk5DV7FW6T_cjs.toggleVariants; }
7598
7949
  });
7950
+ Object.defineProperty(exports, "ArbiProvider", {
7951
+ enumerable: true,
7952
+ get: function () { return chunkRWCMW36I_cjs.ArbiProvider; }
7953
+ });
7954
+ Object.defineProperty(exports, "useArbi", {
7955
+ enumerable: true,
7956
+ get: function () { return chunkRWCMW36I_cjs.useArbi; }
7957
+ });
7599
7958
  Object.defineProperty(exports, "Arbi", {
7600
7959
  enumerable: true,
7601
7960
  get: function () { return browser.Arbi; }
@@ -7665,6 +8024,7 @@ exports.LinkedInIcon = LinkedInIcon;
7665
8024
  exports.MessageArtifactCard = MessageArtifactCard;
7666
8025
  exports.MessageBubble = MessageBubble2;
7667
8026
  exports.MessageThread = MessageThread;
8027
+ exports.MicWaveformIndicator = MicWaveformIndicator;
7668
8028
  exports.NEUTRAL_GRAY = NEUTRAL_GRAY2;
7669
8029
  exports.NotificationBell = NotificationBell;
7670
8030
  exports.OpenAIIcon = OpenAIIcon;
@@ -7690,6 +8050,7 @@ exports.UserMenu = UserMenu;
7690
8050
  exports.VISIBILITY_ICONS = VISIBILITY_ICONS;
7691
8051
  exports.VidIcon = VidIcon;
7692
8052
  exports.VisibilityIcon = VisibilityIcon;
8053
+ exports.VoiceNoteRecorder = VoiceNoteRecorder;
7693
8054
  exports.XlsIcon = XlsIcon;
7694
8055
  exports.annotateThread = annotateThread;
7695
8056
  exports.arbiQueryKeys = arbiQueryKeys;
@@ -7699,6 +8060,7 @@ exports.configureStatusRegistry = configureStatusRegistry;
7699
8060
  exports.cropImage = cropImage;
7700
8061
  exports.dayKey = dayKey;
7701
8062
  exports.describeActivity = describeActivity;
8063
+ exports.formatElapsed = formatElapsed;
7702
8064
  exports.formatRelativeTime = formatRelativeTime;
7703
8065
  exports.getDocIcon = getDocIcon;
7704
8066
  exports.getEntityColor = getEntityColor2;
@@ -7712,6 +8074,7 @@ exports.getTagTypeLabel = getTagTypeLabel;
7712
8074
  exports.getWorkspaceActionText = getWorkspaceActionText;
7713
8075
  exports.getWorkspaceColor = getWorkspaceColor;
7714
8076
  exports.getWorkspaceSentPhrase = getWorkspaceSentPhrase;
8077
+ exports.hasVideoTrack = hasVideoTrack;
7715
8078
  exports.isWorkspaceNotificationType = isWorkspaceNotificationType;
7716
8079
  exports.notify = notify;
7717
8080
  exports.parseActivityContent = parseActivityContent;
@@ -7734,6 +8097,7 @@ exports.useArbiWsStore = useArbiWsStore;
7734
8097
  exports.useArbiWsTask = useArbiWsTask;
7735
8098
  exports.useArbiWsTasks = useArbiWsTasks;
7736
8099
  exports.useAssistantQuery = useAssistantQuery;
8100
+ exports.useAudioRecorder = useAudioRecorder;
7737
8101
  exports.useCommandPalette = useCommandPalette;
7738
8102
  exports.useConfigs = useConfigs;
7739
8103
  exports.useConversations = useConversations;