@arbidocs/react 0.4.11 → 0.4.13

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/artifacts/redline-engine.ts","../../src/artifacts/useRedline.ts","../../src/artifacts/versions.ts","../../src/artifacts/useArtifactEditSession.ts","../../src/artifacts/useArtifactText.ts","../../src/artifacts/useArtifactSession.ts","../../src/artifacts/renderArtifactMarkdown.tsx","../../src/artifacts/useStreamedArtifact.ts"],"names":["useState","useCallback","useRef","useEffect","content","useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import {\n buildHybridRedlineMarkdown,\n buildHybridRedlineWithRegions,\n revertRedlineRegion,\n type RedlineWithRegions,\n} from './redline-diff'\n\n/**\n * Where a redline is computed. The default runs on the calling thread; a host with large\n * documents passes an engine backed by a Web Worker (for example a Comlink proxy exposing the same\n * three functions) so typing never waits on a diff.\n */\nexport interface RedlineEngine {\n buildRedline(baseText: string, compareText: string): string | Promise<string>\n buildRedlineWithRegions(\n baseText: string,\n compareText: string\n ): RedlineWithRegions | Promise<RedlineWithRegions>\n revertRegion(baseText: string, compareText: string, regionId: string): string | Promise<string>\n}\n\n/** Main-thread engine: the pure functions of `redline-diff`. */\nexport const mainThreadRedlineEngine: RedlineEngine = {\n buildRedline: buildHybridRedlineMarkdown,\n buildRedlineWithRegions: buildHybridRedlineWithRegions,\n revertRegion: revertRedlineRegion,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { RedlineRegion } from './redline-diff'\nimport { normalizeMarkdown } from './normalize-markdown'\nimport { mainThreadRedlineEngine, type RedlineEngine } from './redline-engine'\n\n/** What a redline view can show. Mirrors the status parts of `@arbidocs/blocks/artifacts`. */\nexport type RedlineState =\n | { kind: 'idle' }\n | { kind: 'computing' }\n | { kind: 'ready'; markdown: string; regions: RedlineRegion[] }\n | { kind: 'identical' }\n | { kind: 'unavailable' }\n\nexport interface UseRedlineOptions {\n /** The older side. `null` means the text could not be loaded; `undefined` means not chosen. */\n baseText: string | null | undefined\n /** The newer side (a loaded version, or the live edit buffer). */\n compareText: string | null | undefined\n /** Either text is still being fetched. */\n isLoading?: boolean\n /** Tag every change with a stable id so a view can offer per-change undo. */\n withRegions?: boolean\n /** Defaults to the main thread; pass a worker-backed engine for big documents. */\n engine?: RedlineEngine\n}\n\nexport interface UseRedlineResult {\n state: RedlineState\n /** Undo one change: resolves with the compare text rebuilt without it (null if nothing changed). */\n revertRegion: (regionId: string) => Promise<string | null>\n}\n\n/**\n * Track-changes between two texts. Stale results are dropped when the inputs change mid-compute,\n * and a failed diff reports `unavailable` instead of throwing into the render.\n */\nexport function useRedline({\n baseText,\n compareText,\n isLoading = false,\n withRegions = false,\n engine = mainThreadRedlineEngine,\n}: UseRedlineOptions): UseRedlineResult {\n const [state, setState] = useState<RedlineState>({ kind: 'idle' })\n const requestIdRef = useRef(0)\n\n useEffect(() => {\n if (baseText === undefined || compareText === undefined) {\n setState({ kind: 'idle' })\n return\n }\n if (isLoading) {\n setState({ kind: 'computing' })\n return\n }\n if (baseText === null || compareText === null) {\n setState({ kind: 'unavailable' })\n return\n }\n if (\n baseText === compareText ||\n normalizeMarkdown(baseText) === normalizeMarkdown(compareText)\n ) {\n setState({ kind: 'identical' })\n return\n }\n\n const id = ++requestIdRef.current\n let cancelled = false\n setState({ kind: 'computing' })\n Promise.resolve(\n withRegions\n ? engine.buildRedlineWithRegions(baseText, compareText)\n : Promise.resolve(engine.buildRedline(baseText, compareText)).then((markdown) => ({\n markdown,\n regions: [] as RedlineRegion[],\n }))\n )\n .then((result) => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'ready', markdown: result.markdown, regions: result.regions })\n })\n .catch(() => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'unavailable' })\n })\n return () => {\n cancelled = true\n }\n }, [baseText, compareText, isLoading, withRegions, engine])\n\n // The latest texts, so `revertRegion` stays referentially stable while the user types.\n const latest = useRef({ baseText, compareText })\n useEffect(() => {\n latest.current = { baseText, compareText }\n }, [baseText, compareText])\n\n const revertRegion = useCallback(\n async (regionId: string): Promise<string | null> => {\n const { baseText: base, compareText: compare } = latest.current\n if (!base || !compare) return null\n try {\n const next = await engine.revertRegion(base, compare, regionId)\n return next !== normalizeMarkdown(compare) ? next : null\n } catch {\n return null\n }\n },\n [engine]\n )\n\n return useMemo(() => ({ state, revertRegion }), [state, revertRegion])\n}\n","/**\n * Version lineage of an artifact. Every save creates a NEW document whose `parent_ext_id` is the\n * version it was saved from, so a lineage is a tree (a save from an old version is a deliberate\n * branch). Computed from a document list the host already has; no extra request.\n */\n\nimport { repairParsedTitle, unescapeMarkdown } from '../ai/stored-markdown'\n\n/** The fields of a workspace document the lineage needs (structurally a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n parent_ext_id?: string | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n id: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** The version this one was saved from. */\n parentId?: string | null\n}\n\n/**\n * The whole lineage of `docId` (root first, then oldest to newest), or `[]` when the document is\n * not in `docs`. Cycle-safe.\n */\nexport function buildVersionChain<T extends VersionedDoc>(\n docs: readonly T[],\n docId: string | null | undefined\n): T[] {\n if (!docId) return []\n const byId = new Map<string, T>()\n for (const d of docs) if (d.external_id) byId.set(d.external_id, d)\n\n const current = byId.get(docId)\n if (!current) return []\n\n let root = current\n const up = new Set<string>()\n while (\n root.parent_ext_id &&\n byId.has(root.parent_ext_id) &&\n root.external_id &&\n !up.has(root.external_id)\n ) {\n up.add(root.external_id)\n root = byId.get(root.parent_ext_id) as T\n }\n\n const byParent = new Map<string, T[]>()\n for (const d of docs) {\n if (d.parent_ext_id) {\n const siblings = byParent.get(d.parent_ext_id) ?? []\n siblings.push(d)\n byParent.set(d.parent_ext_id, siblings)\n }\n }\n const out: T[] = []\n const visited = new Set<string>()\n const walk = (d: T): void => {\n if (!d.external_id || visited.has(d.external_id)) return\n visited.add(d.external_id)\n out.push(d)\n for (const child of byParent.get(d.external_id) ?? []) walk(child)\n }\n walk(root)\n\n out.sort((a, b) => (a.created_at ?? '').localeCompare(b.created_at ?? ''))\n return out\n}\n\n/** The lineage of `docId` as plain version rows. */\nexport function toArtifactVersions(chain: readonly VersionedDoc[]): ArtifactVersion[] {\n return chain.flatMap((d) =>\n d.external_id\n ? [\n {\n id: d.external_id,\n name: d.file_name ?? '',\n createdAt: d.created_at ?? '',\n parentId: d.parent_ext_id,\n },\n ]\n : []\n )\n}\n\n/**\n * \"v2\": the 1-based position of `docId` in its lineage. `null` when there is nothing to tell apart\n * (the lineage is just this document, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n docId: string | null | undefined\n): string | null {\n if (!docId || versions.length <= 1) return null\n const index = versions.findIndex((v) => v.id === docId)\n return index === -1 ? null : `v${index + 1}`\n}\n\n/**\n * Join parsed chunks into one markdown text (blank line between chunks).\n *\n * `unescape: true` for an artifact stored from markdown: the backend's parse of a `.md` escapes\n * markdown punctuation, which `unescapeMarkdown` undoes (see its rule), and mangles its title\n * (`repairParsedTitle`). Leave it off for the parse\n * of a PDF or Word file.\n */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined,\n options?: { unescape?: boolean }\n): string {\n const text = (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n return options?.unescape ? repairParsedTitle(unescapeMarkdown(text)) : text\n}\n\n/** The backend's pattern for a document id. Anything else (a streamed draft's placeholder) is local. */\nconst DOC_ID = /^doc/\n\n/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */\nexport function isDocumentId(id: string | null | undefined): id is string {\n return !!id && DOC_ID.test(id)\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { normalizeMarkdown } from './normalize-markdown'\nimport { useRedline, type UseRedlineResult } from './useRedline'\nimport type { RedlineEngine } from './redline-engine'\n\n/** What a save reports back. `docId` is the new version when the backend already knows it. */\nexport interface ArtifactSaveResult {\n docId?: string\n /** 1-based number of the version that was just saved (1 for the first save of a draft). */\n version?: number\n}\n\nexport interface ArtifactEditSessionOptions {\n /** The artifact being edited. Changing it discards the buffer and any comparison. */\n docId: string | null | undefined\n /**\n * The saved text of the open version. `undefined` while it loads; whenever it changes the\n * baseline follows it (a version arriving from the realtime channel, a finished stream).\n */\n baseline: string | undefined\n /**\n * A new document the user types from scratch: open straight in the editor, seeded with\n * `initialContent`, instead of showing a read-only view. Read when `docId` changes.\n */\n startEditing?: boolean\n initialContent?: string\n /** The version this one was saved from. Offering \"compare with previous\" needs it. */\n parentId?: string | null\n /** Controlled comparison target. Omit for an uncontrolled one the session owns. */\n compareId?: string | null\n onCompareChange?: (id: string | null) => void\n /** The saved text of the compare target (the older side of the diff). */\n compareText?: string | null\n compareLoading?: boolean\n /** Starting a comparison opens the editor with track changes on (default true). */\n compareOpensEditor?: boolean\n /** Persist the buffer as a NEW version. Rejecting keeps the buffer so nothing is lost. */\n save: (content: string) => Promise<ArtifactSaveResult | void>\n onSaved?: (result: ArtifactSaveResult, content: string) => void\n onSaveError?: (error: unknown) => void\n /** Every buffer change (a host keeps a draft store in sync with it). */\n onContentChange?: (content: string) => void\n /** The unsaved-changes flag, for a host that warns before a panel is closed. */\n onDirtyChange?: (dirty: boolean) => void\n /** Where the diff runs. Defaults to the main thread. */\n redlineEngine?: RedlineEngine\n /** Typing is never debounced; the diff trails the buffer by this long. Default 300ms. */\n diffDelayMs?: number\n}\n\nexport interface ArtifactEditSession {\n isEditing: boolean\n /** The saved text of the open version. */\n baseline: string\n /** The text in the editor (the baseline until the first edit). */\n content: string\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n compareId: string | null\n showTrackChanges: boolean\n /** Track changes between the compare target and the (debounced) buffer. */\n redline: UseRedlineResult\n startEdit: () => void\n /** Discard the buffer and any comparison; back to the rendered view. */\n cancel: () => void\n /** Save the buffer as a new version. Resolves false when it failed (the buffer is kept). */\n save: () => Promise<boolean>\n /** The editor's `onChange`; also replaces the buffer (for example after an undo-this-change). */\n change: (markdown: string) => void\n /** The editor's `onNormalized`: adopt its canonical form as the baseline so Save does not fire. */\n normalized: (markdown: string) => void\n /** Compare with the previous version (when no id is given). */\n compare: (id?: string) => void\n stopCompare: () => void\n setShowTrackChanges: (show: boolean) => void\n /** Undo one tracked change in the buffer. */\n revertRegion: (regionId: string) => Promise<void>\n}\n\n/**\n * The state machine of an artifact edit session, with no SDK and no network: the edit buffer and\n * its baseline, the dirty flag, immutable-version saves and a track-changes comparison. A host\n * supplies the saved text and a `save` function (see `useArtifactSession` for the SDK binding).\n */\nexport function useArtifactEditSession(options: ArtifactEditSessionOptions): ArtifactEditSession {\n const {\n docId,\n baseline: loadedBaseline,\n startEditing = false,\n initialContent,\n parentId,\n compareId: controlledCompareId,\n onCompareChange,\n compareText,\n compareLoading = false,\n compareOpensEditor = true,\n save: persist,\n onSaved,\n onSaveError,\n onContentChange,\n onDirtyChange,\n redlineEngine,\n diffDelayMs = 300,\n } = options\n\n const [isEditing, setIsEditing] = useState(false)\n const [baseline, setBaseline] = useState('')\n const [buffer, setBuffer] = useState('')\n const [isSaving, setIsSaving] = useState(false)\n const [showTrackChanges, setShowTrackChanges] = useState(false)\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const controlled = controlledCompareId !== undefined\n const compareId = controlled ? controlledCompareId : ownCompareId\n\n const setCompareId = useCallback(\n (id: string | null) => {\n if (!controlled) setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [controlled, onCompareChange]\n )\n\n // The latest values for callbacks that must not change identity while the user types.\n const latest = useRef({ buffer, baseline, isEditing, initialContent })\n latest.current = { buffer, baseline, isEditing, initialContent }\n\n // The baseline follows the loaded text. A draft has none and seeds itself below.\n useEffect(() => {\n if (loadedBaseline !== undefined) setBaseline(loadedBaseline)\n }, [loadedBaseline])\n\n // Another artifact: drop stale edits and comparison. A new typed document starts in the editor.\n useEffect(() => {\n if (startEditing) {\n const seed = latest.current.initialContent ?? ''\n setIsEditing(true)\n setBaseline(seed)\n setBuffer(seed)\n } else {\n setIsEditing(false)\n setBuffer('')\n }\n setCompareId(null)\n setShowTrackChanges(false)\n // Only the identity of the artifact resets the session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId])\n\n const startEdit = useCallback(() => {\n setBuffer(latest.current.baseline)\n setIsEditing(true)\n }, [])\n\n const stopCompare = useCallback(() => {\n setCompareId(null)\n setShowTrackChanges(false)\n }, [setCompareId])\n\n const cancel = useCallback(() => {\n setIsEditing(false)\n setBuffer('')\n stopCompare()\n }, [stopCompare])\n\n const compare = useCallback(\n (id?: string) => {\n const target = id ?? parentId\n if (target) setCompareId(target)\n },\n [parentId, setCompareId]\n )\n\n // Comparing and editing are one surface: a comparison opens the editor with the diff showing,\n // like Word's Compare yields tracked changes you can keep typing through.\n const hasBaseline = baseline !== ''\n useEffect(() => {\n if (!compareId || !compareOpensEditor || !hasBaseline) return\n if (!latest.current.isEditing) startEdit()\n setShowTrackChanges(true)\n }, [compareId, compareOpensEditor, hasBaseline, startEdit])\n\n const save = useCallback(async (): Promise<boolean> => {\n // Persist the canonical spelling so the editor's gratuitous escapes never reach a version.\n const raw = latest.current.buffer\n const normalised = normalizeMarkdown(raw)\n const content = raw.endsWith('\\n') ? normalised : normalised.replace(/\\n$/, '')\n setIsSaving(true)\n try {\n const result = (await persist(content)) ?? {}\n setBaseline(content)\n setIsEditing(false)\n stopCompare()\n onSaved?.(result, content)\n return true\n } catch (error) {\n onSaveError?.(error)\n return false\n } finally {\n setIsSaving(false)\n }\n }, [persist, stopCompare, onSaved, onSaveError])\n\n const content = buffer || baseline\n const hasChanges = isEditing && !!buffer && buffer !== baseline\n useEffect(() => {\n onDirtyChange?.(hasChanges)\n return () => onDirtyChange?.(false)\n }, [hasChanges, onDirtyChange])\n\n const setContent = useCallback(\n (markdown: string) => {\n setBuffer(markdown)\n onContentChange?.(markdown)\n },\n [onContentChange]\n )\n const normalized = useCallback((markdown: string) => {\n setBaseline(markdown)\n setBuffer(markdown)\n }, [])\n\n // The diff trails the buffer so it runs on a settled text.\n const [diffContent, setDiffContent] = useState(content)\n useEffect(() => {\n const id = setTimeout(() => setDiffContent(content), diffDelayMs)\n return () => clearTimeout(id)\n }, [content, diffDelayMs])\n\n const redline = useRedline({\n baseText: compareId ? compareText : undefined,\n compareText: compareId ? diffContent || baseline : undefined,\n isLoading: compareLoading,\n withRegions: true,\n engine: redlineEngine,\n })\n const { revertRegion: revertInRedline } = redline\n const revertRegion = useCallback(\n async (regionId: string): Promise<void> => {\n const next = await revertInRedline(regionId)\n if (next !== null) setContent(next)\n },\n [revertInRedline, setContent]\n )\n\n return useMemo(\n () => ({\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n canCompare: !!parentId && !compareId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n change: setContent,\n normalized,\n compare,\n stopCompare,\n setShowTrackChanges,\n revertRegion,\n }),\n [\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n parentId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n setContent,\n normalized,\n compare,\n stopCompare,\n revertRegion,\n ]\n )\n}\n","import { useCallback, useMemo } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { flattenChunks, isDocumentId } from './versions'\n\n/**\n * Where the text of a stored artifact is:\n * - `loading`: the first request is in flight (or there is no document yet);\n * - `parsing`: the backend has not finished parsing the upload (the endpoint answers 404, 422 or\n * 500, or an empty parse, for a few seconds after an upload) and the hook is retrying;\n * - `ready`: the text is here (an empty document is `ready` with `text: null`);\n * - `error`: the retries ran out, or the request was refused (401/403).\n */\nexport type ArtifactTextStatus = 'loading' | 'parsing' | 'ready' | 'error'\n\n/** How long `useArtifactText` keeps asking while a document is still being parsed. */\nexport interface ArtifactTextRetry {\n /** Retries after the first request. Default 12. */\n attempts?: number\n /** Delay before the first retry; it grows by 1.6x each time. Default 1000 ms. */\n baseDelayMs?: number\n /** Cap for one delay. Default 5000 ms (12 retries are about 50 s in all). */\n maxDelayMs?: number\n}\n\nexport const DEFAULT_ARTIFACT_TEXT_RETRY: Required<ArtifactTextRetry> = {\n attempts: 12,\n baseDelayMs: 1000,\n maxDelayMs: 5000,\n}\n\n/** Thrown inside the query when the parse has no text yet, so that it is retried like a 500. */\nclass NotParsedYetError extends Error {\n constructor() {\n super('The document has no parsed text yet')\n }\n}\n\nconst isRefusal = (error: unknown): boolean => {\n const status = error as { status?: number; response?: { status?: number } } | null\n const code = status?.status ?? status?.response?.status\n return code === 401 || code === 403\n}\n\nexport interface ArtifactText {\n /**\n * The markdown, clean: `undefined` while `loading` or `parsing`, `null` when there is none (an\n * empty document, or `error`).\n */\n text: string | null | undefined\n /** `status` is `loading` or `parsing`. */\n isLoading: boolean\n status: ArtifactTextStatus\n /** The last request error while `parsing` or after `error`. */\n error: Error | null\n /** Ask again now (after an `error`). */\n retry: () => void\n}\n\n/**\n * The saved markdown of an artifact version (its parsed chunks, joined and unescaped).\n *\n * A freshly uploaded document is parsed asynchronously, and for roughly 3 to 20 seconds the parsed\n * content endpoint answers 404, 422 or 500 (or an empty parse). The hook therefore retries with a\n * growing delay (see `ArtifactTextRetry`) and reports `status: 'parsing'` meanwhile, so a host can\n * show \"Preparing editor...\" instead of opening an editor on an empty baseline. After the last\n * retry the status is `error`; `retry()` starts a new round.\n *\n * The text is run through `unescapeMarkdown`: an artifact is always stored from markdown, and the\n * backend's parse of a `.md` escapes its punctuation.\n */\nexport function useArtifactText(\n docId: string | null | undefined,\n options?: { enabled?: boolean; retry?: ArtifactTextRetry }\n): ArtifactText {\n const arbi = useArbi()\n const { attempts, baseDelayMs, maxDelayMs } = {\n ...DEFAULT_ARTIFACT_TEXT_RETRY,\n ...options?.retry,\n }\n // A local draft (placeholder id) has no backend document: asking for its text would be a 422.\n const enabled = (options?.enabled ?? true) && isDocumentId(docId) && arbi.hasWorkspace\n const query = useQuery({\n // Under the shared `parsedDoc` key, so a document's invalidation reaches it too.\n queryKey: [...arbiQueryKeys.parsedDoc(docId ?? '', 'marker'), 'artifact-text'] as const,\n queryFn: async () => {\n const parsed = (await arbi.documents.getParsedContent(docId as string, 'marker')) as {\n chunks?: { content?: string | null }[]\n }\n if (!parsed.chunks?.some((c) => c.content?.trim())) throw new NotParsedYetError()\n return flattenChunks(parsed.chunks, { unescape: true })\n },\n enabled,\n retry: (failureCount, error) => !isRefusal(error) && failureCount < attempts,\n retryDelay: (failureCount) => Math.min(baseDelayMs * 1.6 ** failureCount, maxDelayMs),\n })\n\n const { refetch } = query\n const retry = useCallback(() => void refetch(), [refetch])\n\n return useMemo<ArtifactText>(() => {\n const error = query.error\n const neverParsed = error instanceof NotParsedYetError\n let status: ArtifactTextStatus = 'loading'\n if (!enabled) status = 'loading'\n else if (query.isSuccess || (query.isError && neverParsed)) status = 'ready'\n else if (query.isError) status = 'error'\n else if (query.failureCount > 0) status = 'parsing'\n const text = !enabled\n ? undefined\n : query.isSuccess\n ? query.data\n : status === 'ready' || status === 'error'\n ? null\n : undefined\n return {\n text,\n isLoading: enabled && (status === 'loading' || status === 'parsing'),\n status,\n error: status === 'ready' ? null : (error ?? query.failureReason ?? null),\n retry,\n }\n }, [\n enabled,\n query.isSuccess,\n query.isError,\n query.data,\n query.error,\n query.failureCount,\n query.failureReason,\n retry,\n ])\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys, useDocuments } from '../hooks'\nimport { useArtifactText, type ArtifactTextStatus } from './useArtifactText'\nimport {\n buildVersionChain,\n isDocumentId,\n toArtifactVersions,\n versionLabel,\n type ArtifactVersion,\n} from './versions'\nimport {\n useArtifactEditSession,\n type ArtifactEditSession,\n type ArtifactEditSessionOptions,\n type ArtifactSaveResult,\n} from './useArtifactEditSession'\n\n/** The version lineage of an artifact in a workspace, oldest first. */\nexport function useArtifactVersions(\n workspaceId: string | undefined,\n docId: string | null | undefined\n): ArtifactVersion[] {\n const { data: documents } = useDocuments(workspaceId)\n return useMemo(\n () => toArtifactVersions(buildVersionChain(documents ?? [], docId)),\n [documents, docId]\n )\n}\n\nexport interface SaveArtifactVersionInput {\n /** File name of the new version (`.md` is added when missing). */\n title: string\n content: string\n /** The version this one is saved from; omit for a first version. */\n parentId?: string | null\n /** The processing config (auto-title, parsing) to run the upload with. */\n configId?: string | null\n /** `artifact` (default) for AI-style drafts; `source` for a document the user typed. */\n wpType?: 'artifact' | 'source'\n}\n\n/**\n * Save markdown as a NEW immutable version (a child document of `parentId`) and refresh the\n * workspace document list so the version list picks it up. The id of the new version is often not\n * known yet (the document is parsed asynchronously); it then arrives through the list.\n */\nexport function useSaveArtifactVersion() {\n const arbi = useArbi()\n const queryClient = useQueryClient()\n return useMutation<\n ArtifactSaveResult,\n Error,\n SaveArtifactVersionInput & { workspaceId?: string }\n >({\n mutationFn: async ({ title, content, parentId, configId, wpType, workspaceId }) => {\n // The backend classifies uploads by extension: a title without one is silently dropped.\n const fileName = /\\.md$/i.test(title) ? title : `${title}.md`\n const result = await arbi.documents.uploadFile(\n new Blob([content], { type: 'text/markdown' }),\n fileName,\n {\n wpType: wpType ?? 'artifact',\n parentExtId: parentId ?? undefined,\n configExtId: configId ?? undefined,\n }\n )\n if (workspaceId) {\n await queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documents(workspaceId) })\n }\n return { docId: result.doc_ext_ids?.[0] }\n },\n })\n}\n\nexport interface ArtifactSessionOptions extends Pick<\n ArtifactEditSessionOptions,\n | 'onSaved'\n | 'onSaveError'\n | 'onCompareChange'\n | 'compareId'\n | 'compareOpensEditor'\n | 'redlineEngine'\n | 'onDirtyChange'\n> {\n workspaceId: string | undefined\n /**\n * The open version, or the placeholder id of an unsaved local draft (anything that is not a\n * backend document id, i.e. does not start with `doc`).\n */\n docId: string | null | undefined\n /**\n * The text of a local draft (nothing is fetched for it). The FIRST save uploads it as a real\n * document with no parent and the session switches to the new id; later saves chain from it.\n */\n draftContent?: string\n /** Name for saved versions. Defaults to the open version's file name, else \"Untitled\". */\n title?: string\n /** Processing config for saved versions. */\n configId?: string | null\n}\n\n/** Everything `ArtifactEditor` (`@arbidocs/blocks/artifacts`) takes from a session, flat. */\nexport interface ArtifactSessionView {\n content: string\n isEditing: boolean\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n comparing: boolean\n compareId: string | null\n showTrackChanges: boolean\n versions: ArtifactVersion[]\n currentVersionId: string\n onStartEdit: () => void\n onCancel: () => void\n onSave: () => void\n onCompare: () => void\n onStopCompare: () => void\n onToggleTrackChanges: () => void\n /**\n * Whether the text is ready. `ArtifactEditor` renders \"Preparing editor...\" while it is\n * `loading` or `parsing` (a fresh upload is parsed for a few seconds) and an error with Retry.\n */\n status: ArtifactTextStatus\n /** Ask for the text again after an `error`. */\n onRetry: () => void\n}\n\nexport interface ArtifactSession extends ArtifactEditSession {\n /** The open document: the new real id once a local draft has been saved. */\n docId: string | null | undefined\n /** The open version is an unsaved local draft (no backend document yet). */\n isLocal: boolean\n isLoading: boolean\n /** See `ArtifactTextStatus`. */\n status: ArtifactTextStatus\n versions: ArtifactVersion[]\n /** \"v2\" for any version in the lineage. */\n labelOf: (id: string | null | undefined) => string | null\n /** Props for `<ArtifactEditor>`. */\n view: ArtifactSessionView\n /** Props for `<ArtifactMarkdownEditor>` (`@arbidocs/blocks/artifacts/editor`). */\n editorProps: {\n markdown: string\n onChange: (markdown: string) => void\n onNormalized: (markdown: string) => void\n }\n /** Props for `<ArtifactRedlineView>`. */\n redlineProps: {\n state: ArtifactEditSession['redline']['state']\n onRevert: (regionId: string) => void\n }\n}\n\n/**\n * Edit an artifact through the SDK: load it, edit it, save it as a new version, list its versions\n * and compare any two with track changes. Needs an `<ArbiProvider>` and a selected workspace.\n *\n * ```tsx\n * const session = useArtifactSession({ workspaceId, docId, onSaved: ({ docId }) => docId && open(docId) })\n * <ArtifactEditor {...session.view} onOpenVersion={open}\n * editor={<ArtifactMarkdownEditor {...session.editorProps} />}\n * redline={<ArtifactRedlineView {...session.redlineProps} />} />\n * ```\n */\nexport function useArtifactSession(options: ArtifactSessionOptions): ArtifactSession {\n const {\n workspaceId,\n docId: hostDocId,\n draftContent,\n title,\n configId,\n compareId,\n onCompareChange,\n onSaved,\n ...passthrough\n } = options\n // A saved local draft becomes this real document; another host docId resets it.\n const [saved, setSaved] = useState<{\n forId: string | null | undefined\n id: string\n text: string\n } | null>(null)\n const adopted = saved && saved.forId === hostDocId ? saved : null\n const docId = adopted?.id ?? hostDocId\n const isLocal = !isDocumentId(docId)\n\n // Owned here (not in the edit session) because the compare target's text must be loaded first.\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const activeCompareId = compareId === undefined ? ownCompareId : compareId\n const changeCompare = useCallback(\n (id: string | null) => {\n setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [onCompareChange]\n )\n\n const { text, isLoading, status, retry } = useArtifactText(docId)\n const versions = useArtifactVersions(workspaceId, isLocal ? null : docId)\n const { text: compareText, isLoading: compareLoading } = useArtifactText(activeCompareId, {\n enabled: !!activeCompareId,\n })\n const saveVersion = useSaveArtifactVersion()\n const current = versions.find((v) => v.id === docId)\n\n const save = useCallback(\n async (content: string) => {\n const result = await saveVersion.mutateAsync({\n title: title ?? current?.name ?? 'Untitled',\n content,\n parentId: isLocal ? null : docId,\n configId,\n workspaceId,\n })\n return { ...result, version: isLocal ? 1 : versions.length + 1 }\n },\n [saveVersion, title, current?.name, isLocal, docId, configId, workspaceId, versions.length]\n )\n\n const handleSaved = useCallback(\n (result: ArtifactSaveResult, content: string) => {\n // A host that keeps passing the local draft's placeholder id: follow every save to the real\n // document it created (the first save creates version 1, later ones chain from it).\n if (!isDocumentId(hostDocId) && result.docId)\n setSaved({ forId: hostDocId, id: result.docId, text: content })\n onSaved?.(result, content)\n },\n [hostDocId, onSaved]\n )\n\n const session = useArtifactEditSession({\n ...passthrough,\n docId,\n // A local draft has only its own text; a just-saved one shows what was saved until the parsed\n // text of the new document arrives.\n baseline: text ?? (isLocal ? draftContent : adopted?.text),\n parentId: current?.parentId,\n compareId: activeCompareId,\n onCompareChange: changeCompare,\n compareText,\n compareLoading,\n save,\n onSaved: handleSaved,\n })\n\n const { redline } = session\n return useMemo<ArtifactSession>(\n () => ({\n ...session,\n docId,\n isLocal,\n isLoading,\n status,\n versions,\n labelOf: (id) => versionLabel(versions, id),\n view: {\n content: session.baseline,\n isEditing: session.isEditing,\n hasChanges: session.hasChanges,\n isSaving: session.isSaving,\n canCompare: session.canCompare,\n comparing: !!session.compareId,\n compareId: session.compareId,\n showTrackChanges: session.showTrackChanges,\n versions,\n currentVersionId: docId ?? '',\n onStartEdit: session.startEdit,\n onCancel: session.cancel,\n onSave: () => void session.save(),\n onCompare: () => session.compare(),\n onStopCompare: session.stopCompare,\n onToggleTrackChanges: () => session.setShowTrackChanges(!session.showTrackChanges),\n // A local draft has its text already: it is ready.\n status: isLocal ? 'ready' : status,\n onRetry: retry,\n },\n editorProps: {\n markdown: session.content,\n onChange: session.change,\n onNormalized: session.normalized,\n },\n redlineProps: {\n state: redline.state,\n onRevert: (regionId) => void session.revertRegion(regionId),\n },\n }),\n [session, redline, isLoading, status, retry, isLocal, versions, docId]\n )\n}\n","import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react'\nimport { MarkdownRenderer } from '../ai/MarkdownRenderer'\n\n/** The `<del>` / `<ins>` renderers `ArtifactRedlineView` hands to a markdown renderer. */\nexport interface ArtifactRedlineComponents {\n del: FC<ComponentPropsWithoutRef<'del'> & { 'data-cid'?: string }>\n ins: FC<ComponentPropsWithoutRef<'ins'> & { 'data-cid'?: string }>\n}\n\n/**\n * The kit's markdown renderer as the `renderMarkdown` slot of `ArtifactEditor` and\n * `ArtifactRedlineView`: full markdown (tables, lists, code) plus the raw `<del>` / `<ins>` tags\n * of a redline.\n */\nexport function renderArtifactMarkdown(\n markdown: string,\n components?: ArtifactRedlineComponents\n): ReactNode {\n return <MarkdownRenderer components={components}>{markdown}</MarkdownRenderer>\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { ArtifactEvent } from '../ai/engine'\nimport { cleanDraftMarkdown } from '../ai/stored-markdown'\nimport { useSaveArtifactVersion } from './useArtifactSession'\nimport { isDocumentId } from './versions'\nimport { useArtifactText, type ArtifactTextRetry } from './useArtifactText'\n\n/**\n * Where a drafted artifact is in its STREAM -> PERSIST -> EDIT life:\n * - `streaming`: the agent is still working (or has produced nothing final): show the live canvas;\n * - `persisting`: the finished draft is being stored as version 1 of the artifact;\n * - `parsing`: stored; the backend is still parsing it, so there is no editable text yet;\n * - `ready`: the text is readable: mount the editor on `docId`;\n * - `error`: storing failed or the parse never produced text (`retry()` starts over).\n */\nexport type StreamedArtifactPhase = 'streaming' | 'persisting' | 'parsing' | 'ready' | 'error'\n\nexport interface UseStreamedArtifactOptions {\n /** The artifacts of the agent run (`useConnectedAiTask().artifacts`). */\n artifacts: ArtifactEvent[]\n workspaceId: string | undefined\n /**\n * The run has stopped: not busy and not failed. Nothing is stored before this, so a draft that\n * is still streaming is never persisted half-written.\n */\n settled: boolean\n /** Make the stored markdown from the streamed content. Defaults to `cleanDraftMarkdown`. */\n clean?: (streamed: string) => string\n /** Processing config for the stored version. */\n configId?: string | null\n /** How long to wait for the parse (see `useArtifactText`). */\n parseRetry?: ArtifactTextRetry\n}\n\nexport interface StreamedArtifact {\n phase: StreamedArtifactPhase\n /** The finished streamed artifact (its `title` names the stored versions). */\n artifact: ArtifactEvent | undefined\n /** The backend document to edit, once there is one (while `parsing` and `ready`). */\n docId: string | undefined\n error: Error | null\n /** After an `error`: store again or ask for the parse again. */\n retry: () => void\n}\n\n/**\n * The lifecycle of an agent-drafted artifact, so a host passes the stream and renders the phase.\n *\n * While the agent streams, the draft lives only on the canvas. Once the run is `settled` and the\n * draft is complete, a draft that is not yet a backend document is cleaned (`cleanDraftMarkdown`)\n * and stored ONCE as the artifact's first version (`wpType: 'artifact'`); a draft that already is a\n * backend document passes through. The hook then waits for the parse (`useArtifactText`, which\n * retries) and reports `ready` with the `docId` to open in an editor.\n *\n * Needs an `<ArbiProvider>` and a workspace. `@arbidocs/blocks/connect` has the whole thing as a\n * component (`StreamedArtifact`).\n */\nexport function useStreamedArtifact({\n artifacts,\n workspaceId,\n settled,\n clean = cleanDraftMarkdown,\n configId,\n parseRetry,\n}: UseStreamedArtifactOptions): StreamedArtifact {\n const artifact = artifacts.find((a) => a.is_complete)\n const { mutateAsync } = useSaveArtifactVersion()\n const [saved, setSaved] = useState<{ content: string; docId: string } | null>(null)\n const [saveError, setSaveError] = useState<Error | null>(null)\n const [attempt, setAttempt] = useState(0)\n const started = useRef<string | null>(null)\n\n const content = artifact?.content ?? ''\n const title = artifact?.title ?? 'Draft'\n const passThrough = !!artifact && isDocumentId(artifact.doc_ext_id)\n const needsSave = settled && !!artifact && !passThrough && !!content.trim() && !!workspaceId\n\n useEffect(() => {\n const key = `${attempt}:${content}`\n if (!needsSave || started.current === key) return\n started.current = key\n setSaveError(null)\n mutateAsync({\n title,\n content: clean(content),\n workspaceId,\n configId,\n wpType: 'artifact',\n })\n .then((r) => {\n if (r.docId) setSaved({ content, docId: r.docId })\n else setSaveError(new Error('The draft was stored but the server returned no document id'))\n })\n .catch((e: unknown) => setSaveError(e instanceof Error ? e : new Error(String(e))))\n // `clean` is deliberately not a dependency: a new function identity must not store twice.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [needsSave, content, title, workspaceId, configId, attempt, mutateAsync])\n\n const docId = !artifact\n ? undefined\n : passThrough\n ? artifact.doc_ext_id\n : saved?.content === content\n ? saved.docId\n : undefined\n\n const text = useArtifactText(docId, { enabled: settled, retry: parseRetry })\n const { retry: retryText } = text\n\n const retry = useCallback(() => {\n if (saveError) setAttempt((n) => n + 1)\n else retryText()\n }, [saveError, retryText])\n\n let phase: StreamedArtifactPhase\n if (!settled || !artifact) phase = 'streaming'\n else if (saveError) phase = 'error'\n else if (!docId) phase = needsSave ? 'persisting' : 'streaming'\n else if (text.status === 'ready' && text.text) phase = 'ready'\n else if (text.status === 'error' || text.status === 'ready') phase = 'error'\n else phase = 'parsing'\n\n const error =\n phase !== 'error'\n ? null\n : (saveError ?? text.error ?? new Error('The document has no text to edit'))\n return { phase, artifact, docId, error, retry }\n}\n"]}
1
+ {"version":3,"sources":["../../src/artifacts/redline-engine.ts","../../src/artifacts/useRedline.ts","../../src/artifacts/versions.ts","../../src/artifacts/useArtifactEditSession.ts","../../src/artifacts/useArtifactText.ts","../../src/artifacts/useArtifactSession.ts","../../src/artifacts/renderArtifactMarkdown.tsx","../../src/artifacts/useStreamedArtifact.ts"],"names":["useState","useCallback","useRef","useEffect","content","useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import {\n buildHybridRedlineMarkdown,\n buildHybridRedlineWithRegions,\n revertRedlineRegion,\n type RedlineWithRegions,\n} from './redline-diff'\n\n/**\n * Where a redline is computed. The default runs on the calling thread; a host with large\n * documents passes an engine backed by a Web Worker (for example a Comlink proxy exposing the same\n * three functions) so typing never waits on a diff.\n */\nexport interface RedlineEngine {\n buildRedline(baseText: string, compareText: string): string | Promise<string>\n buildRedlineWithRegions(\n baseText: string,\n compareText: string\n ): RedlineWithRegions | Promise<RedlineWithRegions>\n revertRegion(baseText: string, compareText: string, regionId: string): string | Promise<string>\n}\n\n/** Main-thread engine: the pure functions of `redline-diff`. */\nexport const mainThreadRedlineEngine: RedlineEngine = {\n buildRedline: buildHybridRedlineMarkdown,\n buildRedlineWithRegions: buildHybridRedlineWithRegions,\n revertRegion: revertRedlineRegion,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { RedlineRegion } from './redline-diff'\nimport { normalizeMarkdown } from './normalize-markdown'\nimport { mainThreadRedlineEngine, type RedlineEngine } from './redline-engine'\n\n/** What a redline view can show. Mirrors the status parts of `@arbidocs/blocks/artifacts`. */\nexport type RedlineState =\n | { kind: 'idle' }\n | { kind: 'computing' }\n | { kind: 'ready'; markdown: string; regions: RedlineRegion[] }\n | { kind: 'identical' }\n | { kind: 'unavailable' }\n\nexport interface UseRedlineOptions {\n /** The older side. `null` means the text could not be loaded; `undefined` means not chosen. */\n baseText: string | null | undefined\n /** The newer side (a loaded version, or the live edit buffer). */\n compareText: string | null | undefined\n /** Either text is still being fetched. */\n isLoading?: boolean\n /** Tag every change with a stable id so a view can offer per-change undo. */\n withRegions?: boolean\n /** Defaults to the main thread; pass a worker-backed engine for big documents. */\n engine?: RedlineEngine\n}\n\nexport interface UseRedlineResult {\n state: RedlineState\n /** Undo one change: resolves with the compare text rebuilt without it (null if nothing changed). */\n revertRegion: (regionId: string) => Promise<string | null>\n}\n\n/**\n * Track-changes between two texts. Stale results are dropped when the inputs change mid-compute,\n * and a failed diff reports `unavailable` instead of throwing into the render.\n */\nexport function useRedline({\n baseText,\n compareText,\n isLoading = false,\n withRegions = false,\n engine = mainThreadRedlineEngine,\n}: UseRedlineOptions): UseRedlineResult {\n const [state, setState] = useState<RedlineState>({ kind: 'idle' })\n const requestIdRef = useRef(0)\n\n useEffect(() => {\n if (baseText === undefined || compareText === undefined) {\n setState({ kind: 'idle' })\n return\n }\n if (isLoading) {\n setState({ kind: 'computing' })\n return\n }\n if (baseText === null || compareText === null) {\n setState({ kind: 'unavailable' })\n return\n }\n if (\n baseText === compareText ||\n normalizeMarkdown(baseText) === normalizeMarkdown(compareText)\n ) {\n setState({ kind: 'identical' })\n return\n }\n\n const id = ++requestIdRef.current\n let cancelled = false\n setState({ kind: 'computing' })\n Promise.resolve(\n withRegions\n ? engine.buildRedlineWithRegions(baseText, compareText)\n : Promise.resolve(engine.buildRedline(baseText, compareText)).then((markdown) => ({\n markdown,\n regions: [] as RedlineRegion[],\n }))\n )\n .then((result) => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'ready', markdown: result.markdown, regions: result.regions })\n })\n .catch(() => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'unavailable' })\n })\n return () => {\n cancelled = true\n }\n }, [baseText, compareText, isLoading, withRegions, engine])\n\n // The latest texts, so `revertRegion` stays referentially stable while the user types.\n const latest = useRef({ baseText, compareText })\n useEffect(() => {\n latest.current = { baseText, compareText }\n }, [baseText, compareText])\n\n const revertRegion = useCallback(\n async (regionId: string): Promise<string | null> => {\n const { baseText: base, compareText: compare } = latest.current\n if (!base || !compare) return null\n try {\n const next = await engine.revertRegion(base, compare, regionId)\n return next !== normalizeMarkdown(compare) ? next : null\n } catch {\n return null\n }\n },\n [engine]\n )\n\n return useMemo(() => ({ state, revertRegion }), [state, revertRegion])\n}\n","/**\n * Version lineage of an artifact. Every save creates a NEW document whose `parent_ext_id` is the\n * version it was saved from, so a lineage is a tree (a save from an old version is a deliberate\n * branch). Computed from a document list the host already has; no extra request.\n */\n\nimport { repairParsedStructure, repairParsedTitle, unescapeMarkdown } from '../ai/stored-markdown'\nimport { normalizeMarkdown } from './normalize-markdown'\n\n/** The fields of a workspace document the lineage needs (structurally a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n parent_ext_id?: string | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n id: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** The version this one was saved from. */\n parentId?: string | null\n}\n\n/**\n * The whole lineage of `docId` (root first, then oldest to newest), or `[]` when the document is\n * not in `docs`. Cycle-safe.\n */\nexport function buildVersionChain<T extends VersionedDoc>(\n docs: readonly T[],\n docId: string | null | undefined\n): T[] {\n if (!docId) return []\n const byId = new Map<string, T>()\n for (const d of docs) if (d.external_id) byId.set(d.external_id, d)\n\n const current = byId.get(docId)\n if (!current) return []\n\n let root = current\n const up = new Set<string>()\n while (\n root.parent_ext_id &&\n byId.has(root.parent_ext_id) &&\n root.external_id &&\n !up.has(root.external_id)\n ) {\n up.add(root.external_id)\n root = byId.get(root.parent_ext_id) as T\n }\n\n const byParent = new Map<string, T[]>()\n for (const d of docs) {\n if (d.parent_ext_id) {\n const siblings = byParent.get(d.parent_ext_id) ?? []\n siblings.push(d)\n byParent.set(d.parent_ext_id, siblings)\n }\n }\n const out: T[] = []\n const visited = new Set<string>()\n const walk = (d: T): void => {\n if (!d.external_id || visited.has(d.external_id)) return\n visited.add(d.external_id)\n out.push(d)\n for (const child of byParent.get(d.external_id) ?? []) walk(child)\n }\n walk(root)\n\n out.sort((a, b) => (a.created_at ?? '').localeCompare(b.created_at ?? ''))\n return out\n}\n\n/** The lineage of `docId` as plain version rows. */\nexport function toArtifactVersions(chain: readonly VersionedDoc[]): ArtifactVersion[] {\n return chain.flatMap((d) =>\n d.external_id\n ? [\n {\n id: d.external_id,\n name: d.file_name ?? '',\n createdAt: d.created_at ?? '',\n parentId: d.parent_ext_id,\n },\n ]\n : []\n )\n}\n\n/**\n * \"v2\": the 1-based position of `docId` in its lineage. `null` when there is nothing to tell apart\n * (the lineage is just this document, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n docId: string | null | undefined\n): string | null {\n if (!docId || versions.length <= 1) return null\n const index = versions.findIndex((v) => v.id === docId)\n return index === -1 ? null : `v${index + 1}`\n}\n\n/**\n * Join parsed chunks into one markdown text (blank line between chunks).\n *\n * `unescape: true` for an artifact stored from markdown: the backend's parse of a `.md` escapes\n * markdown punctuation, which `unescapeMarkdown` undoes (see its rule), and mangles its title\n * (`repairParsedTitle`, `repairParsedStructure`: doubled headings, `- ` stacked on list markers,\n * one-line tables), then normalised. Leave it off for the parse\n * of a PDF or Word file.\n */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined,\n options?: { unescape?: boolean }\n): string {\n const text = (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n if (!options?.unescape) return text\n // Canonical spelling last, so the text an editor starts from is what a save would persist.\n return normalizeMarkdown(\n repairParsedStructure(repairParsedTitle(unescapeMarkdown(text)))\n ).replace(/\\n$/, '')\n}\n\n/** The backend's pattern for a document id. Anything else (a streamed draft's placeholder) is local. */\nconst DOC_ID = /^doc/\n\n/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */\nexport function isDocumentId(id: string | null | undefined): id is string {\n return !!id && DOC_ID.test(id)\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { normalizeMarkdown } from './normalize-markdown'\nimport { useRedline, type UseRedlineResult } from './useRedline'\nimport type { RedlineEngine } from './redline-engine'\n\n/** What a save reports back. `docId` is the new version when the backend already knows it. */\nexport interface ArtifactSaveResult {\n docId?: string\n /** 1-based number of the version that was just saved (1 for the first save of a draft). */\n version?: number\n}\n\nexport interface ArtifactEditSessionOptions {\n /** The artifact being edited. Changing it discards the buffer and any comparison. */\n docId: string | null | undefined\n /**\n * The saved text of the open version. `undefined` while it loads; whenever it changes the\n * baseline follows it (a version arriving from the realtime channel, a finished stream).\n */\n baseline: string | undefined\n /**\n * A new document the user types from scratch: open straight in the editor, seeded with\n * `initialContent`, instead of showing a read-only view. Read when `docId` changes.\n */\n startEditing?: boolean\n initialContent?: string\n /** The version this one was saved from. Offering \"compare with previous\" needs it. */\n parentId?: string | null\n /** Controlled comparison target. Omit for an uncontrolled one the session owns. */\n compareId?: string | null\n onCompareChange?: (id: string | null) => void\n /** The saved text of the compare target (the older side of the diff). */\n compareText?: string | null\n compareLoading?: boolean\n /** Starting a comparison opens the editor with track changes on (default true). */\n compareOpensEditor?: boolean\n /** Persist the buffer as a NEW version. Rejecting keeps the buffer so nothing is lost. */\n save: (content: string) => Promise<ArtifactSaveResult | void>\n onSaved?: (result: ArtifactSaveResult, content: string) => void\n onSaveError?: (error: unknown) => void\n /** Every buffer change (a host keeps a draft store in sync with it). */\n onContentChange?: (content: string) => void\n /** The unsaved-changes flag, for a host that warns before a panel is closed. */\n onDirtyChange?: (dirty: boolean) => void\n /** Where the diff runs. Defaults to the main thread. */\n redlineEngine?: RedlineEngine\n /** Typing is never debounced; the diff trails the buffer by this long. Default 300ms. */\n diffDelayMs?: number\n}\n\nexport interface ArtifactEditSession {\n isEditing: boolean\n /** The saved text of the open version. */\n baseline: string\n /** The text in the editor (the baseline until the first edit). */\n content: string\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n compareId: string | null\n showTrackChanges: boolean\n /** Track changes between the compare target and the (debounced) buffer. */\n redline: UseRedlineResult\n startEdit: () => void\n /** Discard the buffer and any comparison; back to the rendered view. */\n cancel: () => void\n /** Save the buffer as a new version. Resolves false when it failed (the buffer is kept). */\n save: () => Promise<boolean>\n /** The editor's `onChange`; also replaces the buffer (for example after an undo-this-change). */\n change: (markdown: string) => void\n /** The editor's `onNormalized`: adopt its canonical form as the baseline so Save does not fire. */\n normalized: (markdown: string) => void\n /** Compare with the previous version (when no id is given). */\n compare: (id?: string) => void\n stopCompare: () => void\n setShowTrackChanges: (show: boolean) => void\n /** Undo one tracked change in the buffer. */\n revertRegion: (regionId: string) => Promise<void>\n}\n\n/**\n * The state machine of an artifact edit session, with no SDK and no network: the edit buffer and\n * its baseline, the dirty flag, immutable-version saves and a track-changes comparison. A host\n * supplies the saved text and a `save` function (see `useArtifactSession` for the SDK binding).\n */\nexport function useArtifactEditSession(options: ArtifactEditSessionOptions): ArtifactEditSession {\n const {\n docId,\n baseline: loadedBaseline,\n startEditing = false,\n initialContent,\n parentId,\n compareId: controlledCompareId,\n onCompareChange,\n compareText,\n compareLoading = false,\n compareOpensEditor = true,\n save: persist,\n onSaved,\n onSaveError,\n onContentChange,\n onDirtyChange,\n redlineEngine,\n diffDelayMs = 300,\n } = options\n\n const [isEditing, setIsEditing] = useState(false)\n const [baseline, setBaseline] = useState('')\n const [buffer, setBuffer] = useState('')\n const [isSaving, setIsSaving] = useState(false)\n const [showTrackChanges, setShowTrackChanges] = useState(false)\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const controlled = controlledCompareId !== undefined\n const compareId = controlled ? controlledCompareId : ownCompareId\n\n const setCompareId = useCallback(\n (id: string | null) => {\n if (!controlled) setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [controlled, onCompareChange]\n )\n\n // The latest values for callbacks that must not change identity while the user types.\n const latest = useRef({ buffer, baseline, isEditing, initialContent })\n latest.current = { buffer, baseline, isEditing, initialContent }\n\n // The baseline follows the loaded text. A draft has none and seeds itself below.\n useEffect(() => {\n if (loadedBaseline !== undefined) setBaseline(loadedBaseline)\n }, [loadedBaseline])\n\n // Another artifact: drop stale edits and comparison. A new typed document starts in the editor.\n useEffect(() => {\n if (startEditing) {\n const seed = latest.current.initialContent ?? ''\n setIsEditing(true)\n setBaseline(seed)\n setBuffer(seed)\n } else {\n setIsEditing(false)\n setBuffer('')\n }\n setCompareId(null)\n setShowTrackChanges(false)\n // Only the identity of the artifact resets the session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId])\n\n const startEdit = useCallback(() => {\n setBuffer(latest.current.baseline)\n setIsEditing(true)\n }, [])\n\n const stopCompare = useCallback(() => {\n setCompareId(null)\n setShowTrackChanges(false)\n }, [setCompareId])\n\n const cancel = useCallback(() => {\n setIsEditing(false)\n setBuffer('')\n stopCompare()\n }, [stopCompare])\n\n const compare = useCallback(\n (id?: string) => {\n const target = id ?? parentId\n if (target) setCompareId(target)\n },\n [parentId, setCompareId]\n )\n\n // Comparing and editing are one surface: a comparison opens the editor with the diff showing,\n // like Word's Compare yields tracked changes you can keep typing through.\n const hasBaseline = baseline !== ''\n useEffect(() => {\n if (!compareId || !compareOpensEditor || !hasBaseline) return\n if (!latest.current.isEditing) startEdit()\n setShowTrackChanges(true)\n }, [compareId, compareOpensEditor, hasBaseline, startEdit])\n\n const save = useCallback(async (): Promise<boolean> => {\n // Persist the canonical spelling so the editor's gratuitous escapes never reach a version.\n const raw = latest.current.buffer\n const normalised = normalizeMarkdown(raw)\n const content = raw.endsWith('\\n') ? normalised : normalised.replace(/\\n$/, '')\n setIsSaving(true)\n try {\n const result = (await persist(content)) ?? {}\n setBaseline(content)\n setIsEditing(false)\n stopCompare()\n onSaved?.(result, content)\n return true\n } catch (error) {\n onSaveError?.(error)\n return false\n } finally {\n setIsSaving(false)\n }\n }, [persist, stopCompare, onSaved, onSaveError])\n\n const content = buffer || baseline\n const hasChanges = isEditing && !!buffer && buffer !== baseline\n useEffect(() => {\n onDirtyChange?.(hasChanges)\n return () => onDirtyChange?.(false)\n }, [hasChanges, onDirtyChange])\n\n const setContent = useCallback(\n (markdown: string) => {\n setBuffer(markdown)\n onContentChange?.(markdown)\n },\n [onContentChange]\n )\n const normalized = useCallback((markdown: string) => {\n setBaseline(markdown)\n setBuffer(markdown)\n }, [])\n\n // The diff trails the buffer so it runs on a settled text.\n const [diffContent, setDiffContent] = useState(content)\n useEffect(() => {\n const id = setTimeout(() => setDiffContent(content), diffDelayMs)\n return () => clearTimeout(id)\n }, [content, diffDelayMs])\n\n const redline = useRedline({\n baseText: compareId ? compareText : undefined,\n compareText: compareId ? diffContent || baseline : undefined,\n isLoading: compareLoading,\n withRegions: true,\n engine: redlineEngine,\n })\n const { revertRegion: revertInRedline } = redline\n const revertRegion = useCallback(\n async (regionId: string): Promise<void> => {\n const next = await revertInRedline(regionId)\n if (next !== null) setContent(next)\n },\n [revertInRedline, setContent]\n )\n\n return useMemo(\n () => ({\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n canCompare: !!parentId && !compareId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n change: setContent,\n normalized,\n compare,\n stopCompare,\n setShowTrackChanges,\n revertRegion,\n }),\n [\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n parentId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n setContent,\n normalized,\n compare,\n stopCompare,\n revertRegion,\n ]\n )\n}\n","import { useCallback, useMemo } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { flattenChunks, isDocumentId } from './versions'\n\n/**\n * Where the text of a stored artifact is:\n * - `loading`: the first request is in flight (or there is no document yet);\n * - `parsing`: the backend has not finished parsing the upload (the endpoint answers 404, 422 or\n * 500, or an empty parse, for a few seconds after an upload) and the hook is retrying;\n * - `ready`: the text is here (an empty document is `ready` with `text: null`);\n * - `error`: the retries ran out, or the request was refused (401/403).\n */\nexport type ArtifactTextStatus = 'loading' | 'parsing' | 'ready' | 'error'\n\n/** How long `useArtifactText` keeps asking while a document is still being parsed. */\nexport interface ArtifactTextRetry {\n /** Retries after the first request. Default 12. */\n attempts?: number\n /** Delay before the first retry; it grows by 1.6x each time. Default 1000 ms. */\n baseDelayMs?: number\n /** Cap for one delay. Default 5000 ms (12 retries are about 50 s in all). */\n maxDelayMs?: number\n}\n\nexport const DEFAULT_ARTIFACT_TEXT_RETRY: Required<ArtifactTextRetry> = {\n attempts: 12,\n baseDelayMs: 1000,\n maxDelayMs: 5000,\n}\n\n/** Thrown inside the query when the parse has no text yet, so that it is retried like a 500. */\nclass NotParsedYetError extends Error {\n constructor() {\n super('The document has no parsed text yet')\n }\n}\n\nconst isRefusal = (error: unknown): boolean => {\n const status = error as { status?: number; response?: { status?: number } } | null\n const code = status?.status ?? status?.response?.status\n return code === 401 || code === 403\n}\n\nexport interface ArtifactText {\n /**\n * The markdown, clean: `undefined` while `loading` or `parsing`, `null` when there is none (an\n * empty document, or `error`).\n */\n text: string | null | undefined\n /** `status` is `loading` or `parsing`. */\n isLoading: boolean\n status: ArtifactTextStatus\n /** The last request error while `parsing` or after `error`. */\n error: Error | null\n /** Ask again now (after an `error`). */\n retry: () => void\n}\n\n/**\n * The saved markdown of an artifact version (its parsed chunks, joined and unescaped).\n *\n * A freshly uploaded document is parsed asynchronously, and for roughly 3 to 20 seconds the parsed\n * content endpoint answers 404, 422 or 500 (or an empty parse). The hook therefore retries with a\n * growing delay (see `ArtifactTextRetry`) and reports `status: 'parsing'` meanwhile, so a host can\n * show \"Preparing editor...\" instead of opening an editor on an empty baseline. After the last\n * retry the status is `error`; `retry()` starts a new round.\n *\n * The text is run through `unescapeMarkdown`: an artifact is always stored from markdown, and the\n * backend's parse of a `.md` escapes its punctuation.\n */\nexport function useArtifactText(\n docId: string | null | undefined,\n options?: { enabled?: boolean; retry?: ArtifactTextRetry }\n): ArtifactText {\n const arbi = useArbi()\n const { attempts, baseDelayMs, maxDelayMs } = {\n ...DEFAULT_ARTIFACT_TEXT_RETRY,\n ...options?.retry,\n }\n // A local draft (placeholder id) has no backend document: asking for its text would be a 422.\n const enabled = (options?.enabled ?? true) && isDocumentId(docId) && arbi.hasWorkspace\n const query = useQuery({\n // Under the shared `parsedDoc` key, so a document's invalidation reaches it too.\n queryKey: [...arbiQueryKeys.parsedDoc(docId ?? '', 'marker'), 'artifact-text'] as const,\n queryFn: async () => {\n const parsed = (await arbi.documents.getParsedContent(docId as string, 'marker')) as {\n chunks?: { content?: string | null }[]\n }\n if (!parsed.chunks?.some((c) => c.content?.trim())) throw new NotParsedYetError()\n return flattenChunks(parsed.chunks, { unescape: true })\n },\n enabled,\n retry: (failureCount, error) => !isRefusal(error) && failureCount < attempts,\n retryDelay: (failureCount) => Math.min(baseDelayMs * 1.6 ** failureCount, maxDelayMs),\n })\n\n const { refetch } = query\n const retry = useCallback(() => void refetch(), [refetch])\n\n return useMemo<ArtifactText>(() => {\n const error = query.error\n const neverParsed = error instanceof NotParsedYetError\n let status: ArtifactTextStatus = 'loading'\n if (!enabled) status = 'loading'\n else if (query.isSuccess || (query.isError && neverParsed)) status = 'ready'\n else if (query.isError) status = 'error'\n else if (query.failureCount > 0) status = 'parsing'\n const text = !enabled\n ? undefined\n : query.isSuccess\n ? query.data\n : status === 'ready' || status === 'error'\n ? null\n : undefined\n return {\n text,\n isLoading: enabled && (status === 'loading' || status === 'parsing'),\n status,\n error: status === 'ready' ? null : (error ?? query.failureReason ?? null),\n retry,\n }\n }, [\n enabled,\n query.isSuccess,\n query.isError,\n query.data,\n query.error,\n query.failureCount,\n query.failureReason,\n retry,\n ])\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys, useDocuments } from '../hooks'\nimport { useArtifactText, type ArtifactTextStatus } from './useArtifactText'\nimport {\n buildVersionChain,\n isDocumentId,\n toArtifactVersions,\n versionLabel,\n type ArtifactVersion,\n} from './versions'\nimport {\n useArtifactEditSession,\n type ArtifactEditSession,\n type ArtifactEditSessionOptions,\n type ArtifactSaveResult,\n} from './useArtifactEditSession'\n\n/** The version lineage of an artifact in a workspace, oldest first. */\nexport function useArtifactVersions(\n workspaceId: string | undefined,\n docId: string | null | undefined\n): ArtifactVersion[] {\n const { data: documents } = useDocuments(workspaceId)\n return useMemo(\n () => toArtifactVersions(buildVersionChain(documents ?? [], docId)),\n [documents, docId]\n )\n}\n\nexport interface SaveArtifactVersionInput {\n /** File name of the new version (`.md` is added when missing). */\n title: string\n content: string\n /** The version this one is saved from; omit for a first version. */\n parentId?: string | null\n /** The processing config (auto-title, parsing) to run the upload with. */\n configId?: string | null\n /** `artifact` (default) for AI-style drafts; `source` for a document the user typed. */\n wpType?: 'artifact' | 'source'\n}\n\n/**\n * Save markdown as a NEW immutable version (a child document of `parentId`) and refresh the\n * workspace document list so the version list picks it up. The id of the new version is often not\n * known yet (the document is parsed asynchronously); it then arrives through the list.\n */\nexport function useSaveArtifactVersion() {\n const arbi = useArbi()\n const queryClient = useQueryClient()\n return useMutation<\n ArtifactSaveResult,\n Error,\n SaveArtifactVersionInput & { workspaceId?: string }\n >({\n mutationFn: async ({ title, content, parentId, configId, wpType, workspaceId }) => {\n // The backend classifies uploads by extension: a title without one is silently dropped.\n const fileName = /\\.md$/i.test(title) ? title : `${title}.md`\n const result = await arbi.documents.uploadFile(\n new Blob([content], { type: 'text/markdown' }),\n fileName,\n {\n wpType: wpType ?? 'artifact',\n parentExtId: parentId ?? undefined,\n configExtId: configId ?? undefined,\n }\n )\n if (workspaceId) {\n await queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documents(workspaceId) })\n }\n return { docId: result.doc_ext_ids?.[0] }\n },\n })\n}\n\nexport interface ArtifactSessionOptions extends Pick<\n ArtifactEditSessionOptions,\n | 'onSaved'\n | 'onSaveError'\n | 'onCompareChange'\n | 'compareId'\n | 'compareOpensEditor'\n | 'redlineEngine'\n | 'onDirtyChange'\n> {\n workspaceId: string | undefined\n /**\n * The open version, or the placeholder id of an unsaved local draft (anything that is not a\n * backend document id, i.e. does not start with `doc`).\n */\n docId: string | null | undefined\n /**\n * The text of a local draft (nothing is fetched for it). The FIRST save uploads it as a real\n * document with no parent and the session switches to the new id; later saves chain from it.\n */\n draftContent?: string\n /** Name for saved versions. Defaults to the open version's file name, else \"Untitled\". */\n title?: string\n /** Processing config for saved versions. */\n configId?: string | null\n}\n\n/** Everything `ArtifactEditor` (`@arbidocs/blocks/artifacts`) takes from a session, flat. */\nexport interface ArtifactSessionView {\n content: string\n isEditing: boolean\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n comparing: boolean\n compareId: string | null\n showTrackChanges: boolean\n versions: ArtifactVersion[]\n currentVersionId: string\n onStartEdit: () => void\n onCancel: () => void\n onSave: () => void\n onCompare: () => void\n onStopCompare: () => void\n onToggleTrackChanges: () => void\n /**\n * Whether the text is ready. `ArtifactEditor` renders \"Preparing editor...\" while it is\n * `loading` or `parsing` (a fresh upload is parsed for a few seconds) and an error with Retry.\n */\n status: ArtifactTextStatus\n /** Ask for the text again after an `error`. */\n onRetry: () => void\n}\n\nexport interface ArtifactSession extends ArtifactEditSession {\n /** The open document: the new real id once a local draft has been saved. */\n docId: string | null | undefined\n /** The open version is an unsaved local draft (no backend document yet). */\n isLocal: boolean\n isLoading: boolean\n /** See `ArtifactTextStatus`. */\n status: ArtifactTextStatus\n versions: ArtifactVersion[]\n /** \"v2\" for any version in the lineage. */\n labelOf: (id: string | null | undefined) => string | null\n /** Props for `<ArtifactEditor>`. */\n view: ArtifactSessionView\n /** Props for `<ArtifactMarkdownEditor>` (`@arbidocs/blocks/artifacts/editor`). */\n editorProps: {\n markdown: string\n onChange: (markdown: string) => void\n onNormalized: (markdown: string) => void\n }\n /** Props for `<ArtifactRedlineView>`. */\n redlineProps: {\n state: ArtifactEditSession['redline']['state']\n onRevert: (regionId: string) => void\n }\n}\n\n/**\n * Edit an artifact through the SDK: load it, edit it, save it as a new version, list its versions\n * and compare any two with track changes. Needs an `<ArbiProvider>` and a selected workspace.\n *\n * ```tsx\n * const session = useArtifactSession({ workspaceId, docId, onSaved: ({ docId }) => docId && open(docId) })\n * <ArtifactEditor {...session.view} onOpenVersion={open}\n * editor={<ArtifactMarkdownEditor {...session.editorProps} />}\n * redline={<ArtifactRedlineView {...session.redlineProps} />} />\n * ```\n */\nexport function useArtifactSession(options: ArtifactSessionOptions): ArtifactSession {\n const {\n workspaceId,\n docId: hostDocId,\n draftContent,\n title,\n configId,\n compareId,\n onCompareChange,\n onSaved,\n ...passthrough\n } = options\n // A saved local draft becomes this real document; another host docId resets it.\n const [saved, setSaved] = useState<{\n forId: string | null | undefined\n id: string\n text: string\n } | null>(null)\n const adopted = saved && saved.forId === hostDocId ? saved : null\n const docId = adopted?.id ?? hostDocId\n const isLocal = !isDocumentId(docId)\n\n // Owned here (not in the edit session) because the compare target's text must be loaded first.\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const activeCompareId = compareId === undefined ? ownCompareId : compareId\n const changeCompare = useCallback(\n (id: string | null) => {\n setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [onCompareChange]\n )\n\n const { text, isLoading, status, retry } = useArtifactText(docId)\n const versions = useArtifactVersions(workspaceId, isLocal ? null : docId)\n const { text: compareText, isLoading: compareLoading } = useArtifactText(activeCompareId, {\n enabled: !!activeCompareId,\n })\n const saveVersion = useSaveArtifactVersion()\n const current = versions.find((v) => v.id === docId)\n\n const save = useCallback(\n async (content: string) => {\n const result = await saveVersion.mutateAsync({\n title: title ?? current?.name ?? 'Untitled',\n content,\n parentId: isLocal ? null : docId,\n configId,\n workspaceId,\n })\n return { ...result, version: isLocal ? 1 : versions.length + 1 }\n },\n [saveVersion, title, current?.name, isLocal, docId, configId, workspaceId, versions.length]\n )\n\n const handleSaved = useCallback(\n (result: ArtifactSaveResult, content: string) => {\n // A host that keeps passing the local draft's placeholder id: follow every save to the real\n // document it created (the first save creates version 1, later ones chain from it).\n if (!isDocumentId(hostDocId) && result.docId)\n setSaved({ forId: hostDocId, id: result.docId, text: content })\n onSaved?.(result, content)\n },\n [hostDocId, onSaved]\n )\n\n const session = useArtifactEditSession({\n ...passthrough,\n docId,\n // A local draft has only its own text; a just-saved one shows what was saved until the parsed\n // text of the new document arrives.\n baseline: text ?? (isLocal ? draftContent : adopted?.text),\n parentId: current?.parentId,\n compareId: activeCompareId,\n onCompareChange: changeCompare,\n compareText,\n compareLoading,\n save,\n onSaved: handleSaved,\n })\n\n const { redline } = session\n return useMemo<ArtifactSession>(\n () => ({\n ...session,\n docId,\n isLocal,\n isLoading,\n status,\n versions,\n labelOf: (id) => versionLabel(versions, id),\n view: {\n content: session.baseline,\n isEditing: session.isEditing,\n hasChanges: session.hasChanges,\n isSaving: session.isSaving,\n canCompare: session.canCompare,\n comparing: !!session.compareId,\n compareId: session.compareId,\n showTrackChanges: session.showTrackChanges,\n versions,\n currentVersionId: docId ?? '',\n onStartEdit: session.startEdit,\n onCancel: session.cancel,\n onSave: () => void session.save(),\n onCompare: () => session.compare(),\n onStopCompare: session.stopCompare,\n onToggleTrackChanges: () => session.setShowTrackChanges(!session.showTrackChanges),\n // A local draft has its text already: it is ready.\n status: isLocal ? 'ready' : status,\n onRetry: retry,\n },\n editorProps: {\n markdown: session.content,\n onChange: session.change,\n onNormalized: session.normalized,\n },\n redlineProps: {\n state: redline.state,\n onRevert: (regionId) => void session.revertRegion(regionId),\n },\n }),\n [session, redline, isLoading, status, retry, isLocal, versions, docId]\n )\n}\n","import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react'\nimport { MarkdownRenderer } from '../ai/MarkdownRenderer'\n\n/** The `<del>` / `<ins>` renderers `ArtifactRedlineView` hands to a markdown renderer. */\nexport interface ArtifactRedlineComponents {\n del: FC<ComponentPropsWithoutRef<'del'> & { 'data-cid'?: string }>\n ins: FC<ComponentPropsWithoutRef<'ins'> & { 'data-cid'?: string }>\n}\n\n/**\n * The kit's markdown renderer as the `renderMarkdown` slot of `ArtifactEditor` and\n * `ArtifactRedlineView`: full markdown (tables, lists, code) plus the raw `<del>` / `<ins>` tags\n * of a redline.\n */\nexport function renderArtifactMarkdown(\n markdown: string,\n components?: ArtifactRedlineComponents\n): ReactNode {\n return <MarkdownRenderer components={components}>{markdown}</MarkdownRenderer>\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { ArtifactEvent } from '../ai/engine'\nimport { cleanDraftMarkdown } from '../ai/stored-markdown'\nimport { useSaveArtifactVersion } from './useArtifactSession'\nimport { isDocumentId } from './versions'\nimport { useArtifactText, type ArtifactTextRetry } from './useArtifactText'\n\n/**\n * Where a drafted artifact is in its STREAM -> PERSIST -> EDIT life:\n * - `streaming`: the agent is still working (or has produced nothing final): show the live canvas;\n * - `persisting`: the finished draft is being stored as version 1 of the artifact;\n * - `parsing`: stored; the backend is still parsing it, so there is no editable text yet;\n * - `ready`: the text is readable: mount the editor on `docId`;\n * - `error`: storing failed or the parse never produced text (`retry()` starts over).\n */\nexport type StreamedArtifactPhase = 'streaming' | 'persisting' | 'parsing' | 'ready' | 'error'\n\nexport interface UseStreamedArtifactOptions {\n /** The artifacts of the agent run (`useConnectedAiTask().artifacts`). */\n artifacts: ArtifactEvent[]\n workspaceId: string | undefined\n /**\n * The run has stopped: not busy and not failed. Nothing is stored before this, so a draft that\n * is still streaming is never persisted half-written.\n */\n settled: boolean\n /** Make the stored markdown from the streamed content. Defaults to `cleanDraftMarkdown`. */\n clean?: (streamed: string) => string\n /** Processing config for the stored version. */\n configId?: string | null\n /** How long to wait for the parse (see `useArtifactText`). */\n parseRetry?: ArtifactTextRetry\n}\n\nexport interface StreamedArtifact {\n phase: StreamedArtifactPhase\n /** The finished streamed artifact (its `title` names the stored versions). */\n artifact: ArtifactEvent | undefined\n /** The backend document to edit, once there is one (while `parsing` and `ready`). */\n docId: string | undefined\n error: Error | null\n /** After an `error`: store again or ask for the parse again. */\n retry: () => void\n}\n\n/**\n * The lifecycle of an agent-drafted artifact, so a host passes the stream and renders the phase.\n *\n * While the agent streams, the draft lives only on the canvas. Once the run is `settled` and the\n * draft is complete, a draft that is not yet a backend document is cleaned (`cleanDraftMarkdown`)\n * and stored ONCE as the artifact's first version (`wpType: 'artifact'`); a draft that already is a\n * backend document passes through. The hook then waits for the parse (`useArtifactText`, which\n * retries) and reports `ready` with the `docId` to open in an editor.\n *\n * Needs an `<ArbiProvider>` and a workspace. `@arbidocs/blocks/connect` has the whole thing as a\n * component (`StreamedArtifact`).\n */\nexport function useStreamedArtifact({\n artifacts,\n workspaceId,\n settled,\n clean = cleanDraftMarkdown,\n configId,\n parseRetry,\n}: UseStreamedArtifactOptions): StreamedArtifact {\n const artifact = artifacts.find((a) => a.is_complete)\n const { mutateAsync } = useSaveArtifactVersion()\n const [saved, setSaved] = useState<{ content: string; docId: string } | null>(null)\n const [saveError, setSaveError] = useState<Error | null>(null)\n const [attempt, setAttempt] = useState(0)\n const started = useRef<string | null>(null)\n\n const content = artifact?.content ?? ''\n const title = artifact?.title ?? 'Draft'\n const passThrough = !!artifact && isDocumentId(artifact.doc_ext_id)\n const needsSave = settled && !!artifact && !passThrough && !!content.trim() && !!workspaceId\n\n useEffect(() => {\n const key = `${attempt}:${content}`\n if (!needsSave || started.current === key) return\n started.current = key\n setSaveError(null)\n mutateAsync({\n title,\n content: clean(content),\n workspaceId,\n configId,\n wpType: 'artifact',\n })\n .then((r) => {\n if (r.docId) setSaved({ content, docId: r.docId })\n else setSaveError(new Error('The draft was stored but the server returned no document id'))\n })\n .catch((e: unknown) => setSaveError(e instanceof Error ? e : new Error(String(e))))\n // `clean` is deliberately not a dependency: a new function identity must not store twice.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [needsSave, content, title, workspaceId, configId, attempt, mutateAsync])\n\n const docId = !artifact\n ? undefined\n : passThrough\n ? artifact.doc_ext_id\n : saved?.content === content\n ? saved.docId\n : undefined\n\n const text = useArtifactText(docId, { enabled: settled, retry: parseRetry })\n const { retry: retryText } = text\n\n const retry = useCallback(() => {\n if (saveError) setAttempt((n) => n + 1)\n else retryText()\n }, [saveError, retryText])\n\n let phase: StreamedArtifactPhase\n if (!settled || !artifact) phase = 'streaming'\n else if (saveError) phase = 'error'\n else if (!docId) phase = needsSave ? 'persisting' : 'streaming'\n else if (text.status === 'ready' && text.text) phase = 'ready'\n else if (text.status === 'error' || text.status === 'ready') phase = 'error'\n else phase = 'parsing'\n\n const error =\n phase !== 'error'\n ? null\n : (saveError ?? text.error ?? new Error('The document has no text to edit'))\n return { phase, artifact, docId, error, retry }\n}\n"]}
@@ -346,6 +346,80 @@ function repairParsedTitle(text) {
346
346
  }
347
347
  return text;
348
348
  }
349
+ var DOUBLED_HEADING = /^#{1,6}\s+(#{1,6}\s+\S.*)$/;
350
+ var LIST_HEADING = /^[-*+]\s+(#{1,6}\s+\S.*)$/;
351
+ var LIST_IN_LIST = /^[-*+]\s+[-*+]\s+(\S.*)$/;
352
+ var LIST_ORDINAL = /^[-*+]\s+(\d{1,9})([.)])\s+(\S.*)$/;
353
+ var LIST_ITEM_LINE = /^\s*(?:[-*+]|\d{1,9}[.)])\s/;
354
+ var TABLE_DELIMITER_CELL = /^:?-{1,}:?$/;
355
+ function splitRunOfOrdinals(first, delimiter, rest) {
356
+ const items = [];
357
+ let n = first;
358
+ let remaining = rest;
359
+ for (; ; ) {
360
+ const next = new RegExp(`^(.+?)\\s+${n + 1}\\${delimiter}\\s+(\\S.*)$`).exec(remaining);
361
+ if (!next) break;
362
+ items.push(`${n}${delimiter} ${next[1]}`);
363
+ n += 1;
364
+ remaining = next[2];
365
+ }
366
+ items.push(`${n}${delimiter} ${remaining}`);
367
+ return items;
368
+ }
369
+ function rebuildFlatTable(line) {
370
+ const trimmed = line.trim();
371
+ if (!trimmed.startsWith("|") || !trimmed.endsWith("|")) return null;
372
+ const cells = trimmed.slice(1, -1).split("|").map((c) => c.trim());
373
+ const firstRule = cells.findIndex((c) => TABLE_DELIMITER_CELL.test(c));
374
+ if (firstRule < 2 || cells[firstRule - 1] !== "") return null;
375
+ const columns = firstRule - 1;
376
+ const rows = [];
377
+ for (let at = 0; at < cells.length; at += columns + 1) {
378
+ const row = cells.slice(at, at + columns);
379
+ const gap = cells[at + columns];
380
+ if (row.length !== columns || gap !== void 0 && gap !== "") return null;
381
+ rows.push(row);
382
+ }
383
+ const [header, rule, ...body] = rows;
384
+ if (!rule.every((c) => TABLE_DELIMITER_CELL.test(c))) return null;
385
+ const fmt = (row) => `| ${row.join(" | ")} |`;
386
+ return [fmt(header), fmt(rule.map(() => "---")), ...body.map(fmt)];
387
+ }
388
+ function repairParsedStructure(text) {
389
+ const out = [];
390
+ let inFence = false;
391
+ for (const line of text.split("\n")) {
392
+ if (FENCE.test(line)) {
393
+ inFence = !inFence;
394
+ out.push(line);
395
+ continue;
396
+ }
397
+ if (inFence) {
398
+ out.push(line);
399
+ continue;
400
+ }
401
+ const table = rebuildFlatTable(line);
402
+ if (table) {
403
+ out.push(...table);
404
+ continue;
405
+ }
406
+ const heading = DOUBLED_HEADING.exec(line) ?? LIST_HEADING.exec(line);
407
+ if (heading) {
408
+ out.push(heading[1]);
409
+ continue;
410
+ }
411
+ const ordinal = LIST_ORDINAL.exec(line);
412
+ if (ordinal) {
413
+ out.push(...splitRunOfOrdinals(Number(ordinal[1]), ordinal[2], ordinal[3]));
414
+ continue;
415
+ }
416
+ const nested = LIST_IN_LIST.exec(line);
417
+ out.push(nested ? `- ${nested[1]}` : line);
418
+ }
419
+ return out.filter(
420
+ (line, i) => !(line === "" && LIST_ITEM_LINE.test(out[i - 1] ?? "") && LIST_ITEM_LINE.test(out[i + 1] ?? ""))
421
+ ).join("\n");
422
+ }
349
423
  var SOURCE_NOTE = /[ \t]*(?:\*+\(\s*Sources?\s*:[^)\n]*\)\*+|\(\s*\*{0,2}\s*Sources?\s*:[^)\n]*\))/gi;
350
424
  var CITE_LINK = /\[([^\]\n]+)\]\(#cite-[\w-]+\)/g;
351
425
  function balanceBold(line) {
@@ -408,6 +482,7 @@ exports.creditsToUsd = creditsToUsd;
408
482
  exports.formatCredits = formatCredits;
409
483
  exports.isUsageMetered = isUsageMetered;
410
484
  exports.promoteBoldTitle = promoteBoldTitle;
485
+ exports.repairParsedStructure = repairParsedStructure;
411
486
  exports.repairParsedTitle = repairParsedTitle;
412
487
  exports.stripAgentPreamble = stripAgentPreamble;
413
488
  exports.unescapeMarkdown = unescapeMarkdown;
@@ -433,5 +508,5 @@ exports.useTasks = useTasks;
433
508
  exports.useThumbnails = useThumbnails;
434
509
  exports.useUserUsageToday = useUserUsageToday;
435
510
  exports.useWorkspaces = useWorkspaces;
436
- //# sourceMappingURL=chunk-VZLGOA4A.cjs.map
437
- //# sourceMappingURL=chunk-VZLGOA4A.cjs.map
511
+ //# sourceMappingURL=chunk-3MFESAPI.cjs.map
512
+ //# sourceMappingURL=chunk-3MFESAPI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/credits.ts","../src/hooks.ts","../src/ai/stored-markdown.ts"],"names":["useArbi","useQuery","useMutation","useQueryClient","useQueries","useMemo","normalizeCitationMarkup"],"mappings":"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","file":"chunk-3MFESAPI.cjs","sourcesContent":["/**\n * Credits: the unit the ARBI backend reports AI usage in.\n *\n * The usage endpoints (`/v1/user/projects/{id}/usage`, `/me/usage/today`) convert the metered USD\n * spend into whole credits at the API boundary: 1 credit = `CREDITS_TO_AI_USD`, which is $0.01 on\n * a default deployment. The fields are still named `spend` / `total_spend` in the schema, but they\n * hold CREDITS, never dollars. Label them as credits; use {@link creditsToUsd} only when a\n * dollar figure is genuinely wanted, with the deployment's own rate.\n */\n\n/** Dollars per credit on a default deployment (`CREDITS_TO_AI_USD`). */\nexport const DEFAULT_USD_PER_CREDIT = 0.01\n\nexport interface FormatCreditsOptions {\n /** Append the unit (\"12 credits\"). Default true; pass false inside a column headed \"Credits\". */\n unit?: boolean\n /** BCP 47 locale for the digit grouping. Default `en-US`. */\n locale?: string\n}\n\n/** \"1,234 credits\" / \"1 credit\". The backend reports whole credits; this rounds away float dust. */\nexport function formatCredits(credits: number, options: FormatCreditsOptions = {}): string {\n const { unit = true, locale = 'en-US' } = options\n const whole = Math.round(Number.isFinite(credits) ? credits : 0)\n const digits = whole.toLocaleString(locale)\n return unit ? `${digits} ${whole === 1 ? 'credit' : 'credits'}` : digits\n}\n\n/** The dollar value of an amount of credits. `usdPerCredit` defaults to {@link DEFAULT_USD_PER_CREDIT}. */\nexport function creditsToUsd(\n credits: number,\n usdPerCredit: number = DEFAULT_USD_PER_CREDIT\n): number {\n return credits * usdPerCredit\n}\n\n/** The slice of a usage response that tells whether anything was recorded. */\nexport interface UsageTotals {\n total_spend: number\n total_tokens: number\n total_requests: number\n}\n\n/**\n * Was this usage actually metered? A project on the `dev` plan belongs to a deployment with\n * billing switched off: the backend only records AI usage per project when billing is enabled, so\n * an all-zero response there means \"not metered\", not \"nothing happened\". Show a note instead of\n * silent zeros.\n */\nexport function isUsageMetered(\n usage: UsageTotals,\n subscription: string | null | undefined\n): boolean {\n const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0\n return !(empty && subscription === 'dev')\n}\n","/**\n * React Query hooks that use the Arbi instance from context.\n */\n\nimport { useMemo } from 'react'\nimport { useQuery, useQueries, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type {\n SSEStreamResult,\n SSEStreamStartData,\n ResponseOutputItemDoneEvent,\n ArtifactEvent,\n UserMessageEvent,\n MessageMetadataPayload,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport type { ParsedDocument } from './documents/parsed-types'\nimport { isUsageMetered } from './credits'\n\n// ── Query keys ──────────────────────────────────────────────────────────────\n\nexport const arbiQueryKeys = {\n workspaces: () => ['arbi', 'workspaces'] as const,\n documents: (workspaceId: string) => ['arbi', 'documents', workspaceId] as const,\n conversations: (workspaceId: string) => ['arbi', 'conversations', workspaceId] as const,\n conversationThreads: (workspaceId: string, conversationId: string) =>\n ['arbi', 'conversations', workspaceId, 'threads', conversationId] as const,\n tags: (workspaceId: string) => ['arbi', 'tags', workspaceId] as const,\n thumbnails: (docIds: string[]) => ['arbi', 'thumbnails', [...docIds].sort().join(',')] as const,\n parsedDoc: (docId: string, stage: string) => ['arbi', 'parsedDoc', docId, stage] as const,\n agents: () => ['arbi', 'agents'] as const,\n sessions: () => ['arbi', 'sessions'] as const,\n health: () => ['arbi', 'health'] as const,\n tasks: () => ['arbi', 'tasks'] as const,\n facts: (workspaceId: string) => ['arbi', 'facts', workspaceId] as const,\n configs: () => ['arbi', 'configs'] as const,\n activity: () => ['arbi', 'activity'] as const,\n projects: () => ['arbi', 'projects'] as const,\n projectUsage: (projectExtId: string, monthsBack: number) =>\n ['arbi', 'projectUsage', projectExtId, monthsBack] as const,\n projectInvoices: (projectExtId: string) => ['arbi', 'projectInvoices', projectExtId] as const,\n userUsageToday: () => ['arbi', 'userUsageToday'] as const,\n contacts: () => ['arbi', 'contacts'] as const,\n skills: () => ['arbi', 'skills'] as const,\n taskRuns: (taskId: string) => ['arbi', 'taskRuns', taskId] as const,\n /** An agent's pinned config; `undefined` = the library default config. */\n agentConfig: (agentExtId?: string) => ['arbi', 'agentConfig', agentExtId ?? 'default'] as const,\n agentWorkspaces: (agentExtId: string) => ['arbi', 'agentWorkspaces', agentExtId] as const,\n models: () => ['arbi', 'models'] as const,\n /** The signed-in user's own profile (name, picture, email). */\n profile: () => ['arbi', 'profile'] as const,\n /** The signed-in user's settings record (notification preferences, flags). */\n userSettings: () => ['arbi', 'userSettings'] as const,\n}\n\n// ── Hooks ───────────────────────────────────────────────────────────────────\n\n/** List the logged-in user's workspaces. */\nexport function useWorkspaces(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.workspaces(),\n queryFn: () => arbi.workspaces.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/** List documents in a workspace. */\nexport function useDocuments(workspaceId: string | undefined, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspaceId ?? ''),\n queryFn: () => arbi.documents.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n/** List conversations in a workspace. */\nexport function useConversations(workspaceId: string | undefined, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.conversations(workspaceId ?? ''),\n queryFn: () => arbi.conversations.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n/**\n * A conversation's stored threads (each with its message history, citations data included).\n * Always refetched on mount: a conversation that was open before may have new turns.\n */\nexport function useConversationThreads(\n workspaceId: string | undefined,\n conversationId: string | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.conversationThreads(workspaceId ?? '', conversationId ?? ''),\n queryFn: () => arbi.conversations.getThreads(conversationId as string),\n enabled: (options?.enabled ?? true) && !!workspaceId && !!conversationId && arbi.hasWorkspace,\n gcTime: 0,\n })\n}\n\n/** List tags in a workspace. */\nexport function useTags(workspaceId: string | undefined, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.tags(workspaceId ?? ''),\n queryFn: () => arbi.tags.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n/**\n * Batch-fetch first-page thumbnails for a set of documents. Returns a map of\n * doc external id → `data:image/webp` URI (or `null` when no thumbnail exists).\n * Cached for a few minutes since thumbnails are effectively immutable per doc.\n */\nexport function useThumbnails(docIds: string[], options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.thumbnails(docIds),\n queryFn: () => arbi.documents.getThumbnails(docIds),\n enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.hasWorkspace,\n staleTime: 5 * 60_000,\n })\n}\n\n/**\n * Fetch a document's parsed content (chunks grouped by page) for the review\n * viewer. `stage` defaults to `final` (fully processed); `marker`/`subchunk`\n * expose earlier pipeline stages.\n */\nexport function useParsedDocument(\n docId: string | undefined,\n stage: string = 'final',\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.parsedDoc(docId ?? '', stage),\n queryFn: () =>\n arbi.documents.getParsedContent(docId as string, stage) as unknown as Promise<ParsedDocument>,\n enabled: (options?.enabled ?? true) && !!docId && arbi.hasWorkspace,\n })\n}\n\n/** Send a streaming query to the RAG assistant. Returns a mutation. */\nexport function useAssistantQuery() {\n const arbi = useArbi()\n\n return useMutation<\n SSEStreamResult,\n Error,\n {\n question: string\n docIds: string[]\n previousResponseId?: string | null\n model?: string\n onToken?: (content: string) => void\n /** Aborts the request and the stream; the mutation then rejects with an `AbortError`. */\n signal?: AbortSignal\n onStreamStart?: (data: SSEStreamStartData) => void\n onUserMessage?: (data: UserMessageEvent) => void\n onMetadata?: (data: MessageMetadataPayload) => void\n onOutputItemDone?: (data: ResponseOutputItemDoneEvent) => void\n onArtifact?: (data: ArtifactEvent) => void\n onError?: (message: string) => void\n onComplete?: () => void\n }\n >({\n mutationFn: ({ question, ...options }) => arbi.assistant.query(question, options),\n })\n}\n\n/** List agents owned by the current user. */\nexport function useAgents(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.agents(),\n queryFn: () => arbi.agents.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/**\n * Delete agents. Returns a mutation. Refreshes the agent list and the task list (a deleted\n * agent's tasks go with it), and drops the deleted agents' own config and workspace queries.\n */\nexport function useDeleteAgents() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation<unknown, Error, { agentExtIds: string[] }>({\n mutationFn: ({ agentExtIds }) => arbi.agents.delete(agentExtIds),\n onSuccess: (_result, { agentExtIds }) => {\n for (const id of agentExtIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.agentConfig(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.agentWorkspaces(id) })\n }\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.agents() }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.configs() }),\n ])\n },\n })\n}\n\n/** List active sessions. */\nexport function useSessions(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.sessions(),\n queryFn: () => arbi.sessions.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/** Authorize a delegated session (generates claim code). Returns a mutation. */\n\n/** Check backend health. */\nexport function useHealth(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.health(),\n queryFn: () => arbi.health.check(),\n enabled: options?.enabled,\n })\n}\n\n// ── Scheduled tasks ──────────────────────────────────────────────────────────\n\n/** List the caller's scheduled agent tasks. */\nexport function useTasks(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.tasks(),\n queryFn: () => arbi.tasks.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n// ── Workspace notes ──────────────────────────────────────────────────────────\n\n/** List the open workspace's facts. */\nexport function useFacts(\n workspaceId: string | undefined,\n options?: { enabled?: boolean; pinnedOnly?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.facts(workspaceId ?? ''),\n queryFn: () => arbi.facts.list({ pinnedOnly: options?.pinnedOnly }),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n// ── Behaviour-template configs ───────────────────────────────────────────────\n\n/** List the caller's saved agent configurations (behaviour templates). */\nexport function useConfigs(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.configs(),\n queryFn: () => arbi.agentConfig.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n// ── Activity feed ─────────────────────────────────────────────────────────────\n\n/**\n * List the caller's durable activity feed, newest first.\n *\n * Activity entries are backend-originated, to-self log lines that are always\n * read — they are deliberately kept out of the normal notifications/DM feed and\n * never affect the unread badge, so this is a separate, opt-in query.\n */\nexport function useActivity(options?: { enabled?: boolean; limit?: number; offset?: number }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.activity(),\n queryFn: () => arbi.dm.listActivity({ limit: options?.limit, offset: options?.offset }),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n// ── Projects, usage & spend ───────────────────────────────────────────────────\n\n/** List the logged-in user's projects (billing accounts). */\nexport function useProjects(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.projects(),\n queryFn: () => arbi.projects.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/**\n * AI usage breakdown for a project's billing period. `monthsBack` selects the period (0 =\n * current, 1 = previous month, …).\n *\n * The response's `total_spend` / `spend` fields are CREDITS, not dollars (see `formatCredits`).\n * `metered` is `false` when the deployment does not record usage (a `dev`-plan project with all\n * zeros): show \"usage is not metered here\" instead of zeros. It is `undefined` until the usage\n * has loaded.\n */\nexport function useProjectUsage(\n projectExtId: string | undefined,\n monthsBack: number = 0,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const usage = useQuery({\n queryKey: arbiQueryKeys.projectUsage(projectExtId ?? '', monthsBack),\n queryFn: () => arbi.projects.usage(projectExtId as string, monthsBack),\n enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn,\n })\n const projects = useProjects({ enabled: !!projectExtId && (options?.enabled ?? true) })\n const subscription = projects.data?.find((p) => p.external_id === projectExtId)?.subscription\n const metered = usage.data ? isUsageMetered(usage.data, subscription) : undefined\n return { ...usage, metered }\n}\n\n/** One day of aggregated usage across projects (for a spend/token trend). */\nexport interface AggregatedDailyUsage {\n date: string\n /** Credits used that day (not dollars). */\n credits: number\n totalTokens: number\n apiRequests: number\n}\n\n/** One model group's aggregated usage across projects (for a breakdown). */\nexport interface AggregatedModelGroupUsage {\n model: string\n /** Credits used by this model group (not dollars). */\n credits: number\n totalTokens: number\n promptTokens: number\n completionTokens: number\n successfulRequests: number\n}\n\n/** Aggregated AI usage + spend across several projects. */\nexport interface ProjectsUsageAggregate {\n /** Summed usage across the projects, in CREDITS (1 credit = $0.01 by default), not dollars. */\n totalCredits: number\n /** Summed token count across the projects. */\n totalTokens: number\n /** Summed API request count across the projects. */\n totalRequests: number\n /** Per-day totals merged across every project, oldest first. */\n daily: AggregatedDailyUsage[]\n /** Per-model-group totals merged across every project, most credits first. */\n modelGroups: AggregatedModelGroupUsage[]\n /**\n * False when none of the loaded projects records usage (billing is off on this deployment), so\n * zeros mean \"not metered\". True while anything real was recorded, or before data arrived.\n */\n metered: boolean\n /** True while any per-project query is still loading. */\n isLoading: boolean\n /** True if any per-project query errored. */\n isError: boolean\n}\n\n/**\n * Firm-wide AI usage + spend: aggregates {@link useProjectUsage} across several\n * projects (e.g. all of a firm's matters) in parallel and merges the real totals,\n * the daily trend, and the per-model breakdown. Shares the per-project query\n * cache, so it costs nothing extra where a project's usage is already loaded.\n * Numbers are genuine — zero projects (or zero billed work) yields zero totals;\n * callers render that honestly.\n */\nexport function useProjectsUsage(\n projectExtIds: string[],\n monthsBack: number = 0,\n options?: { enabled?: boolean }\n): ProjectsUsageAggregate {\n const arbi = useArbi()\n const enabled = (options?.enabled ?? true) && arbi.isLoggedIn\n const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 })\n const results = useQueries({\n queries: projectExtIds.map((id) => ({\n queryKey: arbiQueryKeys.projectUsage(id, monthsBack),\n queryFn: () => arbi.projects.usage(id, monthsBack),\n enabled: enabled && !!id,\n })),\n })\n\n // Recompute only when a query's data actually changes (not on every parent\n // render — the dashboard re-renders often while a digest streams).\n const signature =\n results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join('|') +\n `#${projects.dataUpdatedAt}`\n\n return useMemo(() => {\n const dailyMap = new Map<string, AggregatedDailyUsage>()\n const modelMap = new Map<string, AggregatedModelGroupUsage>()\n let totalCredits = 0\n let anyData = false\n let anyMetered = false\n let totalTokens = 0\n let totalRequests = 0\n\n results.forEach((r, i) => {\n const d = r.data\n if (!d) return\n anyData = true\n const subscription = projects.data?.find(\n (p) => p.external_id === projectExtIds[i]\n )?.subscription\n if (isUsageMetered(d, subscription)) anyMetered = true\n totalCredits += d.total_spend ?? 0\n totalTokens += d.total_tokens ?? 0\n totalRequests += d.total_requests ?? 0\n\n for (const day of d.daily ?? []) {\n const cur = dailyMap.get(day.date) ?? {\n date: day.date,\n credits: 0,\n totalTokens: 0,\n apiRequests: 0,\n }\n cur.credits += day.spend ?? 0\n cur.totalTokens += day.total_tokens ?? 0\n cur.apiRequests += day.api_requests ?? 0\n dailyMap.set(day.date, cur)\n }\n\n for (const [model, mg] of Object.entries(d.model_groups ?? {})) {\n const cur = modelMap.get(model) ?? {\n model,\n credits: 0,\n totalTokens: 0,\n promptTokens: 0,\n completionTokens: 0,\n successfulRequests: 0,\n }\n cur.credits += mg.spend ?? 0\n cur.totalTokens += mg.total_tokens ?? 0\n cur.promptTokens += mg.prompt_tokens ?? 0\n cur.completionTokens += mg.completion_tokens ?? 0\n cur.successfulRequests += mg.successful_requests ?? 0\n modelMap.set(model, cur)\n }\n })\n\n return {\n totalCredits,\n totalTokens,\n totalRequests,\n daily: [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date)),\n modelGroups: [...modelMap.values()].sort(\n (a, b) => b.credits - a.credits || b.totalTokens - a.totalTokens\n ),\n metered: !anyData || anyMetered,\n isLoading: results.some((r) => r.isLoading),\n isError: results.some((r) => r.isError),\n }\n }, [signature])\n}\n\n/** List the Stripe invoices for a project's subscription. */\nexport function useProjectInvoices(\n projectExtId: string | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ''),\n queryFn: () => arbi.projects.invoices(projectExtId as string),\n enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn,\n })\n}\n\n/** Today's deployment-wide credit use for the current user (`credits_used`, in credits). */\nexport function useUserUsageToday(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.userUsageToday(),\n queryFn: () => arbi.user.usageToday(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n","/**\n * Helpers for markdown that is STORED (an agent's draft saved as an artifact, then read back from\n * the backend's parse). Pure and SDK-free; they sit next to `normalizeCitationMarkup`, which they\n * build on.\n *\n * Two directions:\n *\n * - Going in (`cleanDraftMarkdown` = `unwrapCitationLinks` + `stripAgentPreamble` +\n * `promoteBoldTitle`): a streamed draft carries citation links, `(*Source: ...*)` notes and\n * sometimes narration before the document. A stored letter should hold only the letter.\n * - Coming out (`unescapeMarkdown`): the backend's parse of a stored `.md` returns the text with\n * markdown punctuation backslash-escaped (`**Fees.**` comes back as `\\*\\*Fees\\.\\*\\*`).\n */\n\nimport { normalizeCitationMarkup } from './normalize-citations'\n\nconst FENCE = /^\\s*(```|~~~)/\n\n/** Run `fn` on every line outside a fenced code block. */\nfunction mapOutsideFences(text: string, fn: (line: string) => string): string {\n let inFence = false\n return text\n .split('\\n')\n .map((line) => {\n if (FENCE.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : fn(line)\n })\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Coming out: undo the parser's escaping\n// ---------------------------------------------------------------------------------------------\n\n/** A backslash followed by markdown punctuation: the only thing the parser's escaping produces. */\nconst ESCAPED_PUNCTUATION = /\\\\([\\\\`*_{}[\\]()#+\\-.!|>~<])/g\n/** The only escapes the parser puts inside an inline code span. */\nconst ESCAPED_EMPHASIS = /\\\\([*_])/g\nconst INLINE_CODE = /(`+)(?!`)(.+?)(?<!`)\\1(?!`)/g\n\n/**\n * Undo the backend's escaping of a markdown artifact: `\\*\\*Scope\\.\\*\\*` becomes `**Scope.**`.\n *\n * THE RULE. Apply this ONLY to text of an artifact that was stored from markdown (an agent draft\n * or an edited version, always uploaded as `.md`): for those the parser escapes every markdown\n * punctuation character, including the backslash itself, so removing one level of escaping is the\n * exact inverse (an author's literal `\\*` is stored as `\\\\\\*` and comes back as `\\*`). Do not\n * apply it to a PDF or Word parse, where a backslash is just a character.\n *\n * Details:\n * - Only a backslash followed by markdown punctuation (``\\ ` * _ { } [ ] ( ) # + - . ! | > ~ <``)\n * is removed; `\\n`, `C:\\temp` and a trailing backslash are left alone.\n * - Pairs are read left to right, so `\\\\*` is an escaped backslash followed by a bare `*`.\n * - Fenced code blocks are never touched (the parser does not escape inside them).\n * - Inline code spans: the parser DOES escape `*` and `_` there (`` `a*b` `` comes back as\n * `` `a\\*b` ``), so only `\\*` and `\\_` are undone inside a span; any other backslash in code\n * (`` `re\\.x` ``) is a literal and stays.\n */\nexport function unescapeMarkdown(text: string): string {\n if (!text.includes('\\\\')) return text\n return mapOutsideFences(text, (line) => {\n if (!line.includes('\\\\')) return line\n let out = ''\n let last = 0\n for (const span of line.matchAll(INLINE_CODE)) {\n const at = span.index ?? 0\n out +=\n line.slice(last, at).replace(ESCAPED_PUNCTUATION, '$1') +\n span[0].replace(ESCAPED_EMPHASIS, '$1')\n last = at + span[0].length\n }\n return out + line.slice(last).replace(ESCAPED_PUNCTUATION, '$1')\n })\n}\n\n/**\n * The parser also mangles the TITLE of a stored markdown document (seen on a real backend): the\n * first heading comes back doubled (`## # Title`) or alone inside a code fence\n * (a fence, `# Title`, a fence). Both are repaired, on the first non-blank line only, so a code\n * block or heading later in the text is never touched. Like `unescapeMarkdown`, apply it only to\n * artifacts stored from markdown.\n */\nexport function repairParsedTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const doubled = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/.exec(lines[first])\n if (doubled) {\n lines[first] = doubled[1]\n return lines.join('\\n')\n }\n if (/^\\s*```\\s*$/.test(lines[first]) && /^#{1,6}\\s+\\S/.test(lines[first + 1] ?? '')) {\n if (/^\\s*```\\s*$/.test(lines[first + 2] ?? '')) lines.splice(first + 2, 1)\n else return text\n lines.splice(first, 1)\n return lines.join('\\n')\n }\n return text\n}\n\nconst DOUBLED_HEADING = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_HEADING = /^[-*+]\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_IN_LIST = /^[-*+]\\s+[-*+]\\s+(\\S.*)$/\nconst LIST_ORDINAL = /^[-*+]\\s+(\\d{1,9})([.)])\\s+(\\S.*)$/\nconst LIST_ITEM_LINE = /^\\s*(?:[-*+]|\\d{1,9}[.)])\\s/\nconst TABLE_DELIMITER_CELL = /^:?-{1,}:?$/\n\n/** `1. a 2. b 3. c` (one line) split where the next ordinal follows: `['1. a', '2. b', '3. c']`. */\nfunction splitRunOfOrdinals(first: number, delimiter: string, rest: string): string[] {\n const items: string[] = []\n let n = first\n let remaining = rest\n for (;;) {\n const next = new RegExp(`^(.+?)\\\\s+${n + 1}\\\\${delimiter}\\\\s+(\\\\S.*)$`).exec(remaining)\n if (!next) break\n items.push(`${n}${delimiter} ${next[1]}`)\n n += 1\n remaining = next[2]\n }\n items.push(`${n}${delimiter} ${remaining}`)\n return items\n}\n\n/**\n * A table the parser put on ONE line (`| h | h | |---|---| | a | b |`, rows joined by a space, which\n * leaves one empty cell between rows) back as a pipe table. `null` when the line is not that shape.\n */\nfunction rebuildFlatTable(line: string): string[] | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null\n const cells = trimmed\n .slice(1, -1)\n .split('|')\n .map((c) => c.trim())\n const firstRule = cells.findIndex((c) => TABLE_DELIMITER_CELL.test(c))\n if (firstRule < 2 || cells[firstRule - 1] !== '') return null\n const columns = firstRule - 1\n const rows: string[][] = []\n for (let at = 0; at < cells.length; at += columns + 1) {\n const row = cells.slice(at, at + columns)\n const gap = cells[at + columns]\n if (row.length !== columns || (gap !== undefined && gap !== '')) return null\n rows.push(row)\n }\n const [header, rule, ...body] = rows\n if (!rule.every((c) => TABLE_DELIMITER_CELL.test(c))) return null\n const fmt = (row: string[]): string => `| ${row.join(' | ')} |`\n return [fmt(header), fmt(rule.map(() => '---')), ...body.map(fmt)]\n}\n\n/**\n * Undo how the backend's parse of a stored `.md` restructures it (seen on a real backend):\n * - a heading comes back doubled (`## # Title`) or as a list item (`- # Title`);\n * - every list item gets a `- ` of its own on top of the original marker, so `* a` returns as\n * `- * a` and `1. a` as `- 1. a`, which a markdown editor loads as a list inside a list item\n * (and saves as `- - a`); a run of ordinals can come back on one line (`- 1. a 2. b`);\n * - a table comes back on one line.\n * List nesting and the bullet/ordered difference of a flat `- x` cannot be recovered, so items\n * stay flat. Items of one list are kept tight (no blank line between them). Fenced code is\n * never touched. Like `unescapeMarkdown`, apply it only to artifacts stored from markdown.\n */\nexport function repairParsedStructure(text: string): string {\n const out: string[] = []\n let inFence = false\n for (const line of text.split('\\n')) {\n if (FENCE.test(line)) {\n inFence = !inFence\n out.push(line)\n continue\n }\n if (inFence) {\n out.push(line)\n continue\n }\n const table = rebuildFlatTable(line)\n if (table) {\n out.push(...table)\n continue\n }\n const heading = DOUBLED_HEADING.exec(line) ?? LIST_HEADING.exec(line)\n if (heading) {\n out.push(heading[1])\n continue\n }\n const ordinal = LIST_ORDINAL.exec(line)\n if (ordinal) {\n out.push(...splitRunOfOrdinals(Number(ordinal[1]), ordinal[2], ordinal[3]))\n continue\n }\n const nested = LIST_IN_LIST.exec(line)\n out.push(nested ? `- ${nested[1]}` : line)\n }\n // Items parsed as separate chunks arrive one blank line apart: that is one tight list.\n return out\n .filter(\n (line, i) =>\n !(\n line === '' &&\n LIST_ITEM_LINE.test(out[i - 1] ?? '') &&\n LIST_ITEM_LINE.test(out[i + 1] ?? '')\n )\n )\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Going in: clean a streamed draft before it is stored\n// ---------------------------------------------------------------------------------------------\n\n/** `(*Source: Terms.pdf*)`, `(Sources: a, b)` and the italic form `*(Source: ...)*`. */\nconst SOURCE_NOTE =\n /[ \\t]*(?:\\*+\\(\\s*Sources?\\s*:[^)\\n]*\\)\\*+|\\(\\s*\\*{0,2}\\s*Sources?\\s*:[^)\\n]*\\))/gi\nconst CITE_LINK = /\\[([^\\]\\n]+)\\]\\(#cite-[\\w-]+\\)/g\n\n/** A line whose `**` do not pair up (one half was wrapped into a link) loses the stray marks. */\nfunction balanceBold(line: string): string {\n // A bold-wrapped heading (`**# Title**`) is just a heading.\n if (/^\\s*\\*\\*#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '').trim()\n if ((line.match(/\\*\\*/g)?.length ?? 0) % 2 === 0) return line\n if (/^#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '')\n return line.replace(/\\*\\*\\s*$/, '').replace(/^(\\s*(?:[-*]\\s+)?)\\*\\*(?=\\s)/, '$1')\n}\n\n/**\n * Text for storage from text that carries citations: `normalizeCitationMarkup` first (it hoists\n * list, heading and bold tokens out of the link so unwrapping cannot orphan half of a `**` pair),\n * then `[text](#cite-N)` becomes `text`, `(*Source: ...*)` notes are dropped, and a bold or\n * heading marker that lost its partner is repaired. Fenced code is left alone.\n */\nexport function unwrapCitationLinks(text: string): string {\n const withoutNotes = mapOutsideFences(text, (line) => line.replace(SOURCE_NOTE, ''))\n return mapOutsideFences(normalizeCitationMarkup(withoutNotes), (line) => {\n const unlinked = line.includes('](#cite-') ? line.replace(CITE_LINK, '$1') : line\n return unlinked === line ? line : balanceBold(unlinked)\n })\n}\n\nconst HEADING = /^#{1,6}\\s/\n/** A whole-line bold title: `**Client Engagement Letter**`. */\nconst BOLD_LINE = /^\\*\\*[^*#].*[^*]\\*\\*$/\n/** How far down a bold line may sit and still be the document's title. */\nconst TITLE_SEARCH_LINES = 15\nconst MAX_PREAMBLE_CHARS = 1200\n\n/** First person, an announcement of the task or a pointer at the instructions: an agent talking. */\nconst NARRATION =\n /\\b(?:I|I'll|I’ll|I've|I’ve|I'm|I’m|I will|I have|I now|I am)\\b|\\b(?:let me|here is|here's|here’s|below is|per the instructions|as requested|based on (?:the|your)|the workspace (?:contains|has|does)|no (?:relevant )?documents? (?:were|was) found)\\b/i\n\n/** Structure a covering note would not have: lists, tables, quotes, code, headings. */\nconst STRUCTURED = /^\\s*(?:[-*+>|]|\\d{1,9}[.)]\\s|#{1,6}\\s|```|~~~)/m\n\n/**\n * Cut what an agent wrote BEFORE the document, when it is narration.\n *\n * HEURISTIC (conservative, so a document is never trimmed by mistake). The document is taken to\n * start at the first `#` heading, or, when there is none, at the first whole-line bold title within\n * the first 15 lines. The text before it is removed only when ALL of these hold:\n * 1. it is short (at most 1200 characters);\n * 2. it is plain prose: no list, table, quote, code or heading;\n * 3. it reads like the agent talking: first person (\"I'll draft ...\"), \"Here is ...\", \"Per the\n * instructions\", \"Based on the ...\" and the like.\n * A document that opens with a dateline, an address or any text that does not trip rule 3 is kept\n * whole. A horizontal rule left at the end of the cut text is dropped with it.\n */\nexport function stripAgentPreamble(text: string): string {\n const lines = text.split('\\n')\n let start = lines.findIndex((l) => HEADING.test(l))\n if (start < 0)\n start = lines.slice(0, TITLE_SEARCH_LINES).findIndex((l) => BOLD_LINE.test(l.trim()))\n if (start <= 0) return text\n const before = lines.slice(0, start).join('\\n').trim()\n if (!before) return lines.slice(start).join('\\n')\n const prose = before.replace(/^\\s*(?:-{3,}|\\*{3,}|_{3,})\\s*$/gm, '').trim()\n if (prose.length > MAX_PREAMBLE_CHARS || STRUCTURED.test(prose) || !NARRATION.test(prose)) {\n return text\n }\n return lines.slice(start).join('\\n')\n}\n\n/**\n * Make the document's title a real heading: a first line that is a bold title (`**Letter**`, even\n * with stray inner `**`) becomes `# Letter`. A document that already opens with a heading is left\n * alone.\n */\nexport function promoteBoldTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const title = lines[first].trim()\n if (!/^\\*\\*[^*#]/.test(title) || title.length >= 160 || !/\\*\\*$/.test(title)) return text\n lines[first] = `# ${title.replace(/\\*\\*/g, '').trim()}`\n return lines.join('\\n')\n}\n\n/** Tidy headings only: strip stray bold marks from heading lines (`# **Title**`). */\nfunction cleanHeadings(text: string): string {\n return mapOutsideFences(text, (line) =>\n /^\\s*#{1,6}\\s/.test(line) ? line.replace(/\\*\\*/g, '').trim() : line\n )\n}\n\n/**\n * Everything a streamed draft needs before it is stored as the artifact's first version:\n * `unwrapCitationLinks`, `stripAgentPreamble`, `promoteBoldTitle`, clean headings, collapsed blank\n * runs, trimmed.\n */\nexport function cleanDraftMarkdown(raw: string): string {\n const stripped = stripAgentPreamble(unwrapCitationLinks(raw))\n return cleanHeadings(promoteBoldTitle(stripped))\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n}\n"]}