@arbidocs/blocks 0.5.32 → 0.5.33
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/{ConnectedNativeDocxComparison-X6NTNHHM.cjs → ConnectedNativeDocxComparison-H2OZMWHT.cjs} +7 -7
- package/dist/{ConnectedNativeDocxComparison-X6NTNHHM.cjs.map → ConnectedNativeDocxComparison-H2OZMWHT.cjs.map} +1 -1
- package/dist/{ConnectedNativeDocxComparison-4RHC6KCE.js → ConnectedNativeDocxComparison-RWKFPJPJ.js} +6 -6
- package/dist/{ConnectedNativeDocxComparison-4RHC6KCE.js.map → ConnectedNativeDocxComparison-RWKFPJPJ.js.map} +1 -1
- package/dist/{ConnectedNativeDocxEditor-S5AT2UAH.js → ConnectedNativeDocxEditor-43BI5LN6.js} +5 -5
- package/dist/{ConnectedNativeDocxEditor-S5AT2UAH.js.map → ConnectedNativeDocxEditor-43BI5LN6.js.map} +1 -1
- package/dist/{ConnectedNativeDocxEditor-U75VOJBC.cjs → ConnectedNativeDocxEditor-6DQEM6SD.cjs} +7 -7
- package/dist/{ConnectedNativeDocxEditor-U75VOJBC.cjs.map → ConnectedNativeDocxEditor-6DQEM6SD.cjs.map} +1 -1
- package/dist/{ConnectedStreamedWordArtifact-QAZ5VQZS.cjs → ConnectedStreamedWordArtifact-3VKYIG6C.cjs} +7 -7
- package/dist/ConnectedStreamedWordArtifact-3VKYIG6C.cjs.map +1 -0
- package/dist/{ConnectedStreamedWordArtifact-7XU5RSX2.js → ConnectedStreamedWordArtifact-TEB332E3.js} +6 -6
- package/dist/{ConnectedStreamedWordArtifact-7XU5RSX2.js.map → ConnectedStreamedWordArtifact-TEB332E3.js.map} +1 -1
- package/dist/calls/index.cjs +32 -32
- package/dist/calls/index.js +4 -4
- package/dist/{chunk-2MCHQGVY.js → chunk-24H5WTGM.js} +4 -4
- package/dist/{chunk-2MCHQGVY.js.map → chunk-24H5WTGM.js.map} +1 -1
- package/dist/{chunk-D57MPMTZ.js → chunk-2YCCCXYV.js} +12 -3
- package/dist/chunk-2YCCCXYV.js.map +1 -0
- package/dist/{chunk-BNOP4REH.js → chunk-5JEM3BWT.js} +3 -3
- package/dist/{chunk-BNOP4REH.js.map → chunk-5JEM3BWT.js.map} +1 -1
- package/dist/{chunk-ZIURNTTS.cjs → chunk-BIWPXSGS.cjs} +7 -7
- package/dist/{chunk-ZIURNTTS.cjs.map → chunk-BIWPXSGS.cjs.map} +1 -1
- package/dist/{chunk-2RFXSBPD.cjs → chunk-BRYRZOS3.cjs} +4 -4
- package/dist/{chunk-2RFXSBPD.cjs.map → chunk-BRYRZOS3.cjs.map} +1 -1
- package/dist/{chunk-EPQ3364Q.cjs → chunk-C3YIVBTU.cjs} +6 -6
- package/dist/{chunk-EPQ3364Q.cjs.map → chunk-C3YIVBTU.cjs.map} +1 -1
- package/dist/{chunk-JBR3QNHC.cjs → chunk-EFSL4O3B.cjs} +4 -4
- package/dist/{chunk-JBR3QNHC.cjs.map → chunk-EFSL4O3B.cjs.map} +1 -1
- package/dist/{chunk-SBTRXXJF.cjs → chunk-JVXHVFUA.cjs} +11 -2
- package/dist/chunk-JVXHVFUA.cjs.map +1 -0
- package/dist/{chunk-XBY36SIJ.js → chunk-MLHOG7YH.js} +3 -3
- package/dist/{chunk-XBY36SIJ.js.map → chunk-MLHOG7YH.js.map} +1 -1
- package/dist/{chunk-B5G3AZ3O.js → chunk-N3HVTMQK.js} +3 -3
- package/dist/{chunk-B5G3AZ3O.js.map → chunk-N3HVTMQK.js.map} +1 -1
- package/dist/{chunk-3ES6VWRB.cjs → chunk-NOKTUWTN.cjs} +7 -7
- package/dist/{chunk-3ES6VWRB.cjs.map → chunk-NOKTUWTN.cjs.map} +1 -1
- package/dist/{chunk-EOLQ5YBP.js → chunk-NUV5F6MM.js} +3 -3
- package/dist/{chunk-EOLQ5YBP.js.map → chunk-NUV5F6MM.js.map} +1 -1
- package/dist/{chunk-NQWP5PWA.js → chunk-VKY4SQMH.js} +4 -4
- package/dist/{chunk-NQWP5PWA.js.map → chunk-VKY4SQMH.js.map} +1 -1
- package/dist/{chunk-ULA6YWWD.cjs → chunk-VMLEISRZ.cjs} +15 -15
- package/dist/{chunk-ULA6YWWD.cjs.map → chunk-VMLEISRZ.cjs.map} +1 -1
- package/dist/{chunk-DY2Z3DP7.js → chunk-VPWCARVO.js} +3 -3
- package/dist/{chunk-DY2Z3DP7.js.map → chunk-VPWCARVO.js.map} +1 -1
- package/dist/{chunk-L22MGRKB.cjs → chunk-XFSEPGF7.cjs} +4 -4
- package/dist/{chunk-L22MGRKB.cjs.map → chunk-XFSEPGF7.cjs.map} +1 -1
- package/dist/connect/docx.cjs +9 -9
- package/dist/connect/docx.js +5 -5
- package/dist/connect/index.cjs +129 -129
- package/dist/connect/index.js +11 -11
- package/dist/connect/viewer.cjs +24 -24
- package/dist/connect/viewer.js +7 -7
- package/dist/studio/index.cjs +4 -4
- package/dist/studio/index.js +2 -2
- package/dist/workflow-canvas/index.cjs +6 -6
- package/dist/workflow-canvas/index.js +2 -2
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/ConnectedStreamedWordArtifact-QAZ5VQZS.cjs.map +0 -1
- package/dist/chunk-D57MPMTZ.js.map +0 -1
- package/dist/chunk-SBTRXXJF.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection/conversation/useMeetingThreadMessages.ts","../src/calls/connected/SaveTranscriptToThread.tsx","../src/calls/connected/RecordingCard.tsx","../src/calls/connected/ThreadCallLogCard.tsx","../src/calls/connected/TranscriptEntry.tsx","../src/calls/connected/call-person-name.ts","../src/calls/connected/CallConversationParts.tsx","../src/calls/connected/provisional-speakers.ts","../src/calls/connected/transcript-runs-context.ts"],"names":["useMemo","jsx","Fragment","jsxs","cn","useState","Button","useSaveToThread","useArbi","useCall","useCallSession","Captions","useRef","useEffect"],"mappings":"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","file":"chunk-2MCHQGVY.js","sourcesContent":["/**\n * A conversation's messages as its thread shows them: in a call's meeting thread, a recording's\n * transcript supersedes the live lines spoken while it recorded (else both would show).\n */\nimport { useMemo } from 'react'\nimport {\n hasRecordingTranscript,\n supersedeLiveTranscript,\n threadTranscriptRef,\n useRecordingWindows,\n} from '@arbidocs/react'\nimport type { ChatMessage } from '@arbidocs/sdk/browser'\n\nexport function useMeetingThreadMessages(\n meetingCallExtId: string | null,\n messageHistory: ChatMessage[]\n): ChatMessage[] {\n const hasRecTranscript = useMemo(\n () => !!meetingCallExtId && hasRecordingTranscript(messageHistory, threadTranscriptRef),\n [meetingCallExtId, messageHistory]\n )\n const recordingWindows = useRecordingWindows(meetingCallExtId, hasRecTranscript)\n return useMemo(\n () =>\n hasRecTranscript\n ? supersedeLiveTranscript(messageHistory, threadTranscriptRef, recordingWindows)\n : messageHistory,\n [hasRecTranscript, messageHistory, recordingWindows]\n )\n}\n","/**\n * Host action \"Save transcript to thread\": the meeting chat's transcript is decrypted here, in the\n * host's browser, and posted as ONE attributed transcript comment (title, date, then\n * `Speaker [hh:mm:ss]: text` lines) into a workspace thread the host picks — a shared thread of the\n * current workspace they can post in, or a new one. The thread is encrypted with the workspace key\n * like any comment; the meeting chat itself is unchanged and nobody outside it gains access to it.\n */\n\nimport { useSaveToThread, useWorkspaces, type TranscriptExportLine } from '@arbidocs/react'\nimport { useMemo, useState, type ReactElement, type ReactNode } from 'react'\nimport { FileText } from 'lucide-react'\nimport {\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@arbidocs/react/ui'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../../connection/ConnectionProvider'\nimport { useConnectedConversations } from '../../connection/workspaceData'\nimport { HeaderAction } from '../HeaderAction'\n\nconst NEW_THREAD = '__new__'\n\n/** The open workspace and my role in it (the threads I can post in are its shared ones). */\nfunction useCurrentWorkspace() {\n const { workspaceId, userId } = useConnectedWorkspace()\n const { data: workspaces } = useWorkspaces()\n const workspace = workspaces?.find((w) => w.external_id === workspaceId)\n const role = workspace?.users?.find((wu) => wu.user.external_id === userId)?.role ?? null\n return { workspace, role }\n}\n\nexport function SaveTranscriptToThread({\n title,\n lines,\n excludeConversationExtId,\n iconOnly = false,\n className,\n}: {\n /** The meeting's title (decrypted). */\n title: string | null | undefined\n lines: TranscriptExportLine[]\n /** Not offered as a target (the meeting thread itself). */\n excludeConversationExtId?: string | null\n /** Icon only, the label in a tooltip (a crowded header). */\n iconOnly?: boolean\n className?: string\n}): ReactElement | null {\n const [open, setOpen] = useState(false)\n if (!lines.length) return null\n return (\n <>\n <HeaderAction\n label=\"Save transcript to thread\"\n icon={<FileText className=\"size-3.5\" aria-hidden />}\n iconOnly={iconOnly}\n className={className}\n onClick={() => setOpen(true)}\n testId=\"save-transcript-to-thread\"\n />\n {open && (\n <SaveTranscriptDialog\n title={title}\n lines={lines}\n excludeConversationExtId={excludeConversationExtId ?? null}\n onClose={() => setOpen(false)}\n />\n )}\n </>\n )\n}\n\nfunction SaveTranscriptDialog({\n title,\n lines,\n excludeConversationExtId,\n onClose,\n}: {\n title: string | null | undefined\n lines: TranscriptExportLine[]\n excludeConversationExtId: string | null\n onClose(): void\n}): ReactElement {\n const { notify } = useBlocksEnvironment()\n const save = useSaveToThread()\n const { workspace } = useCurrentWorkspace()\n return (\n <PickThreadDialog\n heading=\"Save transcript to thread\"\n description={\n <>\n The transcript ({lines.length} {lines.length === 1 ? 'line' : 'lines'}) is posted as one\n comment in a thread of {workspace?.name ?? 'the current workspace'}. Only that thread’s\n members can read it there.\n </>\n }\n testIdPrefix=\"save-transcript\"\n excludeConversationExtId={excludeConversationExtId}\n onClose={onClose}\n onConfirm={async (target) => {\n await save.transcript({ conversationExtId: target, title, lines })\n notify('Transcript saved to the thread', 'success')\n }}\n />\n )\n}\n\n/**\n * Pick a shared thread of the current workspace I can post in (or a new one) and act on it: the\n * dialog behind \"Save transcript to thread\" and the recording's \"Save to thread\".\n */\nexport function PickThreadDialog({\n heading,\n description,\n testIdPrefix,\n excludeConversationExtId,\n confirmLabel = 'Save',\n busyLabel = 'Saving…',\n onConfirm,\n onClose,\n}: {\n heading: string\n description: ReactNode\n /** `<prefix>-dialog`, `<prefix>-target-<id>`, `<prefix>-confirm`. */\n testIdPrefix: string\n excludeConversationExtId?: string | null\n confirmLabel?: string\n busyLabel?: string\n /** `target` null: a new thread. Throwing keeps the dialog open and shows the error. */\n onConfirm(target: string | null): Promise<unknown>\n onClose(): void\n}): ReactElement {\n const { notify } = useBlocksEnvironment()\n const { role } = useCurrentWorkspace()\n const { data: conversations } = useConnectedConversations()\n const canPost = role === 'owner' || role === 'collaborator'\n const threads = useMemo(\n () =>\n canPost\n ? conversations\n .filter((c) => c.is_shared && c.external_id !== excludeConversationExtId)\n .sort((a, b) => Date.parse(b.updated_at) - Date.parse(a.updated_at))\n : [],\n [conversations, canPost, excludeConversationExtId]\n )\n const [target, setTarget] = useState<string>(NEW_THREAD)\n const [busy, setBusy] = useState(false)\n\n const save = async () => {\n setBusy(true)\n try {\n await onConfirm(target === NEW_THREAD ? null : target)\n onClose()\n } catch (err) {\n notify((err as Error).message, 'error')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Dialog open onOpenChange={(o) => !o && !busy && onClose()}>\n <DialogContent className=\"sm:max-w-md\" data-testid={`${testIdPrefix}-dialog`}>\n <DialogHeader>\n <DialogTitle>{heading}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n {!canPost ? (\n <p className=\"text-sm text-muted-foreground\">\n Open a workspace you can post in to save here.\n </p>\n ) : (\n <ul className=\"flex max-h-72 flex-col gap-1 overflow-y-auto\" role=\"radiogroup\">\n {[{ external_id: NEW_THREAD, title: 'New thread' }, ...threads].map((t) => (\n <li key={t.external_id}>\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={target === t.external_id}\n className={cn(\n 'w-full truncate rounded-md px-2 py-1.5 text-left text-sm hover:bg-muted',\n target === t.external_id && 'bg-muted font-medium'\n )}\n onClick={() => setTarget(t.external_id)}\n data-testid={`${testIdPrefix}-target-${t.external_id}`}\n >\n {t.title || 'Untitled thread'}\n </button>\n </li>\n ))}\n </ul>\n )}\n <DialogFooter>\n <Button variant=\"ghost\" onClick={onClose} disabled={busy}>\n Cancel\n </Button>\n <Button\n onClick={() => void save()}\n disabled={busy || !canPost}\n data-testid={`${testIdPrefix}-confirm`}\n >\n {busy ? busyLabel : confirmLabel}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n","/**\n * The Recording card of a call (ARBI `docs/meeting-chats-plan.md` §6): a `kind = recording` chat\n * message in an E2E meeting chat, a `recording` activity event in a workspace meeting thread, and\n * each entry of a meeting chat's \"Recordings\" list.\n *\n * Everything that touches media happens in this browser: parts are downloaded as ciphertext and\n * decrypted with the track keys (unwrapped under the meeting chat's / workspace's key). Members of\n * the meeting chat can play, download and copy an in-app link; the host can also transcribe, delete\n * the media (keeping the transcript), set an expiry, save the files to a thread, or delete it.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactElement } from 'react'\nimport {\n Captions,\n Download,\n FileUp,\n Link2,\n Loader2,\n Mic,\n Pause,\n Play,\n Trash2,\n Video,\n} from 'lucide-react'\nimport { Button, cn } from '@arbidocs/react/ui'\nimport { downloadBlob } from '@arbidocs/react/document-tools'\nimport {\n useArbi,\n useCallRecording,\n useCallRecordings,\n useCall,\n useRecordingActions,\n useSaveToThread,\n meetingChatRefFrom,\n compositeFiles,\n compositeTrack,\n fetchPart,\n recordingFiles,\n speakerTracks,\n type OpenedRecording,\n PLAYBACK_LOOKAHEAD_MS,\n partKey,\n partsDue,\n playheadAt,\n schedulePart,\n standalone,\n timelineDurationMs,\n timelineOf,\n type TimelinePart,\n} from '@arbidocs/react'\nimport type { calls } from '@arbidocs/sdk/browser'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../../connection/ConnectionProvider'\nimport { recordingLink, setPendingRecording, usePendingRecording } from '../recording-link'\nimport { formatCallDuration } from '../call-cards'\nimport { EXPIRY_DAYS, MODE_LABEL, expiryChoiceOf, expiryFor } from '../recording-labels'\nimport { PickThreadDialog } from './SaveTranscriptToThread'\nimport { CallUserPill } from './CallUserPill'\n\n/** A card for one recording (by id), or for each of the call's recordings when no id is known. */\nexport function RecordingCard({\n callExtId,\n recordingExtId,\n title,\n time,\n}: {\n callExtId: string\n recordingExtId?: string | null\n /** The meeting's title (decrypted), for file names. */\n title?: string | null\n time?: string\n}): ReactElement | null {\n const { data: call } = useCall(callExtId)\n const one = useCallRecording(callExtId, recordingExtId)\n const all = useCallRecordings(callExtId, !recordingExtId)\n if (!call) return null\n if (recordingExtId) {\n if (one.isError) return <RecordingUnavailable />\n return one.data ? (\n <RecordingCardBody call={call} recording={one.data} title={title} time={time} />\n ) : null\n }\n return (\n <>\n {(all.data ?? []).map((r) => (\n <RecordingCardBody\n key={r.external_id}\n call={call}\n recording={r}\n title={title}\n time={time}\n />\n ))}\n </>\n )\n}\n\n/** All of a call's recordings (the meeting chat's \"Recordings\" view), newest first. */\nexport function RecordingsList({\n callExtId,\n title,\n className,\n}: {\n callExtId: string\n title?: string | null\n className?: string\n}): ReactElement {\n const { data: call } = useCall(callExtId)\n const { data, isLoading, isError } = useCallRecordings(callExtId)\n const sorted = useMemo(\n () => [...(data ?? [])].sort((a, b) => Date.parse(b.started_at) - Date.parse(a.started_at)),\n [data]\n )\n return (\n <div className={cn('flex flex-col gap-2', className)} data-testid=\"recordings-list\">\n {isLoading && <Loader2 className=\"mx-auto size-4 animate-spin text-muted-foreground\" />}\n {isError && (\n <p className=\"text-center text-xs text-muted-foreground\">Could not load the recordings.</p>\n )}\n {!isLoading && !isError && !sorted.length && (\n <p className=\"text-center text-xs text-muted-foreground\">No recordings yet.</p>\n )}\n {call &&\n sorted.map((r) => (\n <RecordingCardBody key={r.external_id} call={call} recording={r} title={title} />\n ))}\n </div>\n )\n}\n\nfunction RecordingUnavailable(): ReactElement {\n return (\n <div\n className=\"mx-auto my-1 w-fit rounded-md border border-border bg-card px-3 py-2 text-xs text-muted-foreground\"\n data-testid=\"recording-card\"\n >\n Recording unavailable\n </div>\n )\n}\n\n/** A two-step destructive button: the first click asks, the second does. */\nfunction ConfirmButton({\n label,\n confirmLabel,\n testId,\n disabled,\n onConfirm,\n icon,\n}: {\n label: string\n confirmLabel: string\n testId: string\n disabled?: boolean\n onConfirm(): Promise<void>\n icon: ReactElement\n}): ReactElement {\n const [asking, setAsking] = useState(false)\n const [busy, setBusy] = useState(false)\n useEffect(() => {\n if (!asking) return\n const t = setTimeout(() => setAsking(false), 5000)\n return () => clearTimeout(t)\n }, [asking])\n return (\n <Button\n type=\"button\"\n size=\"sm\"\n variant={asking ? 'destructive' : 'outline'}\n className=\"h-7\"\n disabled={disabled || busy}\n onClick={() => {\n if (!asking) {\n setAsking(true)\n return\n }\n setAsking(false)\n setBusy(true)\n void onConfirm().finally(() => setBusy(false))\n }}\n data-testid={asking ? `${testId}-confirm` : testId}\n >\n {busy ? <Loader2 className=\"mr-1 size-3.5 animate-spin\" aria-hidden /> : icon}\n {asking ? confirmLabel : label}\n </Button>\n )\n}\n\nfunction RecordingCardBody({\n call,\n recording,\n title,\n time,\n}: {\n call: calls.CallResponse\n recording: calls.CallRecording\n title?: string | null\n time?: string\n}): ReactElement {\n const arbi = useArbi()\n const actions = useRecordingActions(call)\n const save = useSaveToThread()\n const { notify, runtimeConfig } = useBlocksEnvironment()\n const isHost = call.is_creator\n const mediaDeleted = !!recording.media_deleted_at\n const live = recording.state === 'recording' || (!recording.stopped_at && !mediaDeleted)\n const speakers = speakerTracks(recording)\n const timeline = useMemo(() => timelineOf(recording.tracks ?? []), [recording.tracks])\n const durationMs = timelineDurationMs(timeline)\n const hasMedia = !mediaDeleted && timeline.length > 0\n const [opened, setOpened] = useState<OpenedRecording | null>(null)\n const [playing, setPlaying] = useState(false)\n const [progress, setProgress] = useState<string | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const { workspaceId: selectedWorkspaceId } = useConnectedWorkspace()\n\n // A link asked to show this recording: bring it into view.\n const pending = usePendingRecording()\n const highlighted = pending === recording.external_id\n const cardRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n if (!highlighted) return\n cardRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n const t = setTimeout(() => setPendingRecording(null), 4000)\n return () => clearTimeout(t)\n }, [highlighted])\n\n const { refresh } = actions\n\n const open = useCallback(async (): Promise<OpenedRecording> => {\n if (opened && opened.recording === recording) return opened\n const next = await actions.open(recording)\n setOpened(next)\n return next\n }, [actions, opened, recording])\n\n const run = async (label: string, task: () => Promise<void>) => {\n setProgress(label)\n try {\n await task()\n } catch (err) {\n console.warn('[calls] recording action failed', err)\n notify((err as Error).message, 'error')\n } finally {\n setProgress(null)\n }\n }\n\n const download = () =>\n run('Decrypting…', async () => {\n const files = await recordingFiles(arbi, await open(), title, (done, total) =>\n setProgress(`Decrypting ${done}/${total}…`)\n )\n if (!files.length) throw new Error('Nothing to download')\n for (const f of files) downloadBlob(f, f.name)\n })\n\n const transcribe = () =>\n run('Transcribing…', async () => {\n const { stored, failed } = await actions.transcribe(await open(), (done, total) =>\n setProgress(`Transcribing ${done}/${total}…`)\n )\n notify(\n failed\n ? `Transcribed ${stored} lines; ${failed} parts failed`\n : `Transcribed ${stored} lines into the meeting chat`,\n failed ? 'warning' : 'success'\n )\n })\n\n const copyLink = async () => {\n const ref = meetingChatRefFrom(call)\n if (!ref) {\n notify('This recording has no meeting chat to link to', 'error')\n return\n }\n try {\n await navigator.clipboard.writeText(\n recordingLink(ref, recording.external_id, runtimeConfig.deploymentDomain)\n )\n notify('Link copied: it opens for members of the meeting chat', 'success')\n } catch {\n notify('Could not copy the link', 'error')\n }\n }\n\n const saveToThread = async (target: string | null) => {\n if (!selectedWorkspaceId) throw new Error('Open a workspace first')\n const files = await recordingFiles(arbi, await open(), title, (done, total) =>\n setProgress(`Decrypting ${done}/${total}…`)\n )\n if (!files.length) throw new Error('Nothing to save')\n // Re-encrypted under the workspace key, as a direct document upload.\n try {\n await save.recording({\n workspaceExtId: selectedWorkspaceId,\n files,\n conversationExtId: target,\n title,\n onUploading: () => setProgress('Uploading…'),\n })\n } finally {\n setProgress(null)\n }\n notify('Recording saved to the thread', 'success')\n }\n\n const summary = [\n 'Recording',\n MODE_LABEL[recording.mode],\n formatCallDuration(durationMs / 1000),\n speakers.length ? `${speakers.length} ${speakers.length === 1 ? 'speaker' : 'speakers'}` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n\n return (\n <div\n ref={cardRef}\n className={cn(\n 'mx-auto my-1 flex w-full max-w-xl flex-col gap-2 rounded-md border border-border bg-card px-3 py-2 text-xs',\n highlighted && 'ring-2 ring-primary'\n )}\n data-testid=\"recording-card\"\n data-recording={recording.external_id}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n {recording.mode === 'audio_video' ? (\n <Video className=\"size-4 text-red-500\" aria-hidden />\n ) : (\n <Mic className=\"size-4 text-red-500\" aria-hidden />\n )}\n <span className=\"font-medium\" data-testid=\"recording-summary\">\n {summary}\n </span>\n {time && <time className=\"text-muted-foreground\">{time}</time>}\n {live && <span className=\"text-red-500\">recording…</span>}\n {mediaDeleted && (\n <span className=\"text-muted-foreground\">Audio and video deleted — transcript kept</span>\n )}\n {!mediaDeleted && recording.expires_at && (\n <span className=\"text-muted-foreground\">\n Deleted after {new Date(recording.expires_at).toLocaleDateString()}\n </span>\n )}\n </div>\n {speakers.length > 0 && (\n <p className=\"flex flex-wrap items-center gap-1 text-muted-foreground\">\n {speakers.map((t, i) =>\n t.speaker_ext_id ? (\n <CallUserPill\n key={t.speaker_ext_id}\n identity={t.speaker_ext_id}\n name={t.speaker_name}\n />\n ) : (\n <span key={i}>{t.speaker_name || 'Someone'}</span>\n )\n )}\n </p>\n )}\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n aria-pressed={playing}\n onClick={() => setPlaying((p) => !p)}\n data-testid=\"recording-play\"\n >\n {playing ? (\n <Pause className=\"mr-1 size-3.5\" aria-hidden />\n ) : (\n <Play className=\"mr-1 size-3.5\" aria-hidden />\n )}\n {playing ? 'Close player' : 'Play'}\n </Button>\n )}\n {hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress}\n onClick={() => void download()}\n data-testid=\"recording-download\"\n >\n <Download className=\"mr-1 size-3.5\" aria-hidden />\n Download\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n onClick={() => void copyLink()}\n title=\"Copy an in-app link (only members of the meeting chat can open it)\"\n data-testid=\"recording-copy-link\"\n >\n <Link2 className=\"mr-1 size-3.5\" aria-hidden />\n Copy link\n </Button>\n {isHost && hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress || live}\n onClick={() => void transcribe()}\n data-testid=\"recording-transcribe\"\n >\n <Captions className=\"mr-1 size-3.5\" aria-hidden />\n Transcribe\n </Button>\n )}\n {isHost && hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress || live}\n onClick={() => setSaveOpen(true)}\n data-testid=\"recording-save-to-thread\"\n >\n <FileUp className=\"mr-1 size-3.5\" aria-hidden />\n Save to thread\n </Button>\n )}\n {isHost && !mediaDeleted && (\n <ConfirmButton\n label=\"Keep transcript, delete audio/video\"\n confirmLabel=\"Delete audio/video now\"\n testId=\"recording-delete-media\"\n disabled={!!progress || live}\n icon={<Trash2 className=\"mr-1 size-3.5\" aria-hidden />}\n onConfirm={async () => {\n try {\n await arbi.calls.recording.deleteMedia(call.external_id, recording.external_id)\n setPlaying(false)\n setOpened(null)\n refresh()\n } catch (err) {\n notify((err as Error).message, 'error')\n }\n }}\n />\n )}\n {isHost && (\n <ConfirmButton\n label=\"Delete\"\n confirmLabel=\"Delete recording\"\n testId=\"recording-delete\"\n disabled={!!progress || live}\n icon={<Trash2 className=\"mr-1 size-3.5\" aria-hidden />}\n onConfirm={async () => {\n try {\n await arbi.calls.recording.delete(call.external_id, recording.external_id)\n refresh()\n } catch (err) {\n notify((err as Error).message, 'error')\n }\n }}\n />\n )}\n {isHost && !mediaDeleted && (\n <label className=\"flex items-center gap-1 text-muted-foreground\">\n Keep\n <select\n className=\"h-7 rounded-sm border border-border bg-background px-1 text-xs text-foreground\"\n value={expiryChoiceOf(recording.expires_at ?? null)}\n onChange={(e) => {\n const days = e.target.value === 'none' ? null : Number(e.target.value)\n void arbi.calls.recording\n .setExpiry(call.external_id, recording.external_id, expiryFor(days))\n .then(refresh)\n .catch((err: unknown) => notify((err as Error).message, 'error'))\n }}\n data-testid=\"recording-expiry\"\n aria-label=\"Keep the audio and video for\"\n >\n {EXPIRY_DAYS.map((d) => (\n <option key={d ?? 'none'} value={d ?? 'none'}>\n {d ? `${d} days` : 'until deleted'}\n </option>\n ))}\n </select>\n </label>\n )}\n {progress && (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n {progress}\n </span>\n )}\n </div>\n {playing && hasMedia && (\n <RecordingPlayer recording={recording} open={open} durationMs={durationMs} />\n )}\n {saveOpen && (\n <PickThreadDialog\n heading=\"Save recording to thread\"\n description=\"The recording is decrypted here and uploaded as documents (one audio file per speaker, and the video) into a thread of the current workspace, encrypted under its key. Only that workspace’s members can read them there.\"\n testIdPrefix=\"save-recording\"\n confirmLabel=\"Save\"\n busyLabel=\"Saving…\"\n onClose={() => setSaveOpen(false)}\n onConfirm={saveToThread}\n />\n )}\n </div>\n )\n}\n\n/**\n * Plays a recording: the composite video when there is one (it carries the mixed audio the host\n * heard), otherwise the speaker tracks mixed in sync on one WebAudio timeline.\n */\nfunction RecordingPlayer({\n recording,\n open,\n durationMs,\n}: {\n recording: calls.CallRecording\n open(): Promise<OpenedRecording>\n durationMs: number\n}): ReactElement {\n const composite = compositeTrack(recording)\n const [view, setView] = useState<'video' | 'audio'>(composite?.parts?.length ? 'video' : 'audio')\n return (\n <div className=\"flex flex-col gap-2\" data-testid=\"recording-player\">\n {composite?.parts?.length ? (\n <div className=\"flex gap-1\" role=\"group\" aria-label=\"Play\">\n {(['video', 'audio'] as const).map((v) => (\n <button\n key={v}\n type=\"button\"\n className={cn(\n 'rounded-full px-2 py-0.5',\n view === v ? 'bg-muted font-medium' : 'text-muted-foreground hover:bg-muted'\n )}\n aria-pressed={view === v}\n onClick={() => setView(v)}\n >\n {v === 'video' ? 'Video' : 'Speakers'}\n </button>\n ))}\n </div>\n ) : null}\n {view === 'video' && composite ? (\n <CompositeVideo open={open} trackExtId={composite.external_id} />\n ) : (\n <MixPlayer recording={recording} open={open} durationMs={durationMs} />\n )}\n </div>\n )\n}\n\nfunction CompositeVideo({\n open,\n trackExtId,\n}: {\n open(): Promise<OpenedRecording>\n trackExtId: string\n}): ReactElement {\n const arbi = useArbi()\n const [urls, setUrls] = useState<string[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n let made: string[] = []\n void (async () => {\n try {\n const opened = await open()\n const track = (opened.recording.tracks ?? []).find((t) => t.external_id === trackExtId)\n const key = opened.keys.get(trackExtId)\n if (!track || !key) throw new Error('The video does not open with your key')\n const blobs = await compositeFiles(arbi, track, key)\n made = blobs.map((b) => URL.createObjectURL(b))\n if (cancelled) made.forEach((u) => URL.revokeObjectURL(u))\n else setUrls(made)\n } catch (err) {\n if (!cancelled) setError((err as Error).message)\n }\n })()\n return () => {\n cancelled = true\n made.forEach((u) => URL.revokeObjectURL(u))\n }\n }, [arbi, open, trackExtId])\n if (error) return <p className=\"text-destructive\">{error}</p>\n if (!urls) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n Decrypting the video…\n </span>\n )\n }\n return (\n <>\n {urls.map((u, i) => (\n <video\n key={u}\n src={u}\n controls\n className=\"w-full rounded-sm bg-black\"\n aria-label={`Video ${i + 1}`}\n />\n ))}\n </>\n )\n}\n\nconst fmt = (ms: number) => {\n const s = Math.max(0, Math.floor(ms / 1000))\n const h = Math.floor(s / 3600)\n const m = Math.floor((s % 3600) / 60)\n const sec = String(s % 60).padStart(2, '0')\n return h ? `${h}:${String(m).padStart(2, '0')}:${sec}` : `${m}:${sec}`\n}\n\n/**\n * The speaker tracks mixed in sync: parts are fetched, decrypted and decoded a little ahead of the\n * playhead and started on one AudioContext clock at their offsets (see `recording-playback.ts`).\n */\nfunction MixPlayer({\n recording,\n open,\n durationMs,\n}: {\n recording: calls.CallRecording\n open(): Promise<OpenedRecording>\n durationMs: number\n}): ReactElement {\n const arbi = useArbi()\n const { notify } = useBlocksEnvironment()\n const parts = useMemo(() => timelineOf(speakerTracks(recording)), [recording])\n const [position, setPosition] = useState(0)\n const [playing, setPlaying] = useState(false)\n const session = useRef<{\n ctx: AudioContext\n ctxStart: number\n seekMs: number\n scheduled: Set<string>\n timer: ReturnType<typeof setInterval>\n } | null>(null)\n\n const halt = useCallback(() => {\n const s = session.current\n session.current = null\n if (!s) return\n clearInterval(s.timer)\n void s.ctx.close().catch(() => undefined)\n }, [])\n\n useEffect(() => halt, [halt])\n\n const play = useCallback(\n async (fromMs: number) => {\n halt()\n const opened = await open()\n const ctx = new AudioContext()\n const s = {\n ctx,\n ctxStart: ctx.currentTime + 0.25,\n seekMs: fromMs,\n scheduled: new Set<string>(),\n timer: 0 as unknown as ReturnType<typeof setInterval>,\n }\n const schedule = async (part: TimelinePart) => {\n const track = (opened.recording.tracks ?? []).find((t) => t.external_id === part.trackExtId)\n const key = opened.keys.get(part.trackExtId)\n const raw = track?.parts?.find((p) => p.seq === part.seq)\n if (!track || !key || !raw) return\n try {\n const bytes = await fetchPart(arbi, raw, key)\n const buffer = await ctx.decodeAudioData(standalone(bytes).buffer)\n if (session.current !== s) return\n const at = schedulePart({\n partOffsetMs: part.offsetMs,\n bufferDurationS: buffer.duration,\n ctxStart: s.ctxStart,\n seekMs: s.seekMs,\n ctxNow: ctx.currentTime,\n })\n if (!at) return\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.connect(ctx.destination)\n source.start(at.when, at.offset)\n } catch (err) {\n console.warn('[calls] a recording part does not play', err)\n }\n }\n const tick = () => {\n if (session.current !== s) return\n const head = playheadAt(ctx.currentTime, s.ctxStart, s.seekMs)\n setPosition(Math.min(head, durationMs))\n if (head >= durationMs) {\n halt()\n setPlaying(false)\n return\n }\n for (const part of partsDue(parts, head, PLAYBACK_LOOKAHEAD_MS, s.scheduled)) {\n s.scheduled.add(partKey(part))\n void schedule(part)\n }\n }\n s.timer = setInterval(tick, 500)\n session.current = s\n setPlaying(true)\n tick()\n },\n [arbi, open, parts, durationMs, halt]\n )\n\n const toggle = () => {\n if (playing) {\n halt()\n setPlaying(false)\n } else {\n void play(position >= durationMs ? 0 : position).catch((err: unknown) => {\n setPlaying(false)\n notify((err as Error).message, 'error')\n })\n }\n }\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"outline\"\n className=\"size-7\"\n aria-label={playing ? 'Pause' : 'Play'}\n onClick={toggle}\n data-testid=\"recording-mix-toggle\"\n >\n {playing ? <Pause className=\"size-3.5\" /> : <Play className=\"size-3.5\" />}\n </Button>\n <input\n type=\"range\"\n min={0}\n max={Math.max(1, durationMs)}\n step={1000}\n value={position}\n className=\"flex-1\"\n aria-label=\"Position\"\n onChange={(e) => {\n const ms = Number(e.target.value)\n setPosition(ms)\n if (playing) {\n void play(ms).catch((err: unknown) => notify((err as Error).message, 'error'))\n }\n }}\n />\n <span className=\"tabular-nums text-muted-foreground\">\n {fmt(position)} / {fmt(durationMs)}\n </span>\n </div>\n )\n}\n","/**\n * A thread call's log card in the thread transcript: the `convo_events` row of kind `call` the\n * server writes when the call starts and updates when it ends (plaintext ids and times only).\n *\n * live: \"Call started by Ada · invited Bob, Cy\" · Join\n * ended: \"Call · 12 min · joined Ada, Bob\" · Open meeting chat\n *\n * It re-reads on `call.started` / `call.ended` (see `refreshCallCards`).\n */\n\nimport { useArbi, useCallSession, useCall, useOpenCallMeetingChat, openCall } from '@arbidocs/react'\nimport { useState, type ReactElement } from 'react'\nimport { MessageSquare, Phone, PhoneOff } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\nimport { formatCallDuration, type CallLogDetail } from '../call-cards'\n\nfunction joinNames(people: string[], name: (id: string) => string): string {\n const names = people.map(name)\n return names.length > 4\n ? `${names.slice(0, 4).join(', ')} +${names.length - 4}`\n : names.join(', ')\n}\n\nexport function ThreadCallLogCard({\n detail,\n name,\n workspaceExtId,\n time,\n}: {\n detail: CallLogDetail\n /** A person's display name by user ext id. */\n name: (userExtId: string) => string\n /** The thread's workspace (the meeting thread lives there too). */\n workspaceExtId: string | null\n time?: string\n}): ReactElement {\n const arbi = useArbi()\n const openCallMeetingChat = useOpenCallMeetingChat()\n const live = !detail.ended_at\n const inThisCall = useCallSession((s) => s.active?.callExtId === detail.call_ext_id)\n const inAnotherCall = useCallSession(\n (s) => !!s.active && s.active.callExtId !== detail.call_ext_id\n )\n // Only people holding K (the creator and those rung) can join from the card.\n const { data: call } = useCall(live ? detail.call_ext_id : null)\n const invitedOnly = live && !!call && !call.my_sealed_key\n const [busy, setBusy] = useState(false)\n\n const summary = live\n ? [\n detail.started_by ? `Call started by ${name(detail.started_by)}` : 'Call started',\n detail.invited.length ? `invited ${joinNames(detail.invited, name)}` : null,\n ]\n : [\n 'Call',\n formatCallDuration(detail.duration_s),\n detail.joined.length ? `joined ${joinNames(detail.joined, name)}` : null,\n ]\n\n return (\n <div\n className=\"mx-auto my-1 flex w-fit max-w-full flex-wrap items-center justify-center gap-2 rounded-md border border-border bg-card px-3 py-2 text-xs\"\n data-testid=\"thread-call-log-card\"\n data-live={live || undefined}\n >\n {live ? (\n <Phone className=\"size-4 animate-pulse text-green-text\" aria-hidden />\n ) : (\n <PhoneOff className=\"size-4 text-muted-foreground\" aria-hidden />\n )}\n <span data-testid=\"thread-call-log-summary\">{summary.filter(Boolean).join(' · ')}</span>\n {time && <time className=\"text-muted-foreground\">{time}</time>}\n {live ? (\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-7 bg-green-600 text-white hover:bg-green-700\"\n disabled={busy || inThisCall || inAnotherCall || invitedOnly}\n title={\n invitedOnly\n ? 'Only the people rung into this call can join'\n : inAnotherCall\n ? 'You are already in a call'\n : undefined\n }\n onClick={() => {\n setBusy(true)\n void openCall(arbi, { callExtId: detail.call_ext_id }).finally(() => setBusy(false))\n }}\n data-testid=\"thread-call-log-join\"\n >\n {inThisCall ? 'In call' : 'Join'}\n </Button>\n ) : (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n onClick={() =>\n void openCallMeetingChat({\n callExtId: detail.call_ext_id,\n meetingConversationExtId: detail.meeting_conversation_ext_id,\n workspaceExtId,\n })\n }\n data-testid=\"thread-call-log-open-chat\"\n >\n <MessageSquare className=\"mr-1 size-3.5\" aria-hidden />\n Open meeting chat\n </Button>\n )}\n </div>\n )\n}\n","/**\n * One stored line of a call transcript in its conversation (meeting chat or workspace meeting\n * thread): `TranscriptLine` from `@arbidocs/blocks`, centred for everyone. What someone is saying\n * right now shows as a provisional \"is speaking…\" row below, not as a highlight on a past line.\n */\n\nimport type { ReactElement } from 'react'\nimport { TranscriptLine } from '../../chat/TranscriptLine'\nimport { CallUserPill } from './CallUserPill'\n\nfunction formatTime(iso: string | null | undefined): string {\n if (!iso) return ''\n const at = Date.parse(iso)\n if (Number.isNaN(at)) return ''\n return new Date(at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport function TranscriptEntry({\n speakerId,\n speakerName,\n text,\n at,\n continued = false,\n className,\n}: {\n /** The speaker's identity (user ext id), for `data-speaker`. */\n speakerId: string\n /** The name to show (\"Me\" for my own lines). */\n speakerName: string\n text: string\n /** ISO time the segment started (or the message was stored). */\n at: string | null | undefined\n /** A further line of the same speaker's run (no name repeated). */\n continued?: boolean\n className?: string\n}): ReactElement {\n return (\n <TranscriptLine\n speakerId={speakerId}\n speakerName={speakerName}\n speaker={<CallUserPill identity={speakerId} name={speakerName} />}\n time={formatTime(at)}\n text={text}\n continued={continued}\n className={className}\n />\n )\n}\n","/** A call participant's name, as the people directory knows them. */\n\nimport { useMemo } from 'react'\nimport { useArbi, usePeople } from '@arbidocs/react'\nimport { getUserDisplayName } from '@arbidocs/react/ui'\n\n/** The name for an identity (user ext id): mine, a known person's, else the call's name for them. */\nexport function useCallPersonName(identity: string, fallbackName?: string | null): string {\n const arbi = useArbi()\n const { byId } = usePeople()\n const me = arbi.isLoggedIn && arbi.user.identity()?.externalId === identity\n const profile = me ? arbi.user.profile() : null\n return useMemo(() => {\n if (profile)\n return getUserDisplayName({ given_name: profile.givenName, family_name: profile.familyName })\n const user = byId(identity)\n if (user) return getUserDisplayName(user)\n return (fallbackName || identity).trim().split(/\\s+/).join(' ')\n }, [profile, byId, identity, fallbackName])\n}\n","/**\n * A call's conversation (meeting chat or meeting thread), call-aware: its empty state (\"Call in\n * progress — the transcript will appear here\", or \"No transcript\" afterwards) instead of the\n * generic one, and provisional \"<speaker> is speaking…\" rows while a line is on its way.\n */\n\nimport { useCallSession } from '@arbidocs/react'\nimport type { ReactElement } from 'react'\nimport { AudioLines, Captions, CaptionsOff } from 'lucide-react'\nimport { EmptyState } from '../../components/EmptyState'\nimport { ProvisionalTranscriptLine } from '../../chat/TranscriptLine'\nimport { useMyCallStatus } from '../call-status'\nimport { CallUserPill } from './CallUserPill'\nimport { useCallPersonName } from './call-person-name'\n\n/** The empty conversation of a call: live while the call runs, \"No transcript\" after. */\nexport function CallConversationEmpty({ callExtId }: { callExtId: string }): ReactElement {\n const { inCall, transcribing } = useMyCallStatus(callExtId)\n const live = useCallSession((s) => !!s.liveCalls[callExtId]) || inCall\n if (!live) {\n return (\n <EmptyState\n icon={AudioLines}\n title=\"No transcript\"\n description=\"This call was not transcribed. When a call here is transcribed, what people say appears in this conversation.\"\n className=\"mx-auto my-8 max-w-xl\"\n testId=\"call-conversation-empty\"\n />\n )\n }\n return (\n <EmptyState\n icon={transcribing ? Captions : CaptionsOff}\n title=\"Call in progress — the transcript will appear here\"\n description={\n transcribing\n ? 'Transcription is on: what people say shows up here as they speak.'\n : 'Transcription is off. The host can turn it on with CC in the call.'\n }\n className=\"mx-auto my-8 max-w-xl\"\n testId=\"call-conversation-empty\"\n />\n )\n}\n\nfunction ProvisionalRow({ identity }: { identity: string }): ReactElement {\n const name = useCallPersonName(identity)\n return (\n <ProvisionalTranscriptLine\n speakerId={identity}\n speakerName={name}\n speaker={<CallUserPill identity={identity} />}\n />\n )\n}\n\n/** The provisional rows at the bottom of a call's conversation (never stored). */\nexport function ProvisionalSpeakers({ ids }: { ids: string[] }): ReactElement | null {\n if (!ids.length) return null\n return (\n <div className=\"pb-2\" data-testid=\"transcript-provisional-rows\">\n {ids.map((id) => (\n <ProvisionalRow key={id} identity={id} />\n ))}\n </div>\n )\n}\n","/** Who gets a provisional \"is speaking…\" row in a call's conversation. */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useMyCallStatus } from '../call-status'\nimport { useSpeakingIds } from '../voice-levels'\n\n/** A spoken stretch whose line has not arrived yet. */\ninterface Pending {\n startedAt: number\n lastHeardAt: number\n}\n\n/** How long after someone stops a provisional row waits for their line before it gives up. */\nconst LINE_WAIT_MS = 10_000\n/** A burst shorter than this (a cough, a word) gets no row. */\nconst MIN_SPEECH_MS = 800\n\n/**\n * Who should show a provisional row: people talking now, and people who stopped but whose line\n * has not arrived yet (a line started at or after their stretch began replaces the row).\n */\nexport function useProvisionalSpeakers(\n callExtId: string | null | undefined,\n lines: { speakerId: string; at: number }[]\n): string[] {\n const { inCall, transcribing } = useMyCallStatus(callExtId)\n const speaking = useSpeakingIds()\n const pending = useRef(new Map<string, Pending>())\n const [, tick] = useState(0)\n const active = inCall && transcribing\n const now = Date.now()\n if (active) {\n for (const id of speaking) {\n const p = pending.current.get(id)\n if (p) p.lastHeardAt = now\n else pending.current.set(id, { startedAt: now, lastHeardAt: now })\n }\n } else if (pending.current.size) {\n pending.current.clear()\n }\n // A line that began within the stretch (a little slack for clock skew) replaces the row.\n const latest = useMemo(() => {\n const m = new Map<string, number>()\n for (const l of lines) m.set(l.speakerId, Math.max(m.get(l.speakerId) ?? 0, l.at))\n return m\n }, [lines])\n for (const [id, p] of [...pending.current]) {\n const arrived = (latest.get(id) ?? 0) >= p.startedAt - 3000\n const stale = !speaking.includes(id) && now - p.lastHeardAt > LINE_WAIT_MS\n if ((arrived && !speaking.includes(id)) || stale) pending.current.delete(id)\n else if (arrived) p.startedAt = now\n }\n // Re-check while rows wait for their lines.\n const waiting = pending.current.size > 0\n useEffect(() => {\n if (!waiting) return\n const id = setInterval(() => tick((n) => n + 1), 1000)\n return () => clearInterval(id)\n }, [waiting])\n return [...pending.current]\n .filter(([, p]) => p.lastHeardAt - p.startedAt >= MIN_SPEECH_MS)\n .map(([id]) => id)\n}\n","/**\n * How a meeting thread's transcript lines group: which messages continue their speaker's run (the\n * name is not repeated) and which are each speaker's newest line (highlighted while they talk).\n * Provided by the conversation page, read by each transcript message.\n */\n\nimport { createContext, useContext } from 'react'\nimport { transcriptRuns } from '../../chat/transcript-runs'\nimport { transcriptSegmentOf } from '@arbidocs/react'\n\nexport interface TranscriptRunInfo {\n continued: ReadonlySet<string>\n latest: ReadonlySet<string>\n}\n\nconst EMPTY: TranscriptRunInfo = { continued: new Set(), latest: new Set() }\n\nexport const TranscriptRunsContext = createContext<TranscriptRunInfo>(EMPTY)\n\nexport function useTranscriptRuns(): TranscriptRunInfo {\n return useContext(TranscriptRunsContext)\n}\n\ninterface ThreadMessageLike {\n external_id?: string | null\n created_at?: string | null\n tools?: unknown\n meta?: { tools?: unknown } | null\n}\n\n/** Runs and newest lines of a thread's messages (in display order). */\nexport function threadTranscriptRuns(messages: ThreadMessageLike[]): TranscriptRunInfo {\n const segmentOf = (m: ThreadMessageLike) => transcriptSegmentOf(m.tools ?? m.meta?.tools)\n const continuedItems = transcriptRuns(\n messages,\n (m) => segmentOf(m)?.speaker_ext_id ?? null,\n (m) => Date.parse(segmentOf(m)?.started_at ?? m.created_at ?? '') || 0\n )\n const latest = new Map<string, string>()\n for (const m of messages) {\n const seg = segmentOf(m)\n if (seg && m.external_id) latest.set(seg.speaker_ext_id, m.external_id)\n }\n return {\n continued: new Set(\n [...continuedItems].map((m) => m.external_id).filter((id): id is string => !!id)\n ),\n latest: new Set(latest.values()),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/connection/conversation/useMeetingThreadMessages.ts","../src/calls/connected/SaveTranscriptToThread.tsx","../src/calls/connected/RecordingCard.tsx","../src/calls/connected/ThreadCallLogCard.tsx","../src/calls/connected/TranscriptEntry.tsx","../src/calls/connected/call-person-name.ts","../src/calls/connected/CallConversationParts.tsx","../src/calls/connected/provisional-speakers.ts","../src/calls/connected/transcript-runs-context.ts"],"names":["useMemo","jsx","Fragment","jsxs","cn","useState","Button","useSaveToThread","useArbi","useCall","useCallSession","Captions","useRef","useEffect"],"mappings":";;;;;;;;;;;;;AAaO,SAAS,wBAAA,CACd,kBACA,cAAA,EACe;AACf,EAAA,MAAM,gBAAA,GAAmB,OAAA;AAAA,IACvB,MAAM,CAAC,CAAC,gBAAA,IAAoB,sBAAA,CAAuB,gBAAgB,mBAAmB,CAAA;AAAA,IACtF,CAAC,kBAAkB,cAAc;AAAA,GACnC;AACA,EAAA,MAAM,gBAAA,GAAmB,mBAAA,CAAoB,gBAAA,EAAkB,gBAAgB,CAAA;AAC/E,EAAA,OAAO,OAAA;AAAA,IACL,MACE,gBAAA,GACI,uBAAA,CAAwB,cAAA,EAAgB,mBAAA,EAAqB,gBAAgB,CAAA,GAC7E,cAAA;AAAA,IACN,CAAC,gBAAA,EAAkB,cAAA,EAAgB,gBAAgB;AAAA,GACrD;AACF;ACHA,IAAM,UAAA,GAAa,SAAA;AAGnB,SAAS,mBAAA,GAAsB;AAC7B,EAAA,MAAM,EAAE,WAAA,EAAa,MAAA,EAAO,GAAI,qBAAA,EAAsB;AACtD,EAAA,MAAM,EAAE,IAAA,EAAM,UAAA,EAAW,GAAI,aAAA,EAAc;AAC3C,EAAA,MAAM,YAAY,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AACvE,EAAA,MAAM,IAAA,GAAO,SAAA,EAAW,KAAA,EAAO,IAAA,CAAK,CAAC,EAAA,KAAO,EAAA,CAAG,IAAA,CAAK,WAAA,KAAgB,MAAM,CAAA,EAAG,IAAA,IAAQ,IAAA;AACrF,EAAA,OAAO,EAAE,WAAW,IAAA,EAAK;AAC3B;AAEO,SAAS,sBAAA,CAAuB;AAAA,EACrC,KAAA;AAAA,EACA,KAAA;AAAA,EACA,wBAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX;AACF,CAAA,EASwB;AACtB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,IAAI,CAAC,KAAA,CAAM,MAAA,EAAQ,OAAO,IAAA;AAC1B,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAM,2BAAA;AAAA,QACN,sBAAM,GAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC,CAAA;AAAA,QACjD,QAAA;AAAA,QACA,SAAA;AAAA,QACA,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,QAC3B,MAAA,EAAO;AAAA;AAAA,KACT;AAAA,IACC,IAAA,oBACC,GAAA;AAAA,MAAC,oBAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,KAAA;AAAA,QACA,0BAA0B,wBAAA,IAA4B,IAAA;AAAA,QACtD,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK;AAAA;AAAA;AAC9B,GAAA,EAEJ,CAAA;AAEJ;AAEA,SAAS,oBAAA,CAAqB;AAAA,EAC5B,KAAA;AAAA,EACA,KAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF,CAAA,EAKiB;AACf,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,oBAAA,EAAqB;AACxC,EAAA,MAAM,OAAO,eAAA,EAAgB;AAC7B,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,mBAAA,EAAoB;AAC1C,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,2BAAA;AAAA,MACR,6BACE,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,QAAA,kBAAA;AAAA,QACiB,KAAA,CAAM,MAAA;AAAA,QAAO,GAAA;AAAA,QAAE,KAAA,CAAM,MAAA,KAAW,CAAA,GAAI,MAAA,GAAS,OAAA;AAAA,QAAQ,4CAAA;AAAA,QAC9C,WAAW,IAAA,IAAQ,uBAAA;AAAA,QAAwB;AAAA,OAAA,EAErE,CAAA;AAAA,MAEF,YAAA,EAAa,iBAAA;AAAA,MACb,wBAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA,EAAW,OAAO,MAAA,KAAW;AAC3B,QAAA,MAAM,KAAK,UAAA,CAAW,EAAE,mBAAmB,MAAA,EAAQ,KAAA,EAAO,OAAO,CAAA;AACjE,QAAA,MAAA,CAAO,kCAAkC,SAAS,CAAA;AAAA,MACpD;AAAA;AAAA,GACF;AAEJ;AAMO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,OAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,wBAAA;AAAA,EACA,YAAA,GAAe,MAAA;AAAA,EACf,SAAA,GAAY,cAAA;AAAA,EACZ,SAAA;AAAA,EACA;AACF,CAAA,EAWiB;AACf,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,oBAAA,EAAqB;AACxC,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,mBAAA,EAAoB;AACrC,EAAA,MAAM,EAAE,IAAA,EAAM,aAAA,EAAc,GAAI,yBAAA,EAA0B;AAC1D,EAAA,MAAM,OAAA,GAAU,IAAA,KAAS,OAAA,IAAW,IAAA,KAAS,cAAA;AAC7C,EAAA,MAAM,OAAA,GAAUA,OAAAA;AAAA,IACd,MACE,OAAA,GACI,aAAA,CACG,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,IAAa,CAAA,CAAE,WAAA,KAAgB,wBAAwB,CAAA,CACvE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,UAAU,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,UAAU,CAAC,CAAA,GACrE,EAAC;AAAA,IACP,CAAC,aAAA,EAAe,OAAA,EAAS,wBAAwB;AAAA,GACnD;AACA,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAiB,UAAU,CAAA;AACvD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AAEtC,EAAA,MAAM,OAAO,YAAY;AACvB,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,MAAA,KAAW,UAAA,GAAa,IAAA,GAAO,MAAM,CAAA;AACrD,MAAA,OAAA,EAAQ;AAAA,IACV,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAQ,GAAA,CAAc,SAAS,OAAO,CAAA;AAAA,IACxC,CAAA,SAAE;AACA,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IACf;AAAA,EACF,CAAA;AAEA,EAAA,uBACE,GAAA,CAAC,UAAO,IAAA,EAAI,IAAA,EAAC,cAAc,CAAC,CAAA,KAAM,CAAC,CAAA,IAAK,CAAC,QAAQ,OAAA,EAAQ,EACvD,+BAAC,aAAA,EAAA,EAAc,SAAA,EAAU,eAAc,aAAA,EAAa,CAAA,EAAG,YAAY,CAAA,OAAA,CAAA,EACjE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,eAAa,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,sBACtB,GAAA,CAAC,qBAAmB,QAAA,EAAA,WAAA,EAAY;AAAA,KAAA,EAClC,CAAA;AAAA,IACC,CAAC,OAAA,mBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAgC,QAAA,EAAA,gDAAA,EAE7C,CAAA,mBAEA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,8CAAA,EAA+C,IAAA,EAAK,YAAA,EAC/D,QAAA,EAAA,CAAC,EAAE,WAAA,EAAa,UAAA,EAAY,KAAA,EAAO,YAAA,EAAa,EAAG,GAAG,OAAO,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,qBACnE,GAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,OAAA;AAAA,QACL,cAAA,EAAc,WAAW,CAAA,CAAE,WAAA;AAAA,QAC3B,SAAA,EAAW,EAAA;AAAA,UACT,yEAAA;AAAA,UACA,MAAA,KAAW,EAAE,WAAA,IAAe;AAAA,SAC9B;AAAA,QACA,OAAA,EAAS,MAAM,SAAA,CAAU,CAAA,CAAE,WAAW,CAAA;AAAA,QACtC,aAAA,EAAa,CAAA,EAAG,YAAY,CAAA,QAAA,EAAW,EAAE,WAAW,CAAA,CAAA;AAAA,QAEnD,YAAE,KAAA,IAAS;AAAA;AAAA,KACd,EAAA,EAbO,CAAA,CAAE,WAcX,CACD,CAAA,EACH,CAAA;AAAA,yBAED,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAO,OAAA,EAAQ,OAAA,EAAQ,SAAS,OAAA,EAAS,QAAA,EAAU,MAAM,QAAA,EAAA,QAAA,EAE1D,CAAA;AAAA,sBACA,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,MAAM,KAAK,IAAA,EAAK;AAAA,UACzB,QAAA,EAAU,QAAQ,CAAC,OAAA;AAAA,UACnB,aAAA,EAAa,GAAG,YAAY,CAAA,QAAA,CAAA;AAAA,UAE3B,iBAAO,SAAA,GAAY;AAAA;AAAA;AACtB,KAAA,EACF;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;ACxJO,SAAS,aAAA,CAAc;AAAA,EAC5B,SAAA;AAAA,EACA,cAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAMwB;AACtB,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,QAAQ,SAAS,CAAA;AACxC,EAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,SAAA,EAAW,cAAc,CAAA;AACtD,EAAA,MAAM,GAAA,GAAM,iBAAA,CAAkB,SAAA,EAAW,CAAC,cAAc,CAAA;AACxD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,IAAI,GAAA,CAAI,OAAA,EAAS,uBAAOC,IAAC,oBAAA,EAAA,EAAqB,CAAA;AAC9C,IAAA,OAAO,GAAA,CAAI,IAAA,mBACTA,GAAAA,CAAC,iBAAA,EAAA,EAAkB,IAAA,EAAY,SAAA,EAAW,GAAA,CAAI,IAAA,EAAM,KAAA,EAAc,IAAA,EAAY,CAAA,GAC5E,IAAA;AAAA,EACN;AACA,EAAA,uBACEA,GAAAA,CAAAC,QAAAA,EAAA,EACI,QAAA,EAAA,CAAA,GAAA,CAAI,IAAA,IAAQ,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,qBACrBD,GAAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MAEC,IAAA;AAAA,MACA,SAAA,EAAW,CAAA;AAAA,MACX,KAAA;AAAA,MACA;AAAA,KAAA;AAAA,IAJK,CAAA,CAAE;AAAA,GAMV,CAAA,EACH,CAAA;AAEJ;AAGO,SAAS,cAAA,CAAe;AAAA,EAC7B,SAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAIiB;AACf,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,QAAQ,SAAS,CAAA;AACxC,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,OAAA,EAAQ,GAAI,kBAAkB,SAAS,CAAA;AAChE,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,MAAM,CAAC,GAAI,IAAA,IAAQ,EAAG,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,MAAM,IAAA,CAAK,KAAA,CAAM,EAAE,UAAU,CAAA,GAAI,KAAK,KAAA,CAAM,CAAA,CAAE,UAAU,CAAC,CAAA;AAAA,IAC1F,CAAC,IAAI;AAAA,GACP;AACA,EAAA,uBACEG,KAAC,KAAA,EAAA,EAAI,SAAA,EAAWC,GAAG,qBAAA,EAAuB,SAAS,CAAA,EAAG,aAAA,EAAY,iBAAA,EAC/D,QAAA,EAAA;AAAA,IAAA,SAAA,oBAAaH,GAAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,mDAAA,EAAoD,CAAA;AAAA,IACpF,2BACCA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,6CAA4C,QAAA,EAAA,gCAAA,EAA8B,CAAA;AAAA,IAExF,CAAC,SAAA,IAAa,CAAC,OAAA,IAAW,CAAC,MAAA,CAAO,MAAA,oBACjCA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,2CAAA,EAA4C,QAAA,EAAA,oBAAA,EAAkB,CAAA;AAAA,IAE5E,IAAA,IACC,MAAA,CAAO,GAAA,CAAI,CAAC,sBACVA,GAAAA,CAAC,iBAAA,EAAA,EAAsC,IAAA,EAAY,SAAA,EAAW,CAAA,EAAG,KAAA,EAAA,EAAzC,CAAA,CAAE,WAAqD,CAChF;AAAA,GAAA,EACL,CAAA;AAEJ;AAEA,SAAS,oBAAA,GAAqC;AAC5C,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,oGAAA;AAAA,MACV,aAAA,EAAY,gBAAA;AAAA,MACb,QAAA,EAAA;AAAA;AAAA,GAED;AAEJ;AAGA,SAAS,aAAA,CAAc;AAAA,EACrB,KAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAOiB;AACf,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAII,SAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,SAAS,KAAK,CAAA;AACtC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,IAAI,UAAA,CAAW,MAAM,SAAA,CAAU,KAAK,GAAG,GAAI,CAAA;AACjD,IAAA,OAAO,MAAM,aAAa,CAAC,CAAA;AAAA,EAC7B,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,uBACEF,IAAAA;AAAA,IAACG,MAAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,IAAA,EAAK,IAAA;AAAA,MACL,OAAA,EAAS,SAAS,aAAA,GAAgB,SAAA;AAAA,MAClC,SAAA,EAAU,KAAA;AAAA,MACV,UAAU,QAAA,IAAY,IAAA;AAAA,MACtB,SAAS,MAAM;AACb,QAAA,IAAI,CAAC,MAAA,EAAQ;AACX,UAAA,SAAA,CAAU,IAAI,CAAA;AACd,UAAA;AAAA,QACF;AACA,QAAA,SAAA,CAAU,KAAK,CAAA;AACf,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA,KAAK,WAAU,CAAE,OAAA,CAAQ,MAAM,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,MAC/C,CAAA;AAAA,MACA,aAAA,EAAa,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,QAAA,CAAA,GAAa,MAAA;AAAA,MAE3C,QAAA,EAAA;AAAA,QAAA,IAAA,mBAAOL,GAAAA,CAAC,OAAA,EAAA,EAAQ,WAAU,4BAAA,EAA6B,aAAA,EAAW,MAAC,CAAA,GAAK,IAAA;AAAA,QACxE,SAAS,YAAA,GAAe;AAAA;AAAA;AAAA,GAC3B;AAEJ;AAEA,SAAS,iBAAA,CAAkB;AAAA,EACzB,IAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAKiB;AACf,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,OAAA,GAAU,oBAAoB,IAAI,CAAA;AACxC,EAAA,MAAM,OAAOM,eAAAA,EAAgB;AAC7B,EAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAc,GAAI,oBAAA,EAAqB;AACvD,EAAA,MAAM,SAAS,IAAA,CAAK,UAAA;AACpB,EAAA,MAAM,YAAA,GAAe,CAAC,CAAC,SAAA,CAAU,gBAAA;AACjC,EAAA,MAAM,OAAO,SAAA,CAAU,KAAA,KAAU,eAAgB,CAAC,SAAA,CAAU,cAAc,CAAC,YAAA;AAC3E,EAAA,MAAM,QAAA,GAAW,cAAc,SAAS,CAAA;AACxC,EAAA,MAAM,QAAA,GAAWP,OAAAA,CAAQ,MAAM,UAAA,CAAW,SAAA,CAAU,MAAA,IAAU,EAAE,CAAA,EAAG,CAAC,SAAA,CAAU,MAAM,CAAC,CAAA;AACrF,EAAA,MAAM,UAAA,GAAa,mBAAmB,QAAQ,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,CAAC,YAAA,IAAgB,QAAA,CAAS,MAAA,GAAS,CAAA;AACpD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIK,SAAiC,IAAI,CAAA;AACjE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAC5D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,EAAE,WAAA,EAAa,mBAAA,EAAoB,GAAI,qBAAA,EAAsB;AAGnE,EAAA,MAAM,UAAU,mBAAA,EAAoB;AACpC,EAAA,MAAM,WAAA,GAAc,YAAY,SAAA,CAAU,WAAA;AAC1C,EAAA,MAAM,OAAA,GAAU,OAA8B,IAAI,CAAA;AAClD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,OAAA,CAAQ,SAAS,cAAA,CAAe,EAAE,OAAO,QAAA,EAAU,QAAA,EAAU,UAAU,CAAA;AACvE,IAAA,MAAM,IAAI,UAAA,CAAW,MAAM,mBAAA,CAAoB,IAAI,GAAG,GAAI,CAAA;AAC1D,IAAA,OAAO,MAAM,aAAa,CAAC,CAAA;AAAA,EAC7B,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,EAAE,SAAQ,GAAI,OAAA;AAEpB,EAAA,MAAM,IAAA,GAAO,YAAY,YAAsC;AAC7D,IAAA,IAAI,MAAA,IAAU,MAAA,CAAO,SAAA,KAAc,SAAA,EAAW,OAAO,MAAA;AACrD,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA;AACzC,IAAA,SAAA,CAAU,IAAI,CAAA;AACd,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,EAAG,CAAC,OAAA,EAAS,MAAA,EAAQ,SAAS,CAAC,CAAA;AAE/B,EAAA,MAAM,GAAA,GAAM,OAAO,KAAA,EAAe,IAAA,KAA8B;AAC9D,IAAA,WAAA,CAAY,KAAK,CAAA;AACjB,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,EAAK;AAAA,IACb,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,IAAA,CAAK,mCAAmC,GAAG,CAAA;AACnD,MAAA,MAAA,CAAQ,GAAA,CAAc,SAAS,OAAO,CAAA;AAAA,IACxC,CAAA,SAAE;AACA,MAAA,WAAA,CAAY,IAAI,CAAA;AAAA,IAClB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,MACf,GAAA,CAAI,kBAAA,EAAe,YAAY;AAC7B,IAAA,MAAM,QAAQ,MAAM,cAAA;AAAA,MAAe,IAAA;AAAA,MAAM,MAAM,IAAA,EAAK;AAAA,MAAG,KAAA;AAAA,MAAO,CAAC,MAAM,KAAA,KACnE,WAAA,CAAY,cAAc,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,CAAG;AAAA,KAC5C;AACA,IAAA,IAAI,CAAC,KAAA,CAAM,MAAA,EAAQ,MAAM,IAAI,MAAM,qBAAqB,CAAA;AACxD,IAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,YAAA,CAAa,CAAA,EAAG,EAAE,IAAI,CAAA;AAAA,EAC/C,CAAC,CAAA;AAEH,EAAA,MAAM,UAAA,GAAa,MACjB,GAAA,CAAI,oBAAA,EAAiB,YAAY;AAC/B,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAM,OAAA,CAAQ,UAAA;AAAA,MAAW,MAAM,IAAA,EAAK;AAAA,MAAG,CAAC,MAAM,KAAA,KACvE,WAAA,CAAY,gBAAgB,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,CAAG;AAAA,KAC9C;AACA,IAAA,MAAA;AAAA,MACE,SACI,CAAA,YAAA,EAAe,MAAM,WAAW,MAAM,CAAA,aAAA,CAAA,GACtC,eAAe,MAAM,CAAA,4BAAA,CAAA;AAAA,MACzB,SAAS,SAAA,GAAY;AAAA,KACvB;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,MAAM,WAAW,YAAY;AAC3B,IAAA,MAAM,GAAA,GAAM,mBAAmB,IAAI,CAAA;AACnC,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAA,CAAO,iDAAiD,OAAO,CAAA;AAC/D,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,MAAM,UAAU,SAAA,CAAU,SAAA;AAAA,QACxB,aAAA,CAAc,GAAA,EAAK,SAAA,CAAU,WAAA,EAAa,cAAc,gBAAgB;AAAA,OAC1E;AACA,MAAA,MAAA,CAAO,yDAAyD,SAAS,CAAA;AAAA,IAC3E,CAAA,CAAA,MAAQ;AACN,MAAA,MAAA,CAAO,2BAA2B,OAAO,CAAA;AAAA,IAC3C;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,OAAO,MAAA,KAA0B;AACpD,IAAA,IAAI,CAAC,mBAAA,EAAqB,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAClE,IAAA,MAAM,QAAQ,MAAM,cAAA;AAAA,MAAe,IAAA;AAAA,MAAM,MAAM,IAAA,EAAK;AAAA,MAAG,KAAA;AAAA,MAAO,CAAC,MAAM,KAAA,KACnE,WAAA,CAAY,cAAc,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,CAAG;AAAA,KAC5C;AACA,IAAA,IAAI,CAAC,KAAA,CAAM,MAAA,EAAQ,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAEpD,IAAA,IAAI;AACF,MAAA,MAAM,KAAK,SAAA,CAAU;AAAA,QACnB,cAAA,EAAgB,mBAAA;AAAA,QAChB,KAAA;AAAA,QACA,iBAAA,EAAmB,MAAA;AAAA,QACnB,KAAA;AAAA,QACA,WAAA,EAAa,MAAM,WAAA,CAAY,iBAAY;AAAA,OAC5C,CAAA;AAAA,IACH,CAAA,SAAE;AACA,MAAA,WAAA,CAAY,IAAI,CAAA;AAAA,IAClB;AACA,IAAA,MAAA,CAAO,iCAAiC,SAAS,CAAA;AAAA,EACnD,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,WAAA;AAAA,IACA,UAAA,CAAW,UAAU,IAAI,CAAA;AAAA,IACzB,kBAAA,CAAmB,aAAa,GAAI,CAAA;AAAA,IACpC,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,MAAA,KAAW,CAAA,GAAI,SAAA,GAAY,UAAU,CAAA,CAAA,GAAK;AAAA,GAC7F,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,QAAK,CAAA;AAEb,EAAA,uBACEF,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,OAAA;AAAA,MACL,SAAA,EAAWC,EAAAA;AAAA,QACT,4GAAA;AAAA,QACA,WAAA,IAAe;AAAA,OACjB;AAAA,MACA,aAAA,EAAY,gBAAA;AAAA,MACZ,kBAAgB,SAAA,CAAU,WAAA;AAAA,MAE1B,QAAA,EAAA;AAAA,wBAAAD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mCAAA,EACZ,QAAA,EAAA;AAAA,UAAA,SAAA,CAAU,SAAS,aAAA,mBAClBF,GAAAA,CAAC,KAAA,EAAA,EAAM,WAAU,qBAAA,EAAsB,aAAA,EAAW,IAAA,EAAC,CAAA,mBAEnDA,GAAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAsB,eAAW,IAAA,EAAC,CAAA;AAAA,0BAEnDA,GAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,aAAA,EAAc,aAAA,EAAY,qBACvC,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,UACC,wBAAQA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAyB,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,UACtD,wBAAQA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAe,QAAA,EAAA,iBAAA,EAAU,CAAA;AAAA,UACjD,gCACCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAwB,QAAA,EAAA,gDAAA,EAAyC,CAAA;AAAA,UAElF,CAAC,gBAAgB,SAAA,CAAU,UAAA,oBAC1BE,IAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,uBAAA,EAAwB,QAAA,EAAA;AAAA,YAAA,gBAAA;AAAA,YACvB,IAAI,IAAA,CAAK,SAAA,CAAU,UAAU,EAAE,kBAAA;AAAmB,WAAA,EACnE;AAAA,SAAA,EAEJ,CAAA;AAAA,QACC,QAAA,CAAS,SAAS,CAAA,oBACjBF,IAAC,GAAA,EAAA,EAAE,SAAA,EAAU,2DACV,QAAA,EAAA,QAAA,CAAS,GAAA;AAAA,UAAI,CAAC,CAAA,EAAG,CAAA,KAChB,CAAA,CAAE,iCACAA,GAAAA;AAAA,YAAC,YAAA;AAAA,YAAA;AAAA,cAEC,UAAU,CAAA,CAAE,cAAA;AAAA,cACZ,MAAM,CAAA,CAAE;AAAA,aAAA;AAAA,YAFH,CAAA,CAAE;AAAA,8BAKTA,GAAAA,CAAC,UAAc,QAAA,EAAA,CAAA,CAAE,YAAA,IAAgB,aAAtB,CAAgC;AAAA,SAE/C,EACF,CAAA;AAAA,wBAEFE,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qCAAA,EACZ,QAAA,EAAA;AAAA,UAAA,QAAA,oBACCA,IAAAA;AAAA,YAACG,MAAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,IAAA;AAAA,cACL,OAAA,EAAQ,SAAA;AAAA,cACR,SAAA,EAAU,KAAA;AAAA,cACV,cAAA,EAAc,OAAA;AAAA,cACd,SAAS,MAAM,UAAA,CAAW,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA;AAAA,cACnC,aAAA,EAAY,gBAAA;AAAA,cAEX,QAAA,EAAA;AAAA,gBAAA,OAAA,mBACCL,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,iBAAgB,aAAA,EAAW,IAAA,EAAC,CAAA,mBAE7CA,GAAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,gBAE7C,UAAU,cAAA,GAAiB;AAAA;AAAA;AAAA,WAC9B;AAAA,UAED,4BACCE,IAAAA;AAAA,YAACG,MAAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,IAAA;AAAA,cACL,OAAA,EAAQ,SAAA;AAAA,cACR,SAAA,EAAU,KAAA;AAAA,cACV,QAAA,EAAU,CAAC,CAAC,QAAA;AAAA,cACZ,OAAA,EAAS,MAAM,KAAK,QAAA,EAAS;AAAA,cAC7B,aAAA,EAAY,oBAAA;AAAA,cAEZ,QAAA,EAAA;AAAA,gCAAAL,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,gBAAE;AAAA;AAAA;AAAA,WAEpD;AAAA,0BAEFE,IAAAA;AAAA,YAACG,MAAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,IAAA;AAAA,cACL,OAAA,EAAQ,SAAA;AAAA,cACR,SAAA,EAAU,KAAA;AAAA,cACV,OAAA,EAAS,MAAM,KAAK,QAAA,EAAS;AAAA,cAC7B,KAAA,EAAM,oEAAA;AAAA,cACN,aAAA,EAAY,qBAAA;AAAA,cAEZ,QAAA,EAAA;AAAA,gCAAAL,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,gBAAE;AAAA;AAAA;AAAA,WAEjD;AAAA,UACC,MAAA,IAAU,4BACTE,IAAAA;AAAA,YAACG,MAAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,IAAA;AAAA,cACL,OAAA,EAAQ,SAAA;AAAA,cACR,SAAA,EAAU,KAAA;AAAA,cACV,QAAA,EAAU,CAAC,CAAC,QAAA,IAAY,IAAA;AAAA,cACxB,OAAA,EAAS,MAAM,KAAK,UAAA,EAAW;AAAA,cAC/B,aAAA,EAAY,sBAAA;AAAA,cAEZ,QAAA,EAAA;AAAA,gCAAAL,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,gBAAE;AAAA;AAAA;AAAA,WAEpD;AAAA,UAED,MAAA,IAAU,4BACTE,IAAAA;AAAA,YAACG,MAAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,IAAA;AAAA,cACL,OAAA,EAAQ,SAAA;AAAA,cACR,SAAA,EAAU,KAAA;AAAA,cACV,QAAA,EAAU,CAAC,CAAC,QAAA,IAAY,IAAA;AAAA,cACxB,OAAA,EAAS,MAAM,WAAA,CAAY,IAAI,CAAA;AAAA,cAC/B,aAAA,EAAY,0BAAA;AAAA,cAEZ,QAAA,EAAA;AAAA,gCAAAL,GAAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,gBAAE;AAAA;AAAA;AAAA,WAElD;AAAA,UAED,MAAA,IAAU,CAAC,YAAA,oBACVA,GAAAA;AAAA,YAAC,aAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,qCAAA;AAAA,cACN,YAAA,EAAa,wBAAA;AAAA,cACb,MAAA,EAAO,wBAAA;AAAA,cACP,QAAA,EAAU,CAAC,CAAC,QAAA,IAAY,IAAA;AAAA,cACxB,sBAAMA,GAAAA,CAAC,UAAO,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,cACpD,WAAW,YAAY;AACrB,gBAAA,IAAI;AACF,kBAAA,MAAM,KAAK,KAAA,CAAM,SAAA,CAAU,YAAY,IAAA,CAAK,WAAA,EAAa,UAAU,WAAW,CAAA;AAC9E,kBAAA,UAAA,CAAW,KAAK,CAAA;AAChB,kBAAA,SAAA,CAAU,IAAI,CAAA;AACd,kBAAA,OAAA,EAAQ;AAAA,gBACV,SAAS,GAAA,EAAK;AACZ,kBAAA,MAAA,CAAQ,GAAA,CAAc,SAAS,OAAO,CAAA;AAAA,gBACxC;AAAA,cACF;AAAA;AAAA,WACF;AAAA,UAED,0BACCA,GAAAA;AAAA,YAAC,aAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,QAAA;AAAA,cACN,YAAA,EAAa,kBAAA;AAAA,cACb,MAAA,EAAO,kBAAA;AAAA,cACP,QAAA,EAAU,CAAC,CAAC,QAAA,IAAY,IAAA;AAAA,cACxB,sBAAMA,GAAAA,CAAC,UAAO,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,cACpD,WAAW,YAAY;AACrB,gBAAA,IAAI;AACF,kBAAA,MAAM,KAAK,KAAA,CAAM,SAAA,CAAU,OAAO,IAAA,CAAK,WAAA,EAAa,UAAU,WAAW,CAAA;AACzE,kBAAA,OAAA,EAAQ;AAAA,gBACV,SAAS,GAAA,EAAK;AACZ,kBAAA,MAAA,CAAQ,GAAA,CAAc,SAAS,OAAO,CAAA;AAAA,gBACxC;AAAA,cACF;AAAA;AAAA,WACF;AAAA,UAED,UAAU,CAAC,YAAA,oBACVE,IAAAA,CAAC,OAAA,EAAA,EAAM,WAAU,+CAAA,EAAgD,QAAA,EAAA;AAAA,YAAA,MAAA;AAAA,4BAE/DF,GAAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,gFAAA;AAAA,gBACV,KAAA,EAAO,cAAA,CAAe,SAAA,CAAU,UAAA,IAAc,IAAI,CAAA;AAAA,gBAClD,QAAA,EAAU,CAAC,CAAA,KAAM;AACf,kBAAA,MAAM,IAAA,GAAO,EAAE,MAAA,CAAO,KAAA,KAAU,SAAS,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AACrE,kBAAA,KAAK,IAAA,CAAK,MAAM,SAAA,CACb,SAAA,CAAU,KAAK,WAAA,EAAa,SAAA,CAAU,WAAA,EAAa,SAAA,CAAU,IAAI,CAAC,EAClE,IAAA,CAAK,OAAO,EACZ,KAAA,CAAM,CAAC,QAAiB,MAAA,CAAQ,GAAA,CAAc,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,gBACpE,CAAA;AAAA,gBACA,aAAA,EAAY,kBAAA;AAAA,gBACZ,YAAA,EAAW,8BAAA;AAAA,gBAEV,sBAAY,GAAA,CAAI,CAAC,CAAA,qBAChBA,IAAC,QAAA,EAAA,EAAyB,KAAA,EAAO,CAAA,IAAK,MAAA,EACnC,cAAI,CAAA,EAAG,CAAC,UAAU,eAAA,EAAA,EADR,CAAA,IAAK,MAElB,CACD;AAAA;AAAA;AACH,WAAA,EACF,CAAA;AAAA,UAED,QAAA,oBACCE,IAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,sDAAA,EACd,QAAA,EAAA;AAAA,4BAAAF,GAAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,uBAAA,EAAwB,eAAW,IAAA,EAAC,CAAA;AAAA,YACtD;AAAA,WAAA,EACH;AAAA,SAAA,EAEJ,CAAA;AAAA,QACC,WAAW,QAAA,oBACVA,IAAC,eAAA,EAAA,EAAgB,SAAA,EAAsB,MAAY,UAAA,EAAwB,CAAA;AAAA,QAE5E,4BACCA,GAAAA;AAAA,UAAC,gBAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAQ,0BAAA;AAAA,YACR,WAAA,EAAY,gOAAA;AAAA,YACZ,YAAA,EAAa,gBAAA;AAAA,YACb,YAAA,EAAa,MAAA;AAAA,YACb,SAAA,EAAU,cAAA;AAAA,YACV,OAAA,EAAS,MAAM,WAAA,CAAY,KAAK,CAAA;AAAA,YAChC,SAAA,EAAW;AAAA;AAAA;AACb;AAAA;AAAA,GAEJ;AAEJ;AAMA,SAAS,eAAA,CAAgB;AAAA,EACvB,SAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIiB;AACf,EAAA,MAAM,SAAA,GAAY,eAAe,SAAS,CAAA;AAC1C,EAAA,MAAM,CAAC,MAAM,OAAO,CAAA,GAAII,SAA4B,SAAA,EAAW,KAAA,EAAO,MAAA,GAAS,OAAA,GAAU,OAAO,CAAA;AAChG,EAAA,uBACEF,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAsB,eAAY,kBAAA,EAC9C,QAAA,EAAA;AAAA,IAAA,SAAA,EAAW,OAAO,MAAA,mBACjBF,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,cAAa,IAAA,EAAK,OAAA,EAAQ,YAAA,EAAW,MAAA,EAChD,WAAC,OAAA,EAAS,OAAO,EAAY,GAAA,CAAI,CAAC,sBAClCA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QAEC,IAAA,EAAK,QAAA;AAAA,QACL,SAAA,EAAWG,EAAAA;AAAA,UACT,0BAAA;AAAA,UACA,IAAA,KAAS,IAAI,sBAAA,GAAyB;AAAA,SACxC;AAAA,QACA,gBAAc,IAAA,KAAS,CAAA;AAAA,QACvB,OAAA,EAAS,MAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,QAEvB,QAAA,EAAA,CAAA,KAAM,UAAU,OAAA,GAAU;AAAA,OAAA;AAAA,MATtB;AAAA,KAWR,GACH,CAAA,GACE,IAAA;AAAA,IACH,SAAS,OAAA,IAAW,SAAA,mBACnBH,GAAAA,CAAC,kBAAe,IAAA,EAAY,UAAA,EAAY,SAAA,CAAU,WAAA,EAAa,oBAE/DA,GAAAA,CAAC,SAAA,EAAA,EAAU,SAAA,EAAsB,MAAY,UAAA,EAAwB;AAAA,GAAA,EAEzE,CAAA;AAEJ;AAEA,SAAS,cAAA,CAAe;AAAA,EACtB,IAAA;AAAA,EACA;AACF,CAAA,EAGiB;AACf,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAII,SAA0B,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAwB,IAAI,CAAA;AACtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,IAAI,OAAiB,EAAC;AACtB,IAAA,KAAA,CAAM,YAAY;AAChB,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAC1B,QAAA,MAAM,KAAA,GAAA,CAAS,MAAA,CAAO,SAAA,CAAU,MAAA,IAAU,EAAC,EAAG,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,UAAU,CAAA;AACtF,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA;AACtC,QAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAK,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAC3E,QAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,IAAA,EAAM,OAAO,GAAG,CAAA;AACnD,QAAA,IAAA,GAAO,MAAM,GAAA,CAAI,CAAC,MAAM,GAAA,CAAI,eAAA,CAAgB,CAAC,CAAC,CAAA;AAC9C,QAAA,IAAI,SAAA,OAAgB,OAAA,CAAQ,CAAC,MAAM,GAAA,CAAI,eAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,qBAC5C,IAAI,CAAA;AAAA,MACnB,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,CAAC,SAAA,EAAW,QAAA,CAAU,GAAA,CAAc,OAAO,CAAA;AAAA,MACjD;AAAA,IACF,CAAA,GAAG;AACH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,IAAA,CAAK,QAAQ,CAAC,CAAA,KAAM,GAAA,CAAI,eAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,IAC5C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAC3B,EAAA,IAAI,OAAO,uBAAOJ,IAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oBAAoB,QAAA,EAAA,KAAA,EAAM,CAAA;AACzD,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,uBACEE,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sDAAA,EACd,QAAA,EAAA;AAAA,sBAAAF,GAAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,uBAAA,EAAwB,eAAW,IAAA,EAAC,CAAA;AAAA,MAAE;AAAA,KAAA,EAE3D,CAAA;AAAA,EAEJ;AACA,EAAA,uBACEA,IAAAC,QAAAA,EAAA,EACG,eAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACZD,GAAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MAEC,GAAA,EAAK,CAAA;AAAA,MACL,QAAA,EAAQ,IAAA;AAAA,MACR,SAAA,EAAU,4BAAA;AAAA,MACV,YAAA,EAAY,CAAA,MAAA,EAAS,CAAA,GAAI,CAAC,CAAA;AAAA,KAAA;AAAA,IAJrB;AAAA,GAMR,CAAA,EACH,CAAA;AAEJ;AAEA,IAAM,GAAA,GAAM,CAAC,EAAA,KAAe;AAC1B,EAAA,MAAM,CAAA,GAAI,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,EAAA,GAAK,GAAI,CAAC,CAAA;AAC3C,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,IAAI,CAAA;AAC7B,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAO,CAAA,GAAI,OAAQ,EAAE,CAAA;AACpC,EAAA,MAAM,MAAM,MAAA,CAAO,CAAA,GAAI,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAC1C,EAAA,OAAO,IAAI,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,GAAG,KAAK,CAAA,EAAG,CAAC,IAAI,GAAG,CAAA,CAAA;AACtE,CAAA;AAMA,SAAS,SAAA,CAAU;AAAA,EACjB,SAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIiB;AACf,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,oBAAA,EAAqB;AACxC,EAAA,MAAM,KAAA,GAAQD,OAAAA,CAAQ,MAAM,UAAA,CAAW,aAAA,CAAc,SAAS,CAAC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAC7E,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIK,SAAS,CAAC,CAAA;AAC1C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,OAAA,GAAU,OAMN,IAAI,CAAA;AAEd,EAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,IAAA,MAAM,IAAI,OAAA,CAAQ,OAAA;AAClB,IAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAClB,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,aAAA,CAAc,EAAE,KAAK,CAAA;AACrB,IAAA,KAAK,EAAE,GAAA,CAAI,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,EAC1C,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM,IAAA,EAAM,CAAC,IAAI,CAAC,CAAA;AAE5B,EAAA,MAAM,IAAA,GAAO,WAAA;AAAA,IACX,OAAO,MAAA,KAAmB;AACxB,MAAA,IAAA,EAAK;AACL,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAC1B,MAAA,MAAM,GAAA,GAAM,IAAI,YAAA,EAAa;AAC7B,MAAA,MAAM,CAAA,GAAI;AAAA,QACR,GAAA;AAAA,QACA,QAAA,EAAU,IAAI,WAAA,GAAc,IAAA;AAAA,QAC5B,MAAA,EAAQ,MAAA;AAAA,QACR,SAAA,sBAAe,GAAA,EAAY;AAAA,QAC3B,KAAA,EAAO;AAAA,OACT;AACA,MAAA,MAAM,QAAA,GAAW,OAAO,IAAA,KAAuB;AAC7C,QAAA,MAAM,KAAA,GAAA,CAAS,MAAA,CAAO,SAAA,CAAU,MAAA,IAAU,EAAC,EAAG,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,IAAA,CAAK,UAAU,CAAA;AAC3F,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,KAAK,UAAU,CAAA;AAC3C,QAAA,MAAM,GAAA,GAAM,OAAO,KAAA,EAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,KAAQ,IAAA,CAAK,GAAG,CAAA;AACxD,QAAA,IAAI,CAAC,KAAA,IAAS,CAAC,GAAA,IAAO,CAAC,GAAA,EAAK;AAC5B,QAAA,IAAI;AACF,UAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,IAAA,EAAM,KAAK,GAAG,CAAA;AAC5C,UAAA,MAAM,SAAS,MAAM,GAAA,CAAI,gBAAgB,UAAA,CAAW,KAAK,EAAE,MAAM,CAAA;AACjE,UAAA,IAAI,OAAA,CAAQ,YAAY,CAAA,EAAG;AAC3B,UAAA,MAAM,KAAK,YAAA,CAAa;AAAA,YACtB,cAAc,IAAA,CAAK,QAAA;AAAA,YACnB,iBAAiB,MAAA,CAAO,QAAA;AAAA,YACxB,UAAU,CAAA,CAAE,QAAA;AAAA,YACZ,QAAQ,CAAA,CAAE,MAAA;AAAA,YACV,QAAQ,GAAA,CAAI;AAAA,WACb,CAAA;AACD,UAAA,IAAI,CAAC,EAAA,EAAI;AACT,UAAA,MAAM,MAAA,GAAS,IAAI,kBAAA,EAAmB;AACtC,UAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,UAAA,MAAA,CAAO,OAAA,CAAQ,IAAI,WAAW,CAAA;AAC9B,UAAA,MAAA,CAAO,KAAA,CAAM,EAAA,CAAG,IAAA,EAAM,EAAA,CAAG,MAAM,CAAA;AAAA,QACjC,SAAS,GAAA,EAAK;AACZ,UAAA,OAAA,CAAQ,IAAA,CAAK,0CAA0C,GAAG,CAAA;AAAA,QAC5D;AAAA,MACF,CAAA;AACA,MAAA,MAAM,OAAO,MAAM;AACjB,QAAA,IAAI,OAAA,CAAQ,YAAY,CAAA,EAAG;AAC3B,QAAA,MAAM,OAAO,UAAA,CAAW,GAAA,CAAI,aAAa,CAAA,CAAE,QAAA,EAAU,EAAE,MAAM,CAAA;AAC7D,QAAA,WAAA,CAAY,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,UAAU,CAAC,CAAA;AACtC,QAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,UAAA,IAAA,EAAK;AACL,UAAA,UAAA,CAAW,KAAK,CAAA;AAChB,UAAA;AAAA,QACF;AACA,QAAA,KAAA,MAAW,QAAQ,QAAA,CAAS,KAAA,EAAO,MAAM,qBAAA,EAAuB,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5E,UAAA,CAAA,CAAE,SAAA,CAAU,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAC,CAAA;AAC7B,UAAA,KAAK,SAAS,IAAI,CAAA;AAAA,QACpB;AAAA,MACF,CAAA;AACA,MAAA,CAAA,CAAE,KAAA,GAAQ,WAAA,CAAY,IAAA,EAAM,GAAG,CAAA;AAC/B,MAAA,OAAA,CAAQ,OAAA,GAAU,CAAA;AAClB,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,IACA,CAAC,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,YAAY,IAAI;AAAA,GACtC;AAEA,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,IAAA,EAAK;AACL,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAA,MAAO;AACL,MAAA,KAAK,IAAA,CAAK,YAAY,UAAA,GAAa,CAAA,GAAI,QAAQ,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvE,QAAA,UAAA,CAAW,KAAK,CAAA;AAChB,QAAA,MAAA,CAAQ,GAAA,CAAc,SAAS,OAAO,CAAA;AAAA,MACxC,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AAEA,EAAA,uBACEF,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACb,QAAA,EAAA;AAAA,oBAAAF,GAAAA;AAAA,MAACK,MAAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,OAAA,EAAQ,SAAA;AAAA,QACR,SAAA,EAAU,QAAA;AAAA,QACV,YAAA,EAAY,UAAU,OAAA,GAAU,MAAA;AAAA,QAChC,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAY,sBAAA;AAAA,QAEX,QAAA,EAAA,OAAA,mBAAUL,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,UAAA,EAAW,CAAA,mBAAKA,GAAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAW;AAAA;AAAA,KACzE;AAAA,oBACAA,GAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,OAAA;AAAA,QACL,GAAA,EAAK,CAAA;AAAA,QACL,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,UAAU,CAAA;AAAA,QAC3B,IAAA,EAAM,GAAA;AAAA,QACN,KAAA,EAAO,QAAA;AAAA,QACP,SAAA,EAAU,QAAA;AAAA,QACV,YAAA,EAAW,UAAA;AAAA,QACX,QAAA,EAAU,CAAC,CAAA,KAAM;AACf,UAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AAChC,UAAA,WAAA,CAAY,EAAE,CAAA;AACd,UAAA,IAAI,OAAA,EAAS;AACX,YAAA,KAAK,IAAA,CAAK,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,QAAiB,MAAA,CAAQ,GAAA,CAAc,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,UAC/E;AAAA,QACF;AAAA;AAAA,KACF;AAAA,oBACAE,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAA,EACb,QAAA,EAAA;AAAA,MAAA,GAAA,CAAI,QAAQ,CAAA;AAAA,MAAE,KAAA;AAAA,MAAI,IAAI,UAAU;AAAA,KAAA,EACnC;AAAA,GAAA,EACF,CAAA;AAEJ;AChvBA,SAAS,SAAA,CAAU,QAAkB,IAAA,EAAsC;AACzE,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AAC7B,EAAA,OAAO,MAAM,MAAA,GAAS,CAAA,GAClB,GAAG,KAAA,CAAM,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,KAAK,IAAI,CAAC,KAAK,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,CAAA,GACpD,KAAA,CAAM,KAAK,IAAI,CAAA;AACrB;AAEO,SAAS,iBAAA,CAAkB;AAAA,EAChC,MAAA;AAAA,EACA,IAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA,EAOiB;AACf,EAAA,MAAM,OAAOK,OAAAA,EAAQ;AACrB,EAAA,MAAM,sBAAsB,sBAAA,EAAuB;AACnD,EAAA,MAAM,IAAA,GAAO,CAAC,MAAA,CAAO,QAAA;AACrB,EAAA,MAAM,UAAA,GAAa,eAAe,CAAC,CAAA,KAAM,EAAE,MAAA,EAAQ,SAAA,KAAc,OAAO,WAAW,CAAA;AACnF,EAAA,MAAM,aAAA,GAAgB,cAAA;AAAA,IACpB,CAAC,MAAM,CAAC,CAAC,EAAE,MAAA,IAAU,CAAA,CAAE,MAAA,CAAO,SAAA,KAAc,MAAA,CAAO;AAAA,GACrD;AAEA,EAAA,MAAM,EAAE,MAAM,IAAA,EAAK,GAAIC,QAAQ,IAAA,GAAO,MAAA,CAAO,cAAc,IAAI,CAAA;AAC/D,EAAA,MAAM,cAAc,IAAA,IAAQ,CAAC,CAAC,IAAA,IAAQ,CAAC,IAAA,CAAK,aAAA;AAC5C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIJ,SAAS,KAAK,CAAA;AAEtC,EAAA,MAAM,UAAU,IAAA,GACZ;AAAA,IACE,OAAO,UAAA,GAAa,CAAA,gBAAA,EAAmB,KAAK,MAAA,CAAO,UAAU,CAAC,CAAA,CAAA,GAAK,cAAA;AAAA,IACnE,MAAA,CAAO,QAAQ,MAAA,GAAS,CAAA,QAAA,EAAW,UAAU,MAAA,CAAO,OAAA,EAAS,IAAI,CAAC,CAAA,CAAA,GAAK;AAAA,GACzE,GACA;AAAA,IACE,MAAA;AAAA,IACA,kBAAA,CAAmB,OAAO,UAAU,CAAA;AAAA,IACpC,MAAA,CAAO,OAAO,MAAA,GAAS,CAAA,OAAA,EAAU,UAAU,MAAA,CAAO,MAAA,EAAQ,IAAI,CAAC,CAAA,CAAA,GAAK;AAAA,GACtE;AAEJ,EAAA,uBACEF,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,0IAAA;AAAA,MACV,aAAA,EAAY,sBAAA;AAAA,MACZ,aAAW,IAAA,IAAQ,MAAA;AAAA,MAElB,QAAA,EAAA;AAAA,QAAA,IAAA,mBACCF,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,wCAAuC,aAAA,EAAW,IAAA,EAAC,CAAA,mBAEpEA,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,8BAAA,EAA+B,eAAW,IAAA,EAAC,CAAA;AAAA,wBAEjEA,GAAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,yBAAA,EAA2B,QAAA,EAAA,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,QAAK,CAAA,EAAE,CAAA;AAAA,QAChF,wBAAQA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAyB,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,QACtD,uBACCA,GAAAA;AAAA,UAACK,MAAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,IAAA;AAAA,YACL,SAAA,EAAU,gDAAA;AAAA,YACV,QAAA,EAAU,IAAA,IAAQ,UAAA,IAAc,aAAA,IAAiB,WAAA;AAAA,YACjD,KAAA,EACE,WAAA,GACI,8CAAA,GACA,aAAA,GACE,2BAAA,GACA,MAAA;AAAA,YAER,SAAS,MAAM;AACb,cAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,cAAA,KAAK,QAAA,CAAS,IAAA,EAAM,EAAE,SAAA,EAAW,MAAA,CAAO,WAAA,EAAa,CAAA,CAAE,OAAA,CAAQ,MAAM,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,YACrF,CAAA;AAAA,YACA,aAAA,EAAY,sBAAA;AAAA,YAEX,uBAAa,SAAA,GAAY;AAAA;AAAA,4BAG5BH,IAAAA;AAAA,UAACG,MAAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,IAAA;AAAA,YACL,OAAA,EAAQ,SAAA;AAAA,YACR,SAAA,EAAU,KAAA;AAAA,YACV,OAAA,EAAS,MACP,KAAK,mBAAA,CAAoB;AAAA,cACvB,WAAW,MAAA,CAAO,WAAA;AAAA,cAClB,0BAA0B,MAAA,CAAO,2BAAA;AAAA,cACjC;AAAA,aACD,CAAA;AAAA,YAEH,aAAA,EAAY,2BAAA;AAAA,YAEZ,QAAA,EAAA;AAAA,8BAAAL,GAAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EAAU,eAAA,EAAgB,eAAW,IAAA,EAAC,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA;AAEzD;AAAA;AAAA,GAEJ;AAEJ;ACxGA,SAAS,WAAW,GAAA,EAAwC;AAC1D,EAAA,IAAI,CAAC,KAAK,OAAO,EAAA;AACjB,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACzB,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,EAAG,OAAO,EAAA;AAC7B,EAAA,OAAO,IAAI,IAAA,CAAK,EAAE,CAAA,CAAE,kBAAA,CAAmB,EAAC,EAAG,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAW,CAAA;AACnF;AAEO,SAAS,eAAA,CAAgB;AAAA,EAC9B,SAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ;AACF,CAAA,EAWiB;AACf,EAAA,uBACEA,GAAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,WAAA;AAAA,MACA,yBAASA,GAAAA,CAAC,gBAAa,QAAA,EAAU,SAAA,EAAW,MAAM,WAAA,EAAa,CAAA;AAAA,MAC/D,IAAA,EAAM,WAAW,EAAE,CAAA;AAAA,MACnB,IAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA;AAAA,GACF;AAEJ;ACxCO,SAAS,iBAAA,CAAkB,UAAkB,YAAA,EAAsC;AACxF,EAAA,MAAM,OAAOO,OAAAA,EAAQ;AACrB,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,SAAA,EAAU;AAC3B,EAAA,MAAM,KAAK,IAAA,CAAK,UAAA,IAAc,KAAK,IAAA,CAAK,QAAA,IAAY,UAAA,KAAe,QAAA;AACnE,EAAA,MAAM,OAAA,GAAU,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,SAAQ,GAAI,IAAA;AAC3C,EAAA,OAAOR,QAAQ,MAAM;AACnB,IAAA,IAAI,OAAA;AACF,MAAA,OAAO,kBAAA,CAAmB,EAAE,UAAA,EAAY,OAAA,CAAQ,WAAW,WAAA,EAAa,OAAA,CAAQ,YAAY,CAAA;AAC9F,IAAA,MAAM,IAAA,GAAO,KAAK,QAAQ,CAAA;AAC1B,IAAA,IAAI,IAAA,EAAM,OAAO,kBAAA,CAAmB,IAAI,CAAA;AACxC,IAAA,OAAA,CAAQ,YAAA,IAAgB,UAAU,IAAA,EAAK,CAAE,MAAM,KAAK,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,EAChE,GAAG,CAAC,OAAA,EAAS,IAAA,EAAM,QAAA,EAAU,YAAY,CAAC,CAAA;AAC5C;ACHO,SAAS,qBAAA,CAAsB,EAAE,SAAA,EAAU,EAAwC;AACxF,EAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAa,GAAI,gBAAgB,SAAS,CAAA;AAC1D,EAAA,MAAM,IAAA,GAAOU,cAAAA,CAAe,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA,CAAE,SAAA,CAAU,SAAS,CAAC,CAAA,IAAK,MAAA;AAChE,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,uBACET,GAAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,UAAA;AAAA,QACN,KAAA,EAAM,eAAA;AAAA,QACN,WAAA,EAAY,+GAAA;AAAA,QACZ,SAAA,EAAU,uBAAA;AAAA,QACV,MAAA,EAAO;AAAA;AAAA,KACT;AAAA,EAEJ;AACA,EAAA,uBACEA,GAAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,eAAeU,QAAAA,GAAW,WAAA;AAAA,MAChC,KAAA,EAAM,yDAAA;AAAA,MACN,WAAA,EACE,eACI,mEAAA,GACA,oEAAA;AAAA,MAEN,SAAA,EAAU,uBAAA;AAAA,MACV,MAAA,EAAO;AAAA;AAAA,GACT;AAEJ;AAEA,SAAS,cAAA,CAAe,EAAE,QAAA,EAAS,EAAuC;AACxE,EAAA,MAAM,IAAA,GAAO,kBAAkB,QAAQ,CAAA;AACvC,EAAA,uBACEV,GAAAA;AAAA,IAAC,yBAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,QAAA;AAAA,MACX,WAAA,EAAa,IAAA;AAAA,MACb,OAAA,kBAASA,GAAAA,CAAC,YAAA,EAAA,EAAa,QAAA,EAAoB;AAAA;AAAA,GAC7C;AAEJ;AAGO,SAAS,mBAAA,CAAoB,EAAE,GAAA,EAAI,EAA2C;AACnF,EAAA,IAAI,CAAC,GAAA,CAAI,MAAA,EAAQ,OAAO,IAAA;AACxB,EAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,MAAA,EAAO,aAAA,EAAY,+BAC/B,QAAA,EAAA,GAAA,CAAI,GAAA,CAAI,CAAC,EAAA,qBACRA,GAAAA,CAAC,cAAA,EAAA,EAAwB,UAAU,EAAA,EAAA,EAAd,EAAkB,CACxC,CAAA,EACH,CAAA;AAEJ;ACrDA,IAAM,YAAA,GAAe,GAAA;AAErB,IAAM,aAAA,GAAgB,GAAA;AAMf,SAAS,sBAAA,CACd,WACA,KAAA,EACU;AACV,EAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAa,GAAI,gBAAgB,SAAS,CAAA;AAC1D,EAAA,MAAM,WAAW,cAAA,EAAe;AAChC,EAAA,MAAM,OAAA,GAAUW,MAAAA,iBAAO,IAAI,GAAA,EAAsB,CAAA;AACjD,EAAA,MAAM,GAAG,IAAI,CAAA,GAAIP,SAAS,CAAC,CAAA;AAC3B,EAAA,MAAM,SAAS,MAAA,IAAU,YAAA;AACzB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,KAAA,MAAW,MAAM,QAAA,EAAU;AACzB,MAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAChC,MAAA,IAAI,CAAA,IAAK,WAAA,GAAc,GAAA;AAAA,WAClB,OAAA,CAAQ,QAAQ,GAAA,CAAI,EAAA,EAAI,EAAE,SAAA,EAAW,GAAA,EAAK,WAAA,EAAa,GAAA,EAAK,CAAA;AAAA,IACnE;AAAA,EACF,CAAA,MAAA,IAAW,OAAA,CAAQ,OAAA,CAAQ,IAAA,EAAM;AAC/B,IAAA,OAAA,CAAQ,QAAQ,KAAA,EAAM;AAAA,EACxB;AAEA,EAAA,MAAM,MAAA,GAASL,QAAQ,MAAM;AAC3B,IAAA,MAAM,CAAA,uBAAQ,GAAA,EAAoB;AAClC,IAAA,KAAA,MAAW,KAAK,KAAA,EAAO,CAAA,CAAE,GAAA,CAAI,CAAA,CAAE,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,GAAA,CAAI,EAAE,SAAS,CAAA,IAAK,CAAA,EAAG,CAAA,CAAE,EAAE,CAAC,CAAA;AACjF,IAAA,OAAO,CAAA;AAAA,EACT,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACV,EAAA,KAAA,MAAW,CAAC,IAAI,CAAC,CAAA,IAAK,CAAC,GAAG,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1C,IAAA,MAAM,WAAW,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,IAAK,CAAA,KAAM,EAAE,SAAA,GAAY,GAAA;AACvD,IAAA,MAAM,KAAA,GAAQ,CAAC,QAAA,CAAS,QAAA,CAAS,EAAE,CAAA,IAAK,GAAA,GAAM,EAAE,WAAA,GAAc,YAAA;AAC9D,IAAA,IAAK,OAAA,IAAW,CAAC,QAAA,CAAS,QAAA,CAAS,EAAE,KAAM,KAAA,EAAO,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAA;AAAA,SAAA,IAClE,OAAA,IAAW,SAAA,GAAY,GAAA;AAAA,EAClC;AAEA,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,IAAA,GAAO,CAAA;AACvC,EAAAa,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,EAAA,GAAK,YAAY,MAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,EAAG,GAAI,CAAA;AACrD,IAAA,OAAO,MAAM,cAAc,EAAE,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AACZ,EAAA,OAAO,CAAC,GAAG,OAAA,CAAQ,OAAO,EACvB,MAAA,CAAO,CAAC,GAAG,CAAC,CAAA,KAAM,EAAE,WAAA,GAAc,CAAA,CAAE,aAAa,aAAa,CAAA,CAC9D,IAAI,CAAC,CAAC,EAAE,CAAA,KAAM,EAAE,CAAA;AACrB;AC/CA,IAAM,KAAA,GAA2B,EAAE,SAAA,kBAAW,IAAI,KAAI,EAAG,MAAA,kBAAQ,IAAI,GAAA,EAAI,EAAE;AAEpE,IAAM,qBAAA,GAAwB,cAAiC,KAAK;AAEpE,SAAS,iBAAA,GAAuC;AACrD,EAAA,OAAO,WAAW,qBAAqB,CAAA;AACzC;AAUO,SAAS,qBAAqB,QAAA,EAAkD;AACrF,EAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAyB,mBAAA,CAAoB,EAAE,KAAA,IAAS,CAAA,CAAE,MAAM,KAAK,CAAA;AACxF,EAAA,MAAM,cAAA,GAAiB,cAAA;AAAA,IACrB,QAAA;AAAA,IACA,CAAC,CAAA,KAAM,SAAA,CAAU,CAAC,GAAG,cAAA,IAAkB,IAAA;AAAA,IACvC,CAAC,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,EAAG,UAAA,IAAc,CAAA,CAAE,UAAA,IAAc,EAAE,CAAA,IAAK;AAAA,GACvE;AACA,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAoB;AACvC,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,MAAM,GAAA,GAAM,UAAU,CAAC,CAAA;AACvB,IAAA,IAAI,GAAA,IAAO,EAAE,WAAA,EAAa,MAAA,CAAO,IAAI,GAAA,CAAI,cAAA,EAAgB,EAAE,WAAW,CAAA;AAAA,EACxE;AACA,EAAA,OAAO;AAAA,IACL,WAAW,IAAI,GAAA;AAAA,MACb,CAAC,GAAG,cAAc,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,EAAE,MAAA,CAAO,CAAC,EAAA,KAAqB,CAAC,CAAC,EAAE;AAAA,KACjF;AAAA,IACA,MAAA,EAAQ,IAAI,GAAA,CAAI,MAAA,CAAO,QAAQ;AAAA,GACjC;AACF","file":"chunk-24H5WTGM.js","sourcesContent":["/**\n * A conversation's messages as its thread shows them: in a call's meeting thread, a recording's\n * transcript supersedes the live lines spoken while it recorded (else both would show).\n */\nimport { useMemo } from 'react'\nimport {\n hasRecordingTranscript,\n supersedeLiveTranscript,\n threadTranscriptRef,\n useRecordingWindows,\n} from '@arbidocs/react'\nimport type { ChatMessage } from '@arbidocs/sdk/browser'\n\nexport function useMeetingThreadMessages(\n meetingCallExtId: string | null,\n messageHistory: ChatMessage[]\n): ChatMessage[] {\n const hasRecTranscript = useMemo(\n () => !!meetingCallExtId && hasRecordingTranscript(messageHistory, threadTranscriptRef),\n [meetingCallExtId, messageHistory]\n )\n const recordingWindows = useRecordingWindows(meetingCallExtId, hasRecTranscript)\n return useMemo(\n () =>\n hasRecTranscript\n ? supersedeLiveTranscript(messageHistory, threadTranscriptRef, recordingWindows)\n : messageHistory,\n [hasRecTranscript, messageHistory, recordingWindows]\n )\n}\n","/**\n * Host action \"Save transcript to thread\": the meeting chat's transcript is decrypted here, in the\n * host's browser, and posted as ONE attributed transcript comment (title, date, then\n * `Speaker [hh:mm:ss]: text` lines) into a workspace thread the host picks — a shared thread of the\n * current workspace they can post in, or a new one. The thread is encrypted with the workspace key\n * like any comment; the meeting chat itself is unchanged and nobody outside it gains access to it.\n */\n\nimport { useSaveToThread, useWorkspaces, type TranscriptExportLine } from '@arbidocs/react'\nimport { useMemo, useState, type ReactElement, type ReactNode } from 'react'\nimport { FileText } from 'lucide-react'\nimport {\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@arbidocs/react/ui'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../../connection/ConnectionProvider'\nimport { useConnectedConversations } from '../../connection/workspaceData'\nimport { HeaderAction } from '../HeaderAction'\n\nconst NEW_THREAD = '__new__'\n\n/** The open workspace and my role in it (the threads I can post in are its shared ones). */\nfunction useCurrentWorkspace() {\n const { workspaceId, userId } = useConnectedWorkspace()\n const { data: workspaces } = useWorkspaces()\n const workspace = workspaces?.find((w) => w.external_id === workspaceId)\n const role = workspace?.users?.find((wu) => wu.user.external_id === userId)?.role ?? null\n return { workspace, role }\n}\n\nexport function SaveTranscriptToThread({\n title,\n lines,\n excludeConversationExtId,\n iconOnly = false,\n className,\n}: {\n /** The meeting's title (decrypted). */\n title: string | null | undefined\n lines: TranscriptExportLine[]\n /** Not offered as a target (the meeting thread itself). */\n excludeConversationExtId?: string | null\n /** Icon only, the label in a tooltip (a crowded header). */\n iconOnly?: boolean\n className?: string\n}): ReactElement | null {\n const [open, setOpen] = useState(false)\n if (!lines.length) return null\n return (\n <>\n <HeaderAction\n label=\"Save transcript to thread\"\n icon={<FileText className=\"size-3.5\" aria-hidden />}\n iconOnly={iconOnly}\n className={className}\n onClick={() => setOpen(true)}\n testId=\"save-transcript-to-thread\"\n />\n {open && (\n <SaveTranscriptDialog\n title={title}\n lines={lines}\n excludeConversationExtId={excludeConversationExtId ?? null}\n onClose={() => setOpen(false)}\n />\n )}\n </>\n )\n}\n\nfunction SaveTranscriptDialog({\n title,\n lines,\n excludeConversationExtId,\n onClose,\n}: {\n title: string | null | undefined\n lines: TranscriptExportLine[]\n excludeConversationExtId: string | null\n onClose(): void\n}): ReactElement {\n const { notify } = useBlocksEnvironment()\n const save = useSaveToThread()\n const { workspace } = useCurrentWorkspace()\n return (\n <PickThreadDialog\n heading=\"Save transcript to thread\"\n description={\n <>\n The transcript ({lines.length} {lines.length === 1 ? 'line' : 'lines'}) is posted as one\n comment in a thread of {workspace?.name ?? 'the current workspace'}. Only that thread’s\n members can read it there.\n </>\n }\n testIdPrefix=\"save-transcript\"\n excludeConversationExtId={excludeConversationExtId}\n onClose={onClose}\n onConfirm={async (target) => {\n await save.transcript({ conversationExtId: target, title, lines })\n notify('Transcript saved to the thread', 'success')\n }}\n />\n )\n}\n\n/**\n * Pick a shared thread of the current workspace I can post in (or a new one) and act on it: the\n * dialog behind \"Save transcript to thread\" and the recording's \"Save to thread\".\n */\nexport function PickThreadDialog({\n heading,\n description,\n testIdPrefix,\n excludeConversationExtId,\n confirmLabel = 'Save',\n busyLabel = 'Saving…',\n onConfirm,\n onClose,\n}: {\n heading: string\n description: ReactNode\n /** `<prefix>-dialog`, `<prefix>-target-<id>`, `<prefix>-confirm`. */\n testIdPrefix: string\n excludeConversationExtId?: string | null\n confirmLabel?: string\n busyLabel?: string\n /** `target` null: a new thread. Throwing keeps the dialog open and shows the error. */\n onConfirm(target: string | null): Promise<unknown>\n onClose(): void\n}): ReactElement {\n const { notify } = useBlocksEnvironment()\n const { role } = useCurrentWorkspace()\n const { data: conversations } = useConnectedConversations()\n const canPost = role === 'owner' || role === 'collaborator'\n const threads = useMemo(\n () =>\n canPost\n ? conversations\n .filter((c) => c.is_shared && c.external_id !== excludeConversationExtId)\n .sort((a, b) => Date.parse(b.updated_at) - Date.parse(a.updated_at))\n : [],\n [conversations, canPost, excludeConversationExtId]\n )\n const [target, setTarget] = useState<string>(NEW_THREAD)\n const [busy, setBusy] = useState(false)\n\n const save = async () => {\n setBusy(true)\n try {\n await onConfirm(target === NEW_THREAD ? null : target)\n onClose()\n } catch (err) {\n notify((err as Error).message, 'error')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Dialog open onOpenChange={(o) => !o && !busy && onClose()}>\n <DialogContent className=\"sm:max-w-md\" data-testid={`${testIdPrefix}-dialog`}>\n <DialogHeader>\n <DialogTitle>{heading}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n {!canPost ? (\n <p className=\"text-sm text-muted-foreground\">\n Open a workspace you can post in to save here.\n </p>\n ) : (\n <ul className=\"flex max-h-72 flex-col gap-1 overflow-y-auto\" role=\"radiogroup\">\n {[{ external_id: NEW_THREAD, title: 'New thread' }, ...threads].map((t) => (\n <li key={t.external_id}>\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={target === t.external_id}\n className={cn(\n 'w-full truncate rounded-md px-2 py-1.5 text-left text-sm hover:bg-muted',\n target === t.external_id && 'bg-muted font-medium'\n )}\n onClick={() => setTarget(t.external_id)}\n data-testid={`${testIdPrefix}-target-${t.external_id}`}\n >\n {t.title || 'Untitled thread'}\n </button>\n </li>\n ))}\n </ul>\n )}\n <DialogFooter>\n <Button variant=\"ghost\" onClick={onClose} disabled={busy}>\n Cancel\n </Button>\n <Button\n onClick={() => void save()}\n disabled={busy || !canPost}\n data-testid={`${testIdPrefix}-confirm`}\n >\n {busy ? busyLabel : confirmLabel}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n","/**\n * The Recording card of a call (ARBI `docs/meeting-chats-plan.md` §6): a `kind = recording` chat\n * message in an E2E meeting chat, a `recording` activity event in a workspace meeting thread, and\n * each entry of a meeting chat's \"Recordings\" list.\n *\n * Everything that touches media happens in this browser: parts are downloaded as ciphertext and\n * decrypted with the track keys (unwrapped under the meeting chat's / workspace's key). Members of\n * the meeting chat can play, download and copy an in-app link; the host can also transcribe, delete\n * the media (keeping the transcript), set an expiry, save the files to a thread, or delete it.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactElement } from 'react'\nimport {\n Captions,\n Download,\n FileUp,\n Link2,\n Loader2,\n Mic,\n Pause,\n Play,\n Trash2,\n Video,\n} from 'lucide-react'\nimport { Button, cn } from '@arbidocs/react/ui'\nimport { downloadBlob } from '@arbidocs/react/document-tools'\nimport {\n useArbi,\n useCallRecording,\n useCallRecordings,\n useCall,\n useRecordingActions,\n useSaveToThread,\n meetingChatRefFrom,\n compositeFiles,\n compositeTrack,\n fetchPart,\n recordingFiles,\n speakerTracks,\n type OpenedRecording,\n PLAYBACK_LOOKAHEAD_MS,\n partKey,\n partsDue,\n playheadAt,\n schedulePart,\n standalone,\n timelineDurationMs,\n timelineOf,\n type TimelinePart,\n} from '@arbidocs/react'\nimport type { calls } from '@arbidocs/sdk/browser'\nimport { useBlocksEnvironment } from '../../provider/environment'\nimport { useConnectedWorkspace } from '../../connection/ConnectionProvider'\nimport { recordingLink, setPendingRecording, usePendingRecording } from '../recording-link'\nimport { formatCallDuration } from '../call-cards'\nimport { EXPIRY_DAYS, MODE_LABEL, expiryChoiceOf, expiryFor } from '../recording-labels'\nimport { PickThreadDialog } from './SaveTranscriptToThread'\nimport { CallUserPill } from './CallUserPill'\n\n/** A card for one recording (by id), or for each of the call's recordings when no id is known. */\nexport function RecordingCard({\n callExtId,\n recordingExtId,\n title,\n time,\n}: {\n callExtId: string\n recordingExtId?: string | null\n /** The meeting's title (decrypted), for file names. */\n title?: string | null\n time?: string\n}): ReactElement | null {\n const { data: call } = useCall(callExtId)\n const one = useCallRecording(callExtId, recordingExtId)\n const all = useCallRecordings(callExtId, !recordingExtId)\n if (!call) return null\n if (recordingExtId) {\n if (one.isError) return <RecordingUnavailable />\n return one.data ? (\n <RecordingCardBody call={call} recording={one.data} title={title} time={time} />\n ) : null\n }\n return (\n <>\n {(all.data ?? []).map((r) => (\n <RecordingCardBody\n key={r.external_id}\n call={call}\n recording={r}\n title={title}\n time={time}\n />\n ))}\n </>\n )\n}\n\n/** All of a call's recordings (the meeting chat's \"Recordings\" view), newest first. */\nexport function RecordingsList({\n callExtId,\n title,\n className,\n}: {\n callExtId: string\n title?: string | null\n className?: string\n}): ReactElement {\n const { data: call } = useCall(callExtId)\n const { data, isLoading, isError } = useCallRecordings(callExtId)\n const sorted = useMemo(\n () => [...(data ?? [])].sort((a, b) => Date.parse(b.started_at) - Date.parse(a.started_at)),\n [data]\n )\n return (\n <div className={cn('flex flex-col gap-2', className)} data-testid=\"recordings-list\">\n {isLoading && <Loader2 className=\"mx-auto size-4 animate-spin text-muted-foreground\" />}\n {isError && (\n <p className=\"text-center text-xs text-muted-foreground\">Could not load the recordings.</p>\n )}\n {!isLoading && !isError && !sorted.length && (\n <p className=\"text-center text-xs text-muted-foreground\">No recordings yet.</p>\n )}\n {call &&\n sorted.map((r) => (\n <RecordingCardBody key={r.external_id} call={call} recording={r} title={title} />\n ))}\n </div>\n )\n}\n\nfunction RecordingUnavailable(): ReactElement {\n return (\n <div\n className=\"mx-auto my-1 w-fit rounded-md border border-border bg-card px-3 py-2 text-xs text-muted-foreground\"\n data-testid=\"recording-card\"\n >\n Recording unavailable\n </div>\n )\n}\n\n/** A two-step destructive button: the first click asks, the second does. */\nfunction ConfirmButton({\n label,\n confirmLabel,\n testId,\n disabled,\n onConfirm,\n icon,\n}: {\n label: string\n confirmLabel: string\n testId: string\n disabled?: boolean\n onConfirm(): Promise<void>\n icon: ReactElement\n}): ReactElement {\n const [asking, setAsking] = useState(false)\n const [busy, setBusy] = useState(false)\n useEffect(() => {\n if (!asking) return\n const t = setTimeout(() => setAsking(false), 5000)\n return () => clearTimeout(t)\n }, [asking])\n return (\n <Button\n type=\"button\"\n size=\"sm\"\n variant={asking ? 'destructive' : 'outline'}\n className=\"h-7\"\n disabled={disabled || busy}\n onClick={() => {\n if (!asking) {\n setAsking(true)\n return\n }\n setAsking(false)\n setBusy(true)\n void onConfirm().finally(() => setBusy(false))\n }}\n data-testid={asking ? `${testId}-confirm` : testId}\n >\n {busy ? <Loader2 className=\"mr-1 size-3.5 animate-spin\" aria-hidden /> : icon}\n {asking ? confirmLabel : label}\n </Button>\n )\n}\n\nfunction RecordingCardBody({\n call,\n recording,\n title,\n time,\n}: {\n call: calls.CallResponse\n recording: calls.CallRecording\n title?: string | null\n time?: string\n}): ReactElement {\n const arbi = useArbi()\n const actions = useRecordingActions(call)\n const save = useSaveToThread()\n const { notify, runtimeConfig } = useBlocksEnvironment()\n const isHost = call.is_creator\n const mediaDeleted = !!recording.media_deleted_at\n const live = recording.state === 'recording' || (!recording.stopped_at && !mediaDeleted)\n const speakers = speakerTracks(recording)\n const timeline = useMemo(() => timelineOf(recording.tracks ?? []), [recording.tracks])\n const durationMs = timelineDurationMs(timeline)\n const hasMedia = !mediaDeleted && timeline.length > 0\n const [opened, setOpened] = useState<OpenedRecording | null>(null)\n const [playing, setPlaying] = useState(false)\n const [progress, setProgress] = useState<string | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const { workspaceId: selectedWorkspaceId } = useConnectedWorkspace()\n\n // A link asked to show this recording: bring it into view.\n const pending = usePendingRecording()\n const highlighted = pending === recording.external_id\n const cardRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n if (!highlighted) return\n cardRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n const t = setTimeout(() => setPendingRecording(null), 4000)\n return () => clearTimeout(t)\n }, [highlighted])\n\n const { refresh } = actions\n\n const open = useCallback(async (): Promise<OpenedRecording> => {\n if (opened && opened.recording === recording) return opened\n const next = await actions.open(recording)\n setOpened(next)\n return next\n }, [actions, opened, recording])\n\n const run = async (label: string, task: () => Promise<void>) => {\n setProgress(label)\n try {\n await task()\n } catch (err) {\n console.warn('[calls] recording action failed', err)\n notify((err as Error).message, 'error')\n } finally {\n setProgress(null)\n }\n }\n\n const download = () =>\n run('Decrypting…', async () => {\n const files = await recordingFiles(arbi, await open(), title, (done, total) =>\n setProgress(`Decrypting ${done}/${total}…`)\n )\n if (!files.length) throw new Error('Nothing to download')\n for (const f of files) downloadBlob(f, f.name)\n })\n\n const transcribe = () =>\n run('Transcribing…', async () => {\n const { stored, failed } = await actions.transcribe(await open(), (done, total) =>\n setProgress(`Transcribing ${done}/${total}…`)\n )\n notify(\n failed\n ? `Transcribed ${stored} lines; ${failed} parts failed`\n : `Transcribed ${stored} lines into the meeting chat`,\n failed ? 'warning' : 'success'\n )\n })\n\n const copyLink = async () => {\n const ref = meetingChatRefFrom(call)\n if (!ref) {\n notify('This recording has no meeting chat to link to', 'error')\n return\n }\n try {\n await navigator.clipboard.writeText(\n recordingLink(ref, recording.external_id, runtimeConfig.deploymentDomain)\n )\n notify('Link copied: it opens for members of the meeting chat', 'success')\n } catch {\n notify('Could not copy the link', 'error')\n }\n }\n\n const saveToThread = async (target: string | null) => {\n if (!selectedWorkspaceId) throw new Error('Open a workspace first')\n const files = await recordingFiles(arbi, await open(), title, (done, total) =>\n setProgress(`Decrypting ${done}/${total}…`)\n )\n if (!files.length) throw new Error('Nothing to save')\n // Re-encrypted under the workspace key, as a direct document upload.\n try {\n await save.recording({\n workspaceExtId: selectedWorkspaceId,\n files,\n conversationExtId: target,\n title,\n onUploading: () => setProgress('Uploading…'),\n })\n } finally {\n setProgress(null)\n }\n notify('Recording saved to the thread', 'success')\n }\n\n const summary = [\n 'Recording',\n MODE_LABEL[recording.mode],\n formatCallDuration(durationMs / 1000),\n speakers.length ? `${speakers.length} ${speakers.length === 1 ? 'speaker' : 'speakers'}` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n\n return (\n <div\n ref={cardRef}\n className={cn(\n 'mx-auto my-1 flex w-full max-w-xl flex-col gap-2 rounded-md border border-border bg-card px-3 py-2 text-xs',\n highlighted && 'ring-2 ring-primary'\n )}\n data-testid=\"recording-card\"\n data-recording={recording.external_id}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n {recording.mode === 'audio_video' ? (\n <Video className=\"size-4 text-red-500\" aria-hidden />\n ) : (\n <Mic className=\"size-4 text-red-500\" aria-hidden />\n )}\n <span className=\"font-medium\" data-testid=\"recording-summary\">\n {summary}\n </span>\n {time && <time className=\"text-muted-foreground\">{time}</time>}\n {live && <span className=\"text-red-500\">recording…</span>}\n {mediaDeleted && (\n <span className=\"text-muted-foreground\">Audio and video deleted — transcript kept</span>\n )}\n {!mediaDeleted && recording.expires_at && (\n <span className=\"text-muted-foreground\">\n Deleted after {new Date(recording.expires_at).toLocaleDateString()}\n </span>\n )}\n </div>\n {speakers.length > 0 && (\n <p className=\"flex flex-wrap items-center gap-1 text-muted-foreground\">\n {speakers.map((t, i) =>\n t.speaker_ext_id ? (\n <CallUserPill\n key={t.speaker_ext_id}\n identity={t.speaker_ext_id}\n name={t.speaker_name}\n />\n ) : (\n <span key={i}>{t.speaker_name || 'Someone'}</span>\n )\n )}\n </p>\n )}\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n aria-pressed={playing}\n onClick={() => setPlaying((p) => !p)}\n data-testid=\"recording-play\"\n >\n {playing ? (\n <Pause className=\"mr-1 size-3.5\" aria-hidden />\n ) : (\n <Play className=\"mr-1 size-3.5\" aria-hidden />\n )}\n {playing ? 'Close player' : 'Play'}\n </Button>\n )}\n {hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress}\n onClick={() => void download()}\n data-testid=\"recording-download\"\n >\n <Download className=\"mr-1 size-3.5\" aria-hidden />\n Download\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n onClick={() => void copyLink()}\n title=\"Copy an in-app link (only members of the meeting chat can open it)\"\n data-testid=\"recording-copy-link\"\n >\n <Link2 className=\"mr-1 size-3.5\" aria-hidden />\n Copy link\n </Button>\n {isHost && hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress || live}\n onClick={() => void transcribe()}\n data-testid=\"recording-transcribe\"\n >\n <Captions className=\"mr-1 size-3.5\" aria-hidden />\n Transcribe\n </Button>\n )}\n {isHost && hasMedia && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n disabled={!!progress || live}\n onClick={() => setSaveOpen(true)}\n data-testid=\"recording-save-to-thread\"\n >\n <FileUp className=\"mr-1 size-3.5\" aria-hidden />\n Save to thread\n </Button>\n )}\n {isHost && !mediaDeleted && (\n <ConfirmButton\n label=\"Keep transcript, delete audio/video\"\n confirmLabel=\"Delete audio/video now\"\n testId=\"recording-delete-media\"\n disabled={!!progress || live}\n icon={<Trash2 className=\"mr-1 size-3.5\" aria-hidden />}\n onConfirm={async () => {\n try {\n await arbi.calls.recording.deleteMedia(call.external_id, recording.external_id)\n setPlaying(false)\n setOpened(null)\n refresh()\n } catch (err) {\n notify((err as Error).message, 'error')\n }\n }}\n />\n )}\n {isHost && (\n <ConfirmButton\n label=\"Delete\"\n confirmLabel=\"Delete recording\"\n testId=\"recording-delete\"\n disabled={!!progress || live}\n icon={<Trash2 className=\"mr-1 size-3.5\" aria-hidden />}\n onConfirm={async () => {\n try {\n await arbi.calls.recording.delete(call.external_id, recording.external_id)\n refresh()\n } catch (err) {\n notify((err as Error).message, 'error')\n }\n }}\n />\n )}\n {isHost && !mediaDeleted && (\n <label className=\"flex items-center gap-1 text-muted-foreground\">\n Keep\n <select\n className=\"h-7 rounded-sm border border-border bg-background px-1 text-xs text-foreground\"\n value={expiryChoiceOf(recording.expires_at ?? null)}\n onChange={(e) => {\n const days = e.target.value === 'none' ? null : Number(e.target.value)\n void arbi.calls.recording\n .setExpiry(call.external_id, recording.external_id, expiryFor(days))\n .then(refresh)\n .catch((err: unknown) => notify((err as Error).message, 'error'))\n }}\n data-testid=\"recording-expiry\"\n aria-label=\"Keep the audio and video for\"\n >\n {EXPIRY_DAYS.map((d) => (\n <option key={d ?? 'none'} value={d ?? 'none'}>\n {d ? `${d} days` : 'until deleted'}\n </option>\n ))}\n </select>\n </label>\n )}\n {progress && (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n {progress}\n </span>\n )}\n </div>\n {playing && hasMedia && (\n <RecordingPlayer recording={recording} open={open} durationMs={durationMs} />\n )}\n {saveOpen && (\n <PickThreadDialog\n heading=\"Save recording to thread\"\n description=\"The recording is decrypted here and uploaded as documents (one audio file per speaker, and the video) into a thread of the current workspace, encrypted under its key. Only that workspace’s members can read them there.\"\n testIdPrefix=\"save-recording\"\n confirmLabel=\"Save\"\n busyLabel=\"Saving…\"\n onClose={() => setSaveOpen(false)}\n onConfirm={saveToThread}\n />\n )}\n </div>\n )\n}\n\n/**\n * Plays a recording: the composite video when there is one (it carries the mixed audio the host\n * heard), otherwise the speaker tracks mixed in sync on one WebAudio timeline.\n */\nfunction RecordingPlayer({\n recording,\n open,\n durationMs,\n}: {\n recording: calls.CallRecording\n open(): Promise<OpenedRecording>\n durationMs: number\n}): ReactElement {\n const composite = compositeTrack(recording)\n const [view, setView] = useState<'video' | 'audio'>(composite?.parts?.length ? 'video' : 'audio')\n return (\n <div className=\"flex flex-col gap-2\" data-testid=\"recording-player\">\n {composite?.parts?.length ? (\n <div className=\"flex gap-1\" role=\"group\" aria-label=\"Play\">\n {(['video', 'audio'] as const).map((v) => (\n <button\n key={v}\n type=\"button\"\n className={cn(\n 'rounded-full px-2 py-0.5',\n view === v ? 'bg-muted font-medium' : 'text-muted-foreground hover:bg-muted'\n )}\n aria-pressed={view === v}\n onClick={() => setView(v)}\n >\n {v === 'video' ? 'Video' : 'Speakers'}\n </button>\n ))}\n </div>\n ) : null}\n {view === 'video' && composite ? (\n <CompositeVideo open={open} trackExtId={composite.external_id} />\n ) : (\n <MixPlayer recording={recording} open={open} durationMs={durationMs} />\n )}\n </div>\n )\n}\n\nfunction CompositeVideo({\n open,\n trackExtId,\n}: {\n open(): Promise<OpenedRecording>\n trackExtId: string\n}): ReactElement {\n const arbi = useArbi()\n const [urls, setUrls] = useState<string[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n let made: string[] = []\n void (async () => {\n try {\n const opened = await open()\n const track = (opened.recording.tracks ?? []).find((t) => t.external_id === trackExtId)\n const key = opened.keys.get(trackExtId)\n if (!track || !key) throw new Error('The video does not open with your key')\n const blobs = await compositeFiles(arbi, track, key)\n made = blobs.map((b) => URL.createObjectURL(b))\n if (cancelled) made.forEach((u) => URL.revokeObjectURL(u))\n else setUrls(made)\n } catch (err) {\n if (!cancelled) setError((err as Error).message)\n }\n })()\n return () => {\n cancelled = true\n made.forEach((u) => URL.revokeObjectURL(u))\n }\n }, [arbi, open, trackExtId])\n if (error) return <p className=\"text-destructive\">{error}</p>\n if (!urls) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n Decrypting the video…\n </span>\n )\n }\n return (\n <>\n {urls.map((u, i) => (\n <video\n key={u}\n src={u}\n controls\n className=\"w-full rounded-sm bg-black\"\n aria-label={`Video ${i + 1}`}\n />\n ))}\n </>\n )\n}\n\nconst fmt = (ms: number) => {\n const s = Math.max(0, Math.floor(ms / 1000))\n const h = Math.floor(s / 3600)\n const m = Math.floor((s % 3600) / 60)\n const sec = String(s % 60).padStart(2, '0')\n return h ? `${h}:${String(m).padStart(2, '0')}:${sec}` : `${m}:${sec}`\n}\n\n/**\n * The speaker tracks mixed in sync: parts are fetched, decrypted and decoded a little ahead of the\n * playhead and started on one AudioContext clock at their offsets (see `recording-playback.ts`).\n */\nfunction MixPlayer({\n recording,\n open,\n durationMs,\n}: {\n recording: calls.CallRecording\n open(): Promise<OpenedRecording>\n durationMs: number\n}): ReactElement {\n const arbi = useArbi()\n const { notify } = useBlocksEnvironment()\n const parts = useMemo(() => timelineOf(speakerTracks(recording)), [recording])\n const [position, setPosition] = useState(0)\n const [playing, setPlaying] = useState(false)\n const session = useRef<{\n ctx: AudioContext\n ctxStart: number\n seekMs: number\n scheduled: Set<string>\n timer: ReturnType<typeof setInterval>\n } | null>(null)\n\n const halt = useCallback(() => {\n const s = session.current\n session.current = null\n if (!s) return\n clearInterval(s.timer)\n void s.ctx.close().catch(() => undefined)\n }, [])\n\n useEffect(() => halt, [halt])\n\n const play = useCallback(\n async (fromMs: number) => {\n halt()\n const opened = await open()\n const ctx = new AudioContext()\n const s = {\n ctx,\n ctxStart: ctx.currentTime + 0.25,\n seekMs: fromMs,\n scheduled: new Set<string>(),\n timer: 0 as unknown as ReturnType<typeof setInterval>,\n }\n const schedule = async (part: TimelinePart) => {\n const track = (opened.recording.tracks ?? []).find((t) => t.external_id === part.trackExtId)\n const key = opened.keys.get(part.trackExtId)\n const raw = track?.parts?.find((p) => p.seq === part.seq)\n if (!track || !key || !raw) return\n try {\n const bytes = await fetchPart(arbi, raw, key)\n const buffer = await ctx.decodeAudioData(standalone(bytes).buffer)\n if (session.current !== s) return\n const at = schedulePart({\n partOffsetMs: part.offsetMs,\n bufferDurationS: buffer.duration,\n ctxStart: s.ctxStart,\n seekMs: s.seekMs,\n ctxNow: ctx.currentTime,\n })\n if (!at) return\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.connect(ctx.destination)\n source.start(at.when, at.offset)\n } catch (err) {\n console.warn('[calls] a recording part does not play', err)\n }\n }\n const tick = () => {\n if (session.current !== s) return\n const head = playheadAt(ctx.currentTime, s.ctxStart, s.seekMs)\n setPosition(Math.min(head, durationMs))\n if (head >= durationMs) {\n halt()\n setPlaying(false)\n return\n }\n for (const part of partsDue(parts, head, PLAYBACK_LOOKAHEAD_MS, s.scheduled)) {\n s.scheduled.add(partKey(part))\n void schedule(part)\n }\n }\n s.timer = setInterval(tick, 500)\n session.current = s\n setPlaying(true)\n tick()\n },\n [arbi, open, parts, durationMs, halt]\n )\n\n const toggle = () => {\n if (playing) {\n halt()\n setPlaying(false)\n } else {\n void play(position >= durationMs ? 0 : position).catch((err: unknown) => {\n setPlaying(false)\n notify((err as Error).message, 'error')\n })\n }\n }\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"outline\"\n className=\"size-7\"\n aria-label={playing ? 'Pause' : 'Play'}\n onClick={toggle}\n data-testid=\"recording-mix-toggle\"\n >\n {playing ? <Pause className=\"size-3.5\" /> : <Play className=\"size-3.5\" />}\n </Button>\n <input\n type=\"range\"\n min={0}\n max={Math.max(1, durationMs)}\n step={1000}\n value={position}\n className=\"flex-1\"\n aria-label=\"Position\"\n onChange={(e) => {\n const ms = Number(e.target.value)\n setPosition(ms)\n if (playing) {\n void play(ms).catch((err: unknown) => notify((err as Error).message, 'error'))\n }\n }}\n />\n <span className=\"tabular-nums text-muted-foreground\">\n {fmt(position)} / {fmt(durationMs)}\n </span>\n </div>\n )\n}\n","/**\n * A thread call's log card in the thread transcript: the `convo_events` row of kind `call` the\n * server writes when the call starts and updates when it ends (plaintext ids and times only).\n *\n * live: \"Call started by Ada · invited Bob, Cy\" · Join\n * ended: \"Call · 12 min · joined Ada, Bob\" · Open meeting chat\n *\n * It re-reads on `call.started` / `call.ended` (see `refreshCallCards`).\n */\n\nimport { useArbi, useCallSession, useCall, useOpenCallMeetingChat, openCall } from '@arbidocs/react'\nimport { useState, type ReactElement } from 'react'\nimport { MessageSquare, Phone, PhoneOff } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\nimport { formatCallDuration, type CallLogDetail } from '../call-cards'\n\nfunction joinNames(people: string[], name: (id: string) => string): string {\n const names = people.map(name)\n return names.length > 4\n ? `${names.slice(0, 4).join(', ')} +${names.length - 4}`\n : names.join(', ')\n}\n\nexport function ThreadCallLogCard({\n detail,\n name,\n workspaceExtId,\n time,\n}: {\n detail: CallLogDetail\n /** A person's display name by user ext id. */\n name: (userExtId: string) => string\n /** The thread's workspace (the meeting thread lives there too). */\n workspaceExtId: string | null\n time?: string\n}): ReactElement {\n const arbi = useArbi()\n const openCallMeetingChat = useOpenCallMeetingChat()\n const live = !detail.ended_at\n const inThisCall = useCallSession((s) => s.active?.callExtId === detail.call_ext_id)\n const inAnotherCall = useCallSession(\n (s) => !!s.active && s.active.callExtId !== detail.call_ext_id\n )\n // Only people holding K (the creator and those rung) can join from the card.\n const { data: call } = useCall(live ? detail.call_ext_id : null)\n const invitedOnly = live && !!call && !call.my_sealed_key\n const [busy, setBusy] = useState(false)\n\n const summary = live\n ? [\n detail.started_by ? `Call started by ${name(detail.started_by)}` : 'Call started',\n detail.invited.length ? `invited ${joinNames(detail.invited, name)}` : null,\n ]\n : [\n 'Call',\n formatCallDuration(detail.duration_s),\n detail.joined.length ? `joined ${joinNames(detail.joined, name)}` : null,\n ]\n\n return (\n <div\n className=\"mx-auto my-1 flex w-fit max-w-full flex-wrap items-center justify-center gap-2 rounded-md border border-border bg-card px-3 py-2 text-xs\"\n data-testid=\"thread-call-log-card\"\n data-live={live || undefined}\n >\n {live ? (\n <Phone className=\"size-4 animate-pulse text-green-text\" aria-hidden />\n ) : (\n <PhoneOff className=\"size-4 text-muted-foreground\" aria-hidden />\n )}\n <span data-testid=\"thread-call-log-summary\">{summary.filter(Boolean).join(' · ')}</span>\n {time && <time className=\"text-muted-foreground\">{time}</time>}\n {live ? (\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-7 bg-green-600 text-white hover:bg-green-700\"\n disabled={busy || inThisCall || inAnotherCall || invitedOnly}\n title={\n invitedOnly\n ? 'Only the people rung into this call can join'\n : inAnotherCall\n ? 'You are already in a call'\n : undefined\n }\n onClick={() => {\n setBusy(true)\n void openCall(arbi, { callExtId: detail.call_ext_id }).finally(() => setBusy(false))\n }}\n data-testid=\"thread-call-log-join\"\n >\n {inThisCall ? 'In call' : 'Join'}\n </Button>\n ) : (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7\"\n onClick={() =>\n void openCallMeetingChat({\n callExtId: detail.call_ext_id,\n meetingConversationExtId: detail.meeting_conversation_ext_id,\n workspaceExtId,\n })\n }\n data-testid=\"thread-call-log-open-chat\"\n >\n <MessageSquare className=\"mr-1 size-3.5\" aria-hidden />\n Open meeting chat\n </Button>\n )}\n </div>\n )\n}\n","/**\n * One stored line of a call transcript in its conversation (meeting chat or workspace meeting\n * thread): `TranscriptLine` from `@arbidocs/blocks`, centred for everyone. What someone is saying\n * right now shows as a provisional \"is speaking…\" row below, not as a highlight on a past line.\n */\n\nimport type { ReactElement } from 'react'\nimport { TranscriptLine } from '../../chat/TranscriptLine'\nimport { CallUserPill } from './CallUserPill'\n\nfunction formatTime(iso: string | null | undefined): string {\n if (!iso) return ''\n const at = Date.parse(iso)\n if (Number.isNaN(at)) return ''\n return new Date(at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport function TranscriptEntry({\n speakerId,\n speakerName,\n text,\n at,\n continued = false,\n className,\n}: {\n /** The speaker's identity (user ext id), for `data-speaker`. */\n speakerId: string\n /** The name to show (\"Me\" for my own lines). */\n speakerName: string\n text: string\n /** ISO time the segment started (or the message was stored). */\n at: string | null | undefined\n /** A further line of the same speaker's run (no name repeated). */\n continued?: boolean\n className?: string\n}): ReactElement {\n return (\n <TranscriptLine\n speakerId={speakerId}\n speakerName={speakerName}\n speaker={<CallUserPill identity={speakerId} name={speakerName} />}\n time={formatTime(at)}\n text={text}\n continued={continued}\n className={className}\n />\n )\n}\n","/** A call participant's name, as the people directory knows them. */\n\nimport { useMemo } from 'react'\nimport { useArbi, usePeople } from '@arbidocs/react'\nimport { getUserDisplayName } from '@arbidocs/react/ui'\n\n/** The name for an identity (user ext id): mine, a known person's, else the call's name for them. */\nexport function useCallPersonName(identity: string, fallbackName?: string | null): string {\n const arbi = useArbi()\n const { byId } = usePeople()\n const me = arbi.isLoggedIn && arbi.user.identity()?.externalId === identity\n const profile = me ? arbi.user.profile() : null\n return useMemo(() => {\n if (profile)\n return getUserDisplayName({ given_name: profile.givenName, family_name: profile.familyName })\n const user = byId(identity)\n if (user) return getUserDisplayName(user)\n return (fallbackName || identity).trim().split(/\\s+/).join(' ')\n }, [profile, byId, identity, fallbackName])\n}\n","/**\n * A call's conversation (meeting chat or meeting thread), call-aware: its empty state (\"Call in\n * progress — the transcript will appear here\", or \"No transcript\" afterwards) instead of the\n * generic one, and provisional \"<speaker> is speaking…\" rows while a line is on its way.\n */\n\nimport { useCallSession } from '@arbidocs/react'\nimport type { ReactElement } from 'react'\nimport { AudioLines, Captions, CaptionsOff } from 'lucide-react'\nimport { EmptyState } from '../../components/EmptyState'\nimport { ProvisionalTranscriptLine } from '../../chat/TranscriptLine'\nimport { useMyCallStatus } from '../call-status'\nimport { CallUserPill } from './CallUserPill'\nimport { useCallPersonName } from './call-person-name'\n\n/** The empty conversation of a call: live while the call runs, \"No transcript\" after. */\nexport function CallConversationEmpty({ callExtId }: { callExtId: string }): ReactElement {\n const { inCall, transcribing } = useMyCallStatus(callExtId)\n const live = useCallSession((s) => !!s.liveCalls[callExtId]) || inCall\n if (!live) {\n return (\n <EmptyState\n icon={AudioLines}\n title=\"No transcript\"\n description=\"This call was not transcribed. When a call here is transcribed, what people say appears in this conversation.\"\n className=\"mx-auto my-8 max-w-xl\"\n testId=\"call-conversation-empty\"\n />\n )\n }\n return (\n <EmptyState\n icon={transcribing ? Captions : CaptionsOff}\n title=\"Call in progress — the transcript will appear here\"\n description={\n transcribing\n ? 'Transcription is on: what people say shows up here as they speak.'\n : 'Transcription is off. The host can turn it on with CC in the call.'\n }\n className=\"mx-auto my-8 max-w-xl\"\n testId=\"call-conversation-empty\"\n />\n )\n}\n\nfunction ProvisionalRow({ identity }: { identity: string }): ReactElement {\n const name = useCallPersonName(identity)\n return (\n <ProvisionalTranscriptLine\n speakerId={identity}\n speakerName={name}\n speaker={<CallUserPill identity={identity} />}\n />\n )\n}\n\n/** The provisional rows at the bottom of a call's conversation (never stored). */\nexport function ProvisionalSpeakers({ ids }: { ids: string[] }): ReactElement | null {\n if (!ids.length) return null\n return (\n <div className=\"pb-2\" data-testid=\"transcript-provisional-rows\">\n {ids.map((id) => (\n <ProvisionalRow key={id} identity={id} />\n ))}\n </div>\n )\n}\n","/** Who gets a provisional \"is speaking…\" row in a call's conversation. */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useMyCallStatus } from '../call-status'\nimport { useSpeakingIds } from '../voice-levels'\n\n/** A spoken stretch whose line has not arrived yet. */\ninterface Pending {\n startedAt: number\n lastHeardAt: number\n}\n\n/** How long after someone stops a provisional row waits for their line before it gives up. */\nconst LINE_WAIT_MS = 10_000\n/** A burst shorter than this (a cough, a word) gets no row. */\nconst MIN_SPEECH_MS = 800\n\n/**\n * Who should show a provisional row: people talking now, and people who stopped but whose line\n * has not arrived yet (a line started at or after their stretch began replaces the row).\n */\nexport function useProvisionalSpeakers(\n callExtId: string | null | undefined,\n lines: { speakerId: string; at: number }[]\n): string[] {\n const { inCall, transcribing } = useMyCallStatus(callExtId)\n const speaking = useSpeakingIds()\n const pending = useRef(new Map<string, Pending>())\n const [, tick] = useState(0)\n const active = inCall && transcribing\n const now = Date.now()\n if (active) {\n for (const id of speaking) {\n const p = pending.current.get(id)\n if (p) p.lastHeardAt = now\n else pending.current.set(id, { startedAt: now, lastHeardAt: now })\n }\n } else if (pending.current.size) {\n pending.current.clear()\n }\n // A line that began within the stretch (a little slack for clock skew) replaces the row.\n const latest = useMemo(() => {\n const m = new Map<string, number>()\n for (const l of lines) m.set(l.speakerId, Math.max(m.get(l.speakerId) ?? 0, l.at))\n return m\n }, [lines])\n for (const [id, p] of [...pending.current]) {\n const arrived = (latest.get(id) ?? 0) >= p.startedAt - 3000\n const stale = !speaking.includes(id) && now - p.lastHeardAt > LINE_WAIT_MS\n if ((arrived && !speaking.includes(id)) || stale) pending.current.delete(id)\n else if (arrived) p.startedAt = now\n }\n // Re-check while rows wait for their lines.\n const waiting = pending.current.size > 0\n useEffect(() => {\n if (!waiting) return\n const id = setInterval(() => tick((n) => n + 1), 1000)\n return () => clearInterval(id)\n }, [waiting])\n return [...pending.current]\n .filter(([, p]) => p.lastHeardAt - p.startedAt >= MIN_SPEECH_MS)\n .map(([id]) => id)\n}\n","/**\n * How a meeting thread's transcript lines group: which messages continue their speaker's run (the\n * name is not repeated) and which are each speaker's newest line (highlighted while they talk).\n * Provided by the conversation page, read by each transcript message.\n */\n\nimport { createContext, useContext } from 'react'\nimport { transcriptRuns } from '../../chat/transcript-runs'\nimport { transcriptSegmentOf } from '@arbidocs/react'\n\nexport interface TranscriptRunInfo {\n continued: ReadonlySet<string>\n latest: ReadonlySet<string>\n}\n\nconst EMPTY: TranscriptRunInfo = { continued: new Set(), latest: new Set() }\n\nexport const TranscriptRunsContext = createContext<TranscriptRunInfo>(EMPTY)\n\nexport function useTranscriptRuns(): TranscriptRunInfo {\n return useContext(TranscriptRunsContext)\n}\n\ninterface ThreadMessageLike {\n external_id?: string | null\n created_at?: string | null\n tools?: unknown\n meta?: { tools?: unknown } | null\n}\n\n/** Runs and newest lines of a thread's messages (in display order). */\nexport function threadTranscriptRuns(messages: ThreadMessageLike[]): TranscriptRunInfo {\n const segmentOf = (m: ThreadMessageLike) => transcriptSegmentOf(m.tools ?? m.meta?.tools)\n const continuedItems = transcriptRuns(\n messages,\n (m) => segmentOf(m)?.speaker_ext_id ?? null,\n (m) => Date.parse(segmentOf(m)?.started_at ?? m.created_at ?? '') || 0\n )\n const latest = new Map<string, string>()\n for (const m of messages) {\n const seg = segmentOf(m)\n if (seg && m.external_id) latest.set(seg.speaker_ext_id, m.external_id)\n }\n return {\n continued: new Set(\n [...continuedItems].map((m) => m.external_id).filter((id): id is string => !!id)\n ),\n latest: new Set(latest.values()),\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { ArbiHost } from './chunk-T4P237N6.js';
|
|
3
|
-
import { useBlocksEnvironment } from './chunk-QZUZPC4J.js';
|
|
3
|
+
import { closeAllDialogs, useBlocksEnvironment } from './chunk-QZUZPC4J.js';
|
|
4
4
|
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
5
5
|
import { useArbi, useArbiSessionStore, useSwitchWorkspace, useArbiSessionState, clearSealedDrafts, arbiAccountClient, toProfileView } from '@arbidocs/react';
|
|
6
6
|
import { jsx } from 'react/jsx-runtime';
|
|
@@ -54,6 +54,15 @@ function ConnectionProvider({
|
|
|
54
54
|
const selectWorkspaceId = session.setWorkspaceId;
|
|
55
55
|
const [mode, setMode] = useState("demo");
|
|
56
56
|
const [error, setError] = useState(null);
|
|
57
|
+
const hadDialogSession = useRef(false);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (status === "authenticated" || status === "demo") {
|
|
60
|
+
hadDialogSession.current = true;
|
|
61
|
+
} else if (status !== "connecting" && hadDialogSession.current) {
|
|
62
|
+
hadDialogSession.current = false;
|
|
63
|
+
closeAllDialogs();
|
|
64
|
+
}
|
|
65
|
+
}, [status]);
|
|
57
66
|
const storageUserRef = useRef(null);
|
|
58
67
|
const sessionRun = useRef(0);
|
|
59
68
|
useEffect(
|
|
@@ -334,5 +343,5 @@ function useConnectedWorkspace() {
|
|
|
334
343
|
}
|
|
335
344
|
|
|
336
345
|
export { ConnectionProvider, SESSION_EXPIRED_MESSAGE, isAuthenticated, useConnectedWorkspace, useConnection, useOptionalConnection };
|
|
337
|
-
//# sourceMappingURL=chunk-
|
|
338
|
-
//# sourceMappingURL=chunk-
|
|
346
|
+
//# sourceMappingURL=chunk-2YCCCXYV.js.map
|
|
347
|
+
//# sourceMappingURL=chunk-2YCCCXYV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection/ConnectionProvider.tsx"],"names":["login"],"mappings":"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","file":"chunk-2YCCCXYV.js","sourcesContent":["/**\n * The demo/live connection layer for a host app. Holds auth + workspace\n * selection state and exposes it via {@link useConnection}, so every surface\n * works identically whether it's talking to a live ARBI backend or the seeded\n * demo workspace. Host-specific values (backend URL, demo identity, default\n * workspace/assistant ids) arrive once through {@link ArbiConnectionConfig}.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n arbiAccountClient,\n clearSealedDrafts,\n toProfileView,\n useArbi,\n useArbiSessionState,\n useArbiSessionStore,\n useSwitchWorkspace,\n type AccountClient,\n type LoginProfile,\n type ProfileView,\n} from '@arbidocs/react'\nimport type { ArbiMode, ArbiUser, ConnectionStatus, ArbiConnectionConfig } from './types'\nimport { useBlocksEnvironment } from '../provider/environment'\nimport { ArbiHost } from '../provider/host'\nimport { closeAllDialogs } from '../provider/dialog-registry'\n\ninterface ConnectionValue {\n mode: ArbiMode\n status: ConnectionStatus\n user: ArbiUser | null\n /** The selected workspace: the session state's (`useArbiSessionState`), set by `setWorkspace`. */\n workspaceId: string | null\n apiConfigured: boolean\n apiUrl: string\n /**\n * The deployment domain the user's keys are derived for (`arbi.getDeploymentDomain()`), for the\n * document tools' e-signing. `undefined` in demo mode.\n */\n deploymentDomain: string | undefined\n error: string | null\n /** Default assistant config ext_id (for the AI hooks). */\n assistantConfig?: string\n /**\n * The demo's workspace when none is selected. Never set signed in to a live backend: there the\n * selection is the only workspace (none while a switch is in flight), never a remembered one.\n */\n fallbackWorkspaceId?: string\n /** Authenticate. Live login when a backend is configured, otherwise the demo workspace. */\n login: (email: string, password: string) => Promise<void>\n /** One-click demo entry (no backend required). */\n enterDemo: () => void\n logout: () => void\n /**\n * Affirmatively select a workspace: opens it on the server (via the SDK),\n * updates the app-wide state, and persists the choice so it survives future\n * logins. This is the single entry point for \"the user is now in workspace X\".\n */\n setWorkspace: (id: string) => Promise<void>\n /**\n * Re-assert the selected workspace on the server session (idempotent `/open`).\n * Call before a workspace-scoped write when the session may have lost its open\n * workspace (token re-login, backend restart, session expiry) — the server\n * resolves the workspace from the session, so a dropped `/open` yields\n * \"No active workspace\" until it's re-opened.\n */\n ensureWorkspaceOpen: () => Promise<void>\n}\n\nconst ConnectionContext = createContext<ConnectionValue | null>(null)\n\n/**\n * Persist the affirmatively-selected workspace per backend AND per signed-in user, so a returning\n * user lands back in the workspace they last chose, while the next person on a shared browser\n * never starts from someone else's workspace id. Namespaced by apiUrl so distinct deployments\n * (and the demo workspace) don't clobber each other. Cleared on logout.\n */\nconst WORKSPACE_STORAGE_PREFIX = 'arbi:selectedWorkspace'\nconst normalizeUserKey = (email: string) => email.trim().toLowerCase()\n\n/** Exported for tests. */\nexport const workspaceStorageKey = (apiUrl: string, userKey: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}:${normalizeUserKey(userKey)}`\n\n/** The pre-isolation key (apiUrl only). Never read: removed so it cannot leak across users. */\nconst legacyWorkspaceStorageKey = (apiUrl: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}`\n\nfunction readPersistedWorkspace(apiUrl: string, userKey: string | null): string | null {\n if (!userKey) return null\n try {\n return window.localStorage.getItem(workspaceStorageKey(apiUrl, userKey))\n } catch {\n return null\n }\n}\n\nfunction persistWorkspace(apiUrl: string, userKey: string | null, id: string | null): void {\n if (!userKey) return\n try {\n if (id) window.localStorage.setItem(workspaceStorageKey(apiUrl, userKey), id)\n else window.localStorage.removeItem(workspaceStorageKey(apiUrl, userKey))\n window.localStorage.removeItem(legacyWorkspaceStorageKey(apiUrl))\n } catch {\n // Storage unavailable (private mode, SSR) — selection stays in-memory only.\n }\n}\n\n/** Shown on the sign-in screen after the session could not be recovered. */\nexport const SESSION_EXPIRED_MESSAGE = 'Your session expired. Sign in again.'\n\n/** The connection user for a profile: its full name, falling back to the email local part. */\nfunction userFromProfile(profile: LoginProfile, externalId?: string): ArbiUser {\n const fullName = [profile.givenName, profile.familyName]\n .map((part) => part?.trim())\n .filter(Boolean)\n .join(' ')\n return {\n name: fullName || profile.email.split('@')[0],\n email: profile.email,\n externalId,\n picture: profile.picture,\n }\n}\n\n/**\n * The sign-in layer of a blocks-only site, mounted by its host (`defaultHost`): login, demo mode\n * and the selected workspace, over the host's session state (the selected workspace lives there,\n * so every block reads one value). Its account client is the host's `account` below it.\n */\nexport function ConnectionProvider({\n config,\n children,\n}: {\n config: ArbiConnectionConfig\n children: ReactNode\n}) {\n const arbi = useArbi()\n const session = useArbiSessionStore()\n const { switchWorkspace, openSelectedWorkspace, settled } = useSwitchWorkspace()\n const isLiveConfigured = config.apiUrl.length > 0\n const demoWorkspaceId = config.demoWorkspaceId ?? 'demo-workspace'\n\n const [status, setStatus] = useState<ConnectionStatus>(\n isLiveConfigured ? 'connecting' : 'disconnected'\n )\n const [user, setUser] = useState<ArbiUser | null>(null)\n const workspaceId = useArbiSessionState((s) => s.workspaceId)\n const selectWorkspaceId = session.setWorkspaceId\n const [mode, setMode] = useState<ArbiMode>('demo')\n const [error, setError] = useState<string | null>(null)\n // Dialogs belong to the signed-in session. A first signed-out mount may carry an invitation\n // intent, so clear only after an authenticated (or demo) session actually ends. A workspace\n // switch / sign-in can pass through `connecting` without ending that session.\n const hadDialogSession = useRef(false)\n useEffect(() => {\n if (status === 'authenticated' || status === 'demo') {\n hadDialogSession.current = true\n } else if (status !== 'connecting' && hadDialogSession.current) {\n hadDialogSession.current = false\n closeAllDialogs()\n }\n }, [status])\n // Who the persisted workspace belongs to; set at sign-in, cleared at logout.\n const storageUserRef = useRef<string | null>(null)\n // Moves at each logout: a sign-in still finishing from before it does not sign back in.\n const sessionRun = useRef(0)\n\n // The SDK could not recover the session (token refused, workspace not re-openable): drop to\n // 'disconnected' with a plain message, so the host's gate sends the user to sign in instead of\n // every call failing with a raw backend error. The remembered workspace is kept for next login.\n useEffect(\n () =>\n arbi.onSessionExpired?.(() => {\n storageUserRef.current = null\n setUser(null)\n selectWorkspaceId(null)\n setStatus('disconnected')\n setError(SESSION_EXPIRED_MESSAGE)\n }),\n [arbi, selectWorkspaceId]\n )\n\n // A saved name, picture or email reaches every surface reading `useConnection().user`.\n useEffect(\n () =>\n arbi.user.onProfileChange?.((profile) =>\n setUser((current) => (current ? userFromProfile(profile, current.externalId) : current))\n ),\n [arbi]\n )\n\n const enterDemo = useCallback(() => {\n setMode('demo')\n setStatus('demo')\n setError(null)\n setUser({ name: config.demoUser.name, email: config.demoUser.email })\n selectWorkspaceId(demoWorkspaceId)\n }, [config.demoUser.name, config.demoUser.email, demoWorkspaceId, selectWorkspaceId])\n\n /**\n * The session signed in, by whatever path (`login` below, a sign-in page on the host's `Arbi`,\n * a restored session): open the user's workspace and resolve who they are.\n */\n const completeSignIn = useCallback(\n async (email: string) => {\n const run = sessionRun.current\n const signedOut = () => run !== sessionRun.current\n setMode('live')\n setStatus('connecting')\n setError(null)\n try {\n storageUserRef.current = normalizeUserKey(email)\n const workspaces = await arbi.workspaces.list()\n if (workspaces?.length) {\n // Prefer the workspace the user last affirmatively selected (persisted),\n // then the configured workspace (there may be several — e.g. a\n // marketing/KM workspace), then whichever happens to be first. Ternary\n // (not `&&`) so an empty value can't leak `\"\"` into `target`.\n const persisted = readPersistedWorkspace(config.apiUrl, storageUserRef.current)\n const preferred = persisted ?? config.workspaceId\n const target =\n (preferred ? workspaces.find((w) => w.external_id === preferred) : undefined) ??\n workspaces[0]\n selectWorkspaceId(target.external_id)\n if (!(await openSelectedWorkspace()))\n throw new Error('Could not open your workspace. Try signing in again.')\n persistWorkspace(config.apiUrl, storageUserRef.current, target.external_id)\n }\n // The profile (name + avatar) comes with the login response. A session restored without\n // a login has none, so fall back to finding ourselves in the workspace roster; the email\n // local part is only the last resort, never the answer when a profile name exists.\n let resolved: ArbiUser = { name: email.split('@')[0], email }\n const me = arbi.user.identity()\n const profile = arbi.user.profile?.()\n if (profile) {\n resolved = userFromProfile(profile, me?.externalId)\n } else {\n try {\n const members = await arbi.workspaces.listUsers()\n const self = members.find((m) => m.user.external_id === me?.externalId)?.user\n if (self) {\n const fullName = [self.given_name, self.family_name].filter(Boolean).join(' ').trim()\n resolved = {\n name: fullName || email.split('@')[0],\n email: self.email || email,\n externalId: self.external_id,\n picture: self.picture ?? null,\n }\n } else if (me?.externalId) {\n resolved.externalId = me.externalId\n }\n } catch {\n // Roster not available (e.g. no workspace) — keep the fallback identity.\n }\n }\n if (signedOut()) return\n setUser(resolved)\n setStatus('authenticated')\n } catch (e) {\n if (signedOut()) return\n // Surface the real error — no silent fallback to a fake session.\n setError(e instanceof Error ? e.message : 'Sign-in failed. Check your credentials.')\n setStatus('error')\n }\n },\n [arbi, config.workspaceId, config.apiUrl, selectWorkspaceId, openSelectedWorkspace]\n )\n\n // Every sign-in on the host's `Arbi` lands here, whichever page or kit made it.\n const signingIn = useRef<Promise<void>>(Promise.resolve())\n useEffect(\n () =>\n arbi.onSignedIn?.((login) => {\n signingIn.current = completeSignIn(\n login.profile?.email ??\n arbi.session?.getState().userEmail ??\n arbi.user.identity()?.email ??\n ''\n )\n }),\n [arbi, completeSignIn]\n )\n\n /** Authenticate: a live login when a backend is configured, otherwise the demo workspace. */\n const login = useCallback(\n async (email: string, password: string) => {\n setError(null)\n if (!isLiveConfigured) {\n enterDemo()\n return\n }\n setStatus('connecting')\n setMode('live')\n try {\n // Signed in: `completeSignIn` follows (onSignedIn); done once it is.\n await arbi.login(email, password)\n await signingIn.current\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Sign-in failed. Check your credentials.')\n setStatus('error')\n }\n },\n [arbi, enterDemo, isLiveConfigured]\n )\n\n // The session kept on this device signs in again (no password; the key stays encrypted on the\n // device). Run once even under StrictMode.\n const restoreStarted = useRef(false)\n useEffect(() => {\n if (restoreStarted.current || !isLiveConfigured) return\n restoreStarted.current = true\n arbi\n .restore()\n .catch(() => false)\n .then(async (restored) => {\n if (restored) await signingIn.current\n else setStatus('disconnected')\n })\n }, [arbi, isLiveConfigured])\n\n const logout = useCallback(() => {\n sessionRun.current++\n // The SDK stops the session's work (requests, re-logins, opens, the queries in flight) before\n // the server revokes the token.\n if (mode === 'live') {\n void arbi.logout?.()\n }\n // What was typed never outlives the session (it is sealed, but kept for no one now).\n clearSealedDrafts()\n setUser(null)\n selectWorkspaceId(null)\n persistWorkspace(config.apiUrl, storageUserRef.current, null)\n storageUserRef.current = null\n setStatus('disconnected')\n setError(null)\n }, [arbi, mode, config.apiUrl, selectWorkspaceId])\n\n // Affirmative selection: the shared workspace switch (live), then remember it so the next\n // login lands there too. This provider IS the host's navigation, so it alone (with sign-in and\n // ensureWorkspaceOpen, which re-open the host's own selection) changes the workspace; kits reach\n // another workspace with `arbi.workspaces.open`.\n const setWorkspace = useCallback(\n async (id: string) => {\n if (mode === 'live' && arbi.isLoggedIn) {\n if (!(await switchWorkspace({ id }))) throw new Error('Could not open the workspace')\n } else {\n selectWorkspaceId(id)\n }\n persistWorkspace(config.apiUrl, storageUserRef.current, id)\n },\n [arbi, mode, config.apiUrl, selectWorkspaceId, switchWorkspace]\n )\n\n // Re-open the selected workspace on the session if the server may have dropped it. Idempotent.\n // A switch in flight is waited out first, then only the selection as of then is opened (none:\n // nothing). Never a remembered or configured workspace: kits call this before reading, and\n // opening another workspace than the selected one would leave the server session in it.\n const ensureWorkspaceOpen = useCallback(async () => {\n if (mode !== 'live' || !arbi.isLoggedIn) return\n await settled()\n if (!session.getState().workspaceId) return\n await openSelectedWorkspace()\n }, [arbi, session, mode, settled, openSelectedWorkspace])\n\n const value = useMemo<ConnectionValue>(\n () => ({\n mode,\n status,\n user,\n workspaceId,\n apiConfigured: isLiveConfigured,\n apiUrl: config.apiUrl,\n deploymentDomain: isLiveConfigured ? arbi.getDeploymentDomain() : undefined,\n error,\n assistantConfig: config.assistantConfig,\n fallbackWorkspaceId: mode === 'live' ? undefined : config.workspaceId,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n }),\n [\n mode,\n status,\n user,\n workspaceId,\n isLiveConfigured,\n config.apiUrl,\n arbi,\n config.assistantConfig,\n config.workspaceId,\n error,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n ]\n )\n\n const account = useConnectionAccount(arbi, user, logout)\n const authenticated = status === 'authenticated'\n const host = useMemo(\n () => ({ account: { client: account, useEnabled: () => authenticated } }),\n [account, authenticated]\n )\n\n return (\n <ConnectionContext.Provider value={value}>\n <ArbiHost config={host}>{children}</ArbiHost>\n </ConnectionContext.Provider>\n )\n}\n\n/**\n * The account client of the settings blocks below: the SDK's, with sign-out going through this\n * connection (so its state is cleared too) and, for a session restored without a login (no SDK\n * profile), the connection user as the profile.\n */\nfunction useConnectionAccount(\n arbi: ReturnType<typeof useArbi>,\n user: ArbiUser | null,\n logout: () => void\n): AccountClient {\n const userRef = useRef(user)\n const logoutRef = useRef(logout)\n logoutRef.current = logout\n const listeners = useRef(new Set<() => void>())\n useEffect(() => {\n userRef.current = user\n listeners.current.forEach((listener) => listener())\n }, [user])\n return useMemo(() => {\n const base = arbiAccountClient(arbi)\n return {\n ...base,\n profile: (): ProfileView | null => {\n const own = base.profile()\n const fallback = userRef.current\n if (own || !fallback) return own\n return {\n ...toProfileView({\n givenName: '',\n familyName: null,\n picture: fallback.picture ?? null,\n email: fallback.email,\n isSso: false,\n }),\n fullName: fallback.name,\n }\n },\n onProfileChange: (listener) => {\n listeners.current.add(listener)\n const off = base.onProfileChange(listener)\n return () => {\n listeners.current.delete(listener)\n off()\n }\n },\n signOut: async ({ everywhere } = {}) => {\n try {\n if (everywhere) await arbi.sessions.logoutAll()\n } finally {\n logoutRef.current()\n }\n },\n }\n }, [arbi])\n}\n\n/** The sign-in layer of `defaultHost`, or null under a host that keeps its own session. */\nexport function useOptionalConnection(): ConnectionValue | null {\n return useContext(ConnectionContext)\n}\n\nexport function useConnection(): ConnectionValue {\n const ctx = useContext(ConnectionContext)\n if (!ctx) throw new Error('useConnection needs the sign-in layer of `defaultHost` above it')\n return ctx\n}\n\nexport const isAuthenticated = (s: ConnectionStatus) => s === 'demo' || s === 'authenticated'\n\n/** The open workspace as the connected kits see it, whoever hosts them. */\nexport interface ConnectedWorkspace {\n /** The selected workspace (the session state's; with a connection, else its fallback). */\n workspaceId: string | null\n /** Signed in to a live backend: workspace-scoped queries may run. */\n live: boolean\n /** The signed-in user (their name and email, e.g. to sign a document). */\n user: ArbiUser | null\n /** The signed-in user's external id. */\n userId: string | undefined\n /** Re-assert the workspace on the server session before a workspace-scoped write. */\n ensureWorkspaceOpen: () => Promise<void>\n /**\n * Go into a workspace: select it (with a connection) and show it (`BlocksEnvironment.\n * openWorkspace`, where a host without a connection also switches its session).\n */\n openWorkspace: (workspaceId: string, options?: { name?: string }) => Promise<void>\n}\n\nconst keptOpenByHost = async () => {}\n\n/** The signed-in user of a host's own session, from its login profile. */\nfunction sessionUser(arbi: ReturnType<typeof useArbi>): ArbiUser | null {\n if (!arbi.isLoggedIn) return null\n const me = arbi.user.identity()\n const profile = arbi.user.profile()\n if (!me) return null\n return profile\n ? userFromProfile(profile, me.externalId)\n : { name: (me.email ?? '').split('@')[0], email: me.email ?? '', externalId: me.externalId }\n}\n\n/**\n * The workspace for a connected kit: the sign-in layer's (`defaultHost`) when there is one, else the\n * host's own session (an app whose host config has its `arbi` and `session` and keeps its\n * workspace open itself). So a kit runs the same in Clarum and in the ARBI app.\n */\nexport function useConnectedWorkspace(): ConnectedWorkspace {\n const connection = useContext(ConnectionContext)\n const arbi = useArbi()\n const sessionWorkspaceId = useArbiSessionState((s) => s.workspaceId)\n const live = connection ? connection.status === 'authenticated' : arbi.isLoggedIn\n const user = connection ? connection.user : live ? sessionUser(arbi) : null\n const userKey = `${user?.externalId ?? ''}|${user?.name ?? ''}|${user?.email ?? ''}`\n const { openWorkspace: showWorkspace } = useBlocksEnvironment()\n return useMemo(\n () => ({\n workspaceId: connection\n ? (connection.workspaceId ?? connection.fallbackWorkspaceId ?? null)\n : sessionWorkspaceId,\n live,\n user,\n userId: user?.externalId,\n ensureWorkspaceOpen: connection?.ensureWorkspaceOpen ?? keptOpenByHost,\n openWorkspace: async (workspaceId: string, options?: { name?: string }) => {\n if (connection) await connection.setWorkspace(workspaceId)\n showWorkspace(workspaceId, options)\n },\n }),\n // `user` is rebuilt each render without a connection: its key says when it changed.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [connection, sessionWorkspaceId, live, userKey, showWorkspace]\n )\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useConnectedWorkspace } from './chunk-
|
|
2
|
+
import { useConnectedWorkspace } from './chunk-2YCCCXYV.js';
|
|
3
3
|
import { useHost } from './chunk-T4P237N6.js';
|
|
4
4
|
import { useMemo } from 'react';
|
|
5
5
|
import { useDocuments, useTags, useConversations } from '@arbidocs/react';
|
|
@@ -57,5 +57,5 @@ function useConnectedConversations(options) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export { isListedDocument, listedDocuments, useConnectedConversations, useConnectedDocuments, useConnectedTags, useDocumentFilter, useListedDocuments };
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
61
|
-
//# sourceMappingURL=chunk-
|
|
60
|
+
//# sourceMappingURL=chunk-5JEM3BWT.js.map
|
|
61
|
+
//# sourceMappingURL=chunk-5JEM3BWT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection/workspaceData.ts"],"names":[],"mappings":";;;;;AA8CO,SAAS,iBAAiB,QAAA,EAAgD;AAC/E,EAAA,OAAO,SAAS,OAAA,KAAY,OAAA;AAC9B;AAGO,SAAS,iBAAA,GAA8D;AAC5E,EAAA,OAAO,OAAA,EAAQ,CAAE,aAAA,EAAe,cAAA,IAAkB,gBAAA;AACpD;AAGO,SAAS,eAAA,CACd,WACA,MAAA,EACK;AAEL,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,MAAA,CAAO,MAA6C,CAAA;AAC3E,EAAA,OAAO,IAAA,CAAK,MAAA,KAAW,SAAA,CAAU,MAAA,GAAS,SAAA,GAAY,IAAA;AACxD;AAEA,IAAM,OAAO,MAAM,MAAA;AASnB,IAAM,QAAiB,EAAC;AAExB,SAAS,OAAA,CACP,QACA,GAAA,EACwB;AACxB,EAAA,MAAM,SAAS,MAAA,IAAU,GAAA;AACzB,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,IAAS,KAAA;AAC7B,EAAA,MAAM,OAAA,GAAU,MAAA,GAAS,MAAA,CAAO,OAAA,GAAU,GAAA,CAAI,OAAA;AAC9C,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,CAAO,WAAW,OAAA,EAAQ,CAAA;AAAA,IACjD,CAAC,IAAA,EAAM,MAAA,CAAO,SAAA,EAAW,OAAO;AAAA,GAClC;AACF;AAGO,SAAS,qBAAA,GAAgE;AAC9E,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAU,GAAI,aAAa,WAAW,CAAA;AACpD,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,IAAA,IAAS,KAAA,EAA+B,QAAQ,SAAA,EAAU,CAAA;AAAA,IACzE,CAAC,MAAM,SAAS;AAAA,GAClB;AACF;AAGO,SAAS,kBAAA,GAA6D;AAC3E,EAAA,MAAM,MAAM,qBAAA,EAAsB;AAClC,EAAA,MAAM,SAAS,iBAAA,EAAkB;AACjC,EAAA,OAAO,OAAA,CAAQ,OAAO,EAAE,GAAG,KAAK,IAAA,EAAM,eAAA,CAAgB,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA,EAAE,CAAA,EAAI,CAAC,GAAA,EAAK,MAAM,CAAC,CAAA;AAC3F;AAGO,SAAS,gBAAA,GAAsD;AACpE,EAAA,MAAM,SAAA,GAAY,OAAA,EAAQ,CAAE,aAAA,EAAe,OAAA,IAAW,IAAA;AACtD,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,GAAA,GAAM,QAAQ,WAAA,IAAe,MAAA,EAAW,EAAE,OAAA,EAAS,CAAC,QAAQ,CAAA;AAClE,EAAA,OAAO,OAAA,CAAQ,QAAQ,GAAG,CAAA;AAC5B;AAMO,SAAS,0BAA0B,OAAA,EAEQ;AAChD,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,SAAQ,GAAI,gBAAA,CAAiB,eAAe,MAAA,EAAW;AAAA,IAC9E,MAAM,OAAA,EAAS;AAAA,GAChB,CAAA;AACD,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,QAAS,KAAA,EAAsC,MAAA,EAAQ,WAAW,OAAA,EAAQ,CAAA;AAAA,IACzF,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO;AAAA,GAC3B;AACF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/connection/workspaceData.ts"],"names":[],"mappings":";;;;;AA8CO,SAAS,iBAAiB,QAAA,EAAgD;AAC/E,EAAA,OAAO,SAAS,OAAA,KAAY,OAAA;AAC9B;AAGO,SAAS,iBAAA,GAA8D;AAC5E,EAAA,OAAO,OAAA,EAAQ,CAAE,aAAA,EAAe,cAAA,IAAkB,gBAAA;AACpD;AAGO,SAAS,eAAA,CACd,WACA,MAAA,EACK;AAEL,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,MAAA,CAAO,MAA6C,CAAA;AAC3E,EAAA,OAAO,IAAA,CAAK,MAAA,KAAW,SAAA,CAAU,MAAA,GAAS,SAAA,GAAY,IAAA;AACxD;AAEA,IAAM,OAAO,MAAM,MAAA;AASnB,IAAM,QAAiB,EAAC;AAExB,SAAS,OAAA,CACP,QACA,GAAA,EACwB;AACxB,EAAA,MAAM,SAAS,MAAA,IAAU,GAAA;AACzB,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,IAAS,KAAA;AAC7B,EAAA,MAAM,OAAA,GAAU,MAAA,GAAS,MAAA,CAAO,OAAA,GAAU,GAAA,CAAI,OAAA;AAC9C,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,CAAO,WAAW,OAAA,EAAQ,CAAA;AAAA,IACjD,CAAC,IAAA,EAAM,MAAA,CAAO,SAAA,EAAW,OAAO;AAAA,GAClC;AACF;AAGO,SAAS,qBAAA,GAAgE;AAC9E,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAU,GAAI,aAAa,WAAW,CAAA;AACpD,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,IAAA,IAAS,KAAA,EAA+B,QAAQ,SAAA,EAAU,CAAA;AAAA,IACzE,CAAC,MAAM,SAAS;AAAA,GAClB;AACF;AAGO,SAAS,kBAAA,GAA6D;AAC3E,EAAA,MAAM,MAAM,qBAAA,EAAsB;AAClC,EAAA,MAAM,SAAS,iBAAA,EAAkB;AACjC,EAAA,OAAO,OAAA,CAAQ,OAAO,EAAE,GAAG,KAAK,IAAA,EAAM,eAAA,CAAgB,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA,EAAE,CAAA,EAAI,CAAC,GAAA,EAAK,MAAM,CAAC,CAAA;AAC3F;AAGO,SAAS,gBAAA,GAAsD;AACpE,EAAA,MAAM,SAAA,GAAY,OAAA,EAAQ,CAAE,aAAA,EAAe,OAAA,IAAW,IAAA;AACtD,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,GAAA,GAAM,QAAQ,WAAA,IAAe,MAAA,EAAW,EAAE,OAAA,EAAS,CAAC,QAAQ,CAAA;AAClE,EAAA,OAAO,OAAA,CAAQ,QAAQ,GAAG,CAAA;AAC5B;AAMO,SAAS,0BAA0B,OAAA,EAEQ;AAChD,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,SAAQ,GAAI,gBAAA,CAAiB,eAAe,MAAA,EAAW;AAAA,IAC9E,MAAM,OAAA,EAAS;AAAA,GAChB,CAAA;AACD,EAAA,OAAO,OAAA;AAAA,IACL,OAAO,EAAE,IAAA,EAAM,QAAS,KAAA,EAAsC,MAAA,EAAQ,WAAW,OAAA,EAAQ,CAAA;AAAA,IACzF,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO;AAAA,GAC3B;AACF","file":"chunk-5JEM3BWT.js","sourcesContent":["/**\n * The open workspace's documents, tags and conversations for the connected kits. Each kit reads them\n * through the `@arbidocs/react` hooks: the documents from `useDocuments` (read once, progressively,\n * then patched in place by every write and event, so a kit never re-reads it) and the conversations\n * from `useConversations` (the one list every host and kit shares, patched by its writers). A host\n * that already keeps tags live in its own cache gives them once, as a hook in the host\n * configuration's `workspaceData`, so the kits show the same list and nothing is fetched twice.\n */\n\nimport { useMemo } from 'react'\nimport { useConversations, useDocuments, useTags } from '@arbidocs/react'\nimport { useConnectedWorkspace } from './ConnectionProvider'\nimport { useHost } from '../provider/host'\n\nexport type ConnectedDocument = NonNullable<ReturnType<typeof useDocuments>['data']>[number]\nexport type ConnectedTag = NonNullable<ReturnType<typeof useTags>['data']>[number]\nexport type ConnectedConversationRow = NonNullable<\n ReturnType<typeof useConversations>['data']\n>[number]\n\n/**\n * A list the host keeps: its rows, whether it has arrived, and how to read it again (absent: the\n * host keeps it current itself, so a kit never re-reads it).\n */\nexport interface ConnectedList<T> {\n data: T[] | undefined\n isFetched: boolean\n refetch?: () => unknown\n}\n\n/** The lists a host keeps live for the open workspace, as hooks (each fixed for the host's life). */\nexport interface ConnectedWorkspaceData {\n useTags?: () => ConnectedList<ConnectedTag>\n /**\n * Which documents the browsing kits list: Files, the dashboard's recent files and the file\n * pickers (a workflow's documents, cross-references). Kits that act on given ids still see every\n * document. Default: `isListedDocument` (all but skill files); a host narrowing it further\n * usually keeps that too: `(d) => isListedDocument(d) && mine(d)`.\n */\n documentFilter?: (document: ConnectedDocument) => boolean\n}\n\n/**\n * The default `documentFilter`: every document but a skill's files (`wp_type: 'skill'`, under\n * `skills/<name>/`). They are how a skill is stored; the skills library shows them as skills.\n */\nexport function isListedDocument(document: { wp_type?: string | null }): boolean {\n return document.wp_type !== 'skill'\n}\n\n/** The host's `documentFilter` (default `isListedDocument`). */\nexport function useDocumentFilter(): (document: ConnectedDocument) => boolean {\n return useHost().workspaceData?.documentFilter ?? isListedDocument\n}\n\n/** Keep the listed documents; the same array when nothing is left out (stable for memos). */\nexport function listedDocuments<D>(\n documents: D[],\n filter: (document: ConnectedDocument) => boolean\n): D[] {\n // A kit's own row type is the same document list (a view of `DocResponse`).\n const kept = documents.filter(filter as unknown as (document: D) => boolean)\n return kept.length === documents.length ? documents : kept\n}\n\nconst NONE = () => undefined\n\nexport interface ConnectedListResult<T> {\n data: T[]\n loaded: boolean\n /** Read the list again after a change made here; absent when the host keeps it current. */\n refetch?: () => unknown\n}\n\nconst EMPTY: never[] = []\n\nfunction useList<T>(\n hosted: ConnectedList<T> | undefined,\n own: { data?: T[]; isFetched: boolean; refetch: () => unknown }\n): ConnectedListResult<T> {\n const source = hosted ?? own\n const data = source.data ?? (EMPTY as T[])\n const refetch = hosted ? hosted.refetch : own.refetch\n return useMemo(\n () => ({ data, loaded: source.isFetched, refetch }),\n [data, source.isFetched, refetch]\n )\n}\n\n/** The open workspace's documents (`useDocuments`: the one list every host and kit shares). */\nexport function useConnectedDocuments(): ConnectedListResult<ConnectedDocument> {\n const { workspaceId } = useConnectedWorkspace()\n const { data, isFetched } = useDocuments(workspaceId)\n return useMemo(\n () => ({ data: data ?? (EMPTY as ConnectedDocument[]), loaded: isFetched }),\n [data, isFetched]\n )\n}\n\n/** The open workspace's documents a person browses (the host's `documentFilter`). */\nexport function useListedDocuments(): ConnectedListResult<ConnectedDocument> {\n const all = useConnectedDocuments()\n const filter = useDocumentFilter()\n return useMemo(() => ({ ...all, data: listedDocuments(all.data, filter) }), [all, filter])\n}\n\n/** The open workspace's tags: the host's list when it gives one, else read here. */\nexport function useConnectedTags(): ConnectedListResult<ConnectedTag> {\n const useHosted = useHost().workspaceData?.useTags ?? NONE\n const hosted = useHosted()\n const { workspaceId } = useConnectedWorkspace()\n const own = useTags(workspaceId ?? undefined, { enabled: !hosted })\n return useList(hosted, own)\n}\n\n/**\n * The open workspace's conversations (threads and tasks): the shared list (`live`: re-read while\n * shown, as a run moves on by itself).\n */\nexport function useConnectedConversations(options?: {\n live?: boolean\n}): ConnectedListResult<ConnectedConversationRow> {\n const { workspaceId } = useConnectedWorkspace()\n const { data, isFetched, refetch } = useConversations(workspaceId ?? undefined, {\n live: options?.live,\n })\n return useMemo(\n () => ({ data: data ?? (EMPTY as ConnectedConversationRow[]), loaded: isFetched, refetch }),\n [data, isFetched, refetch]\n )\n}\n"]}
|