@arbidocs/react 0.5.125 → 0.5.127

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/artifacts/index.cjs +81 -38
  2. package/dist/artifacts/index.cjs.map +1 -1
  3. package/dist/artifacts/index.d.ts +3 -0
  4. package/dist/artifacts/useArtifactSession.js +48 -4
  5. package/dist/artifacts/useArtifactSession.js.map +2 -2
  6. package/dist/artifacts/versions.js +2 -1
  7. package/dist/artifacts/versions.js.map +2 -2
  8. package/dist/calls/livekit/index.cjs +42 -42
  9. package/dist/chat/turn-flush.js +3 -3
  10. package/dist/chat/turn-flush.js.map +2 -2
  11. package/dist/{chunk-WUYSVTKE.cjs → chunk-6RRKO4ZK.cjs} +4 -4
  12. package/dist/{chunk-WUYSVTKE.cjs.map → chunk-6RRKO4ZK.cjs.map} +1 -1
  13. package/dist/{chunk-FAJLJDWS.cjs → chunk-FOBB5U4Y.cjs} +5 -5
  14. package/dist/{chunk-FAJLJDWS.cjs.map → chunk-FOBB5U4Y.cjs.map} +1 -1
  15. package/dist/{chunk-3JAEX57E.cjs → chunk-G5DYDBQN.cjs} +4 -4
  16. package/dist/{chunk-3JAEX57E.cjs.map → chunk-G5DYDBQN.cjs.map} +1 -1
  17. package/dist/{chunk-7L7QRIQ2.cjs → chunk-H3XHBIZ6.cjs} +5 -5
  18. package/dist/{chunk-7L7QRIQ2.cjs.map → chunk-H3XHBIZ6.cjs.map} +1 -1
  19. package/dist/{chunk-NDIKMOBJ.cjs → chunk-KULS4YWP.cjs} +4 -3
  20. package/dist/chunk-KULS4YWP.cjs.map +1 -0
  21. package/dist/{chunk-GKGAPU6T.cjs → chunk-NK5KFHXP.cjs} +17 -2
  22. package/dist/chunk-NK5KFHXP.cjs.map +1 -0
  23. package/dist/{chunk-K6ELFSG6.cjs → chunk-TNJ5T2MV.cjs} +25 -25
  24. package/dist/{chunk-K6ELFSG6.cjs.map → chunk-TNJ5T2MV.cjs.map} +1 -1
  25. package/dist/document-tools/core.cjs +97 -97
  26. package/dist/document-tools/core.d.ts +1 -0
  27. package/dist/document-tools/index.cjs +99 -99
  28. package/dist/index.cjs +809 -806
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +20 -11
  31. package/dist/remote-control.js +12 -2
  32. package/dist/remote-control.js.map +2 -2
  33. package/dist/shell/index.cjs +38 -38
  34. package/package.json +3 -3
  35. package/dist/chunk-GKGAPU6T.cjs.map +0 -1
  36. package/dist/chunk-NDIKMOBJ.cjs.map +0 -1
package/dist/index.d.ts CHANGED
@@ -3157,20 +3157,12 @@ declare function createStreamHandlers(ctx: StreamHandlerContext, params: StreamH
3157
3157
  /** The stream handlers of this host's chat (its cache, session and chat host). */
3158
3158
  declare function useStreamHandlers(): (params: StreamHandlerParams) => StreamHandlers;
3159
3159
 
3160
- /**
3161
- * Saving a document before a chat turn works on it. An editor whose changes live only on screen
3162
- * (the slides editor: no live co-editing) registers how to save them; a turn that names that
3163
- * document (`active_artifact_ext_id`) awaits it first, so ARBI reads and edits what the person
3164
- * sees, not the version saved before their last changes.
3165
- */
3160
+ /** Mounted editors save their local changes before any chat turn reads the workspace. */
3166
3161
  type Flush = () => Promise<void>;
3167
3162
  /** While mounted, `flush` saves `documentId`'s unsaved changes; returns the unregister. */
3168
3163
  declare function registerDocumentTurnFlush(documentId: string, flush: Flush): () => void;
3169
- /**
3170
- * The save of the document a turn names, if an editor registered one; null otherwise, so a turn
3171
- * about anything else is not delayed at all (not even by a microtask).
3172
- */
3173
- declare function flushDocumentForTurn(documentId: string | null | undefined): Promise<void> | null;
3164
+ /** Save every mounted editor before a turn reads workspace documents. */
3165
+ declare function flushDocumentForTurn(_documentId: string | null | undefined): Promise<void> | null;
3174
3166
 
3175
3167
  /**
3176
3168
  * A conversation's bound document in the query cache, and the writes that change it on the server.
@@ -3508,6 +3500,7 @@ declare function useConversationDocuments(): {
3508
3500
  config_ext_id?: string | null;
3509
3501
  parent_ext_id?: string | null;
3510
3502
  current_version: number;
3503
+ autosave: boolean;
3511
3504
  versions: components["schemas"]["DocVersion"][];
3512
3505
  thread_id?: string | null;
3513
3506
  derived_from: components["schemas"]["DerivedFrom"][];
@@ -4380,6 +4373,7 @@ declare function useDocumentVersionList(docId: string | null | undefined, option
4380
4373
  n_chunks?: number | null | undefined;
4381
4374
  made_from?: number | null | undefined;
4382
4375
  is_current: boolean;
4376
+ autosave: boolean;
4383
4377
  markup_revision: number;
4384
4378
  markup_count: number;
4385
4379
  source_message_ext_id?: string | null | undefined;
@@ -8533,6 +8527,7 @@ declare function useSetSkillVisibility(): _tanstack_react_query.UseMutationResul
8533
8527
  config_ext_id?: string | null | undefined;
8534
8528
  parent_ext_id?: string | null | undefined;
8535
8529
  current_version: number;
8530
+ autosave: boolean;
8536
8531
  versions: {
8537
8532
  n: number;
8538
8533
  created_at?: string | null | undefined;
@@ -8547,6 +8542,7 @@ declare function useSetSkillVisibility(): _tanstack_react_query.UseMutationResul
8547
8542
  n_chunks?: number | null | undefined;
8548
8543
  made_from?: number | null | undefined;
8549
8544
  is_current: boolean;
8545
+ autosave: boolean;
8550
8546
  markup_revision: number;
8551
8547
  markup_count: number;
8552
8548
  source_message_ext_id?: string | null | undefined;
@@ -13270,6 +13266,7 @@ declare function useWorkspaceDocs(workspaceId?: string): {
13270
13266
  config_ext_id?: string | null;
13271
13267
  parent_ext_id?: string | null;
13272
13268
  current_version: number;
13269
+ autosave: boolean;
13273
13270
  versions: _arbidocs_client.components["schemas"]["DocVersion"][];
13274
13271
  thread_id?: string | null;
13275
13272
  derived_from: _arbidocs_client.components["schemas"]["DerivedFrom"][];
@@ -14770,6 +14767,7 @@ declare function useDocuments(workspaceId?: string | null, options?: {
14770
14767
  config_ext_id?: string | null;
14771
14768
  parent_ext_id?: string | null;
14772
14769
  current_version: number;
14770
+ autosave: boolean;
14773
14771
  versions: _arbidocs_client.components["schemas"]["DocVersion"][];
14774
14772
  thread_id?: string | null;
14775
14773
  derived_from: _arbidocs_client.components["schemas"]["DerivedFrom"][];
@@ -14813,6 +14811,7 @@ declare function useDocument(docId: string | null | undefined, options?: {
14813
14811
  config_ext_id?: string | null;
14814
14812
  parent_ext_id?: string | null;
14815
14813
  current_version: number;
14814
+ autosave: boolean;
14816
14815
  versions: _arbidocs_client.components["schemas"]["DocVersion"][];
14817
14816
  thread_id?: string | null;
14818
14817
  derived_from: _arbidocs_client.components["schemas"]["DerivedFrom"][];
@@ -14995,6 +14994,7 @@ declare function useUpdateDocuments(): _tanstack_react_query.UseMutationResult<{
14995
14994
  config_ext_id?: string | null;
14996
14995
  parent_ext_id?: string | null;
14997
14996
  current_version: number;
14997
+ autosave: boolean;
14998
14998
  versions: components["schemas"]["DocVersion"][];
14999
14999
  thread_id?: string | null;
15000
15000
  derived_from: components["schemas"]["DerivedFrom"][];
@@ -15043,6 +15043,7 @@ interface UploadUrlsInput {
15043
15043
  declare function useUploadUrls(): _tanstack_react_query.UseMutationResult<{
15044
15044
  doc_ext_ids?: string[] | undefined;
15045
15045
  version?: number | null | undefined;
15046
+ autosave?: boolean | null | undefined;
15046
15047
  batch_id?: string | null | undefined;
15047
15048
  skipped?: {
15048
15049
  file_name: string;
@@ -15772,6 +15773,7 @@ declare function useKeepDocumentsOffline(): _tanstack_react_query.UseMutationRes
15772
15773
  config_ext_id?: string | null;
15773
15774
  parent_ext_id?: string | null;
15774
15775
  current_version: number;
15776
+ autosave: boolean;
15775
15777
  versions: _arbidocs_client.components["schemas"]["DocVersion"][];
15776
15778
  thread_id?: string | null;
15777
15779
  derived_from: _arbidocs_client.components["schemas"]["DerivedFrom"][];
@@ -15847,6 +15849,10 @@ interface RemoteControlRequest {
15847
15849
  sequenceId?: string;
15848
15850
  /** An ad-hoc guided run to execute (used when no registered sequence fits). */
15849
15851
  steps?: GuidedStep[];
15852
+ actionRequestId?: string;
15853
+ screenRequestId?: string;
15854
+ screenQuestion?: string;
15855
+ workspaceExtId?: string;
15850
15856
  }
15851
15857
  /** The agent whose run is actively executing — drives the "controlling" banner. */
15852
15858
  interface ControllingAgent {
@@ -15857,6 +15863,8 @@ interface ControllingAgent {
15857
15863
  interface RemoteControlState {
15858
15864
  /** Whether WS-driven runs may execute without re-prompting this session. */
15859
15865
  enabled: boolean;
15866
+ /** A browser-authorized screen stream is active. Never persisted. */
15867
+ sharing?: boolean;
15860
15868
  /** The in-flight consent request awaiting the user's decision, or null. */
15861
15869
  pending: RemoteControlRequest | null;
15862
15870
  /** Set while a WS-driven run is actively executing (labels the banner). */
@@ -15884,6 +15892,7 @@ declare function remoteControlActions(session: RemoteControlSession): {
15884
15892
  /** Directly set the session enabled flag. Turning it OFF revokes immediately: clears any
15885
15893
  * pending prompt and the controlling banner (GUARANTEE #5). */
15886
15894
  setEnabled: (enabled: boolean) => void;
15895
+ setSharing: (sharing: boolean) => void;
15887
15896
  /** Set (or clear) the agent whose run is currently executing. */
15888
15897
  setControllingAgent: (agent: ControllingAgent | null) => void;
15889
15898
  /** Back to the session start: off, nothing pending, nobody driving (a sign-in or sign-out). */
@@ -22,6 +22,7 @@ function remoteControlActions(session) {
22
22
  /** Directly set the session enabled flag. Turning it OFF revokes immediately: clears any
23
23
  * pending prompt and the controlling banner (GUARANTEE #5). */
24
24
  setEnabled: (enabled) => update(() => enabled ? { enabled } : { enabled, pending: null, controllingAgent: null }),
25
+ setSharing: (sharing) => update(() => ({ sharing })),
25
26
  /** Set (or clear) the agent whose run is currently executing. */
26
27
  setControllingAgent: (agent) => update(() => ({ controllingAgent: agent })),
27
28
  /** Back to the session start: off, nothing pending, nobody driving (a sign-in or sign-out). */
@@ -44,7 +45,7 @@ function toGuidedSteps(steps) {
44
45
  function toRemoteControlRequest(msg, isSequenceId) {
45
46
  const steps = hasRunnableSteps(msg.steps) ? toGuidedSteps(msg.steps) : void 0;
46
47
  const sequenceId = typeof msg.sequence_id === "string" && isSequenceId(msg.sequence_id) ? msg.sequence_id : void 0;
47
- if (!steps && !sequenceId) {
48
+ if (!steps && !sequenceId && !(msg.screen_request_id && msg.workspace_ext_id)) {
48
49
  logger.warn("[RemoteControl] Ignoring message with no runnable action", msg.sequence_id);
49
50
  return null;
50
51
  }
@@ -54,7 +55,16 @@ function toRemoteControlRequest(msg, isSequenceId) {
54
55
  agentName: msg.agent_name.trim() || "An assistant",
55
56
  agentExtId: msg.agent_ext_id ?? void 0,
56
57
  sequenceId,
57
- steps
58
+ steps,
59
+ ...msg.action_request_id ? {
60
+ actionRequestId: msg.action_request_id,
61
+ workspaceExtId: msg.workspace_ext_id ?? void 0
62
+ } : {},
63
+ ...msg.screen_request_id ? {
64
+ screenRequestId: msg.screen_request_id,
65
+ screenQuestion: msg.screen_question ?? void 0,
66
+ workspaceExtId: msg.workspace_ext_id ?? void 0
67
+ } : {}
58
68
  };
59
69
  }
60
70
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/remote-control.ts"],
4
- "sourcesContent": ["/**\n * Remote control's session state and its websocket message: an `agt-\u2026` assistant asks to drive\n * the UI over the live connection (`remote_control`), and the user's consent decides whether it\n * may. The guided run itself (the cursor, the clicks) is `@arbidocs/blocks`' (`createRemoteControl`).\n *\n * GUARANTEE #1: `enabled` is `false` at the start of EVERY session and is NEVER saved. The state is\n * a transient view of the session's layout (`views.transient`), which the layout never saves. Every\n * sign-in and sign-out drops it: `@arbidocs/blocks`' remote control resets it (`reset`) on the\n * host's sign-in, sign-out, expiry and change of user, on every host, and a host's own\n * `resetLayout` drops it too.\n *\n * The actions here are pure state. Running the requested run (and labelling the driver for its\n * duration) is the orchestration layer's.\n *\n * \u2500\u2500 BACKEND WS CONTRACT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Message `type`: `'remote_control'`. Payload (snake_case, matching the other WS messages):\n * {\n * type: 'remote_control',\n * agent_name: string, // display name of the requesting agent\n * agent_ext_id?: string, // the agent's `agt-\u2026` external id\n * sequence_id?: string, // a REGISTERED guided-run id\n * steps?: GuidedStep[], // OR an inline guided run (target-based)\n * }\n * Exactly one of `sequence_id` / `steps` is expected. An unknown `sequence_id`, a `steps` list with\n * no valid target, and an empty/absent run are all ignored.\n */\nimport type { components } from '@arbidocs/client'\nimport { logger } from '@arbidocs/client'\nimport type { ArbiSessionState, ArbiSessionStore } from './session'\nimport { useArbiSessionState } from './session'\n\n/** The websocket message: an `agt-\u2026` agent asks to drive the UI (exactly one of `sequence_id` /\n * `steps`). The generated schema type is the single source of truth. */\nexport type RemoteControlMessage = components['schemas']['RemoteControlMessage']\n/** One guided-cursor step, as on the wire (nullable JSON fields). */\ntype RemoteControlStep = components['schemas']['RemoteControlStep']\n\n/** One UI operation: glide the cursor to `target`, then perform `do` on it. */\nexport interface GuidedStep {\n /** `[data-testid=...]` (or any CSS selector) the cursor glides to and acts on. */\n target: string\n /** Interaction once the cursor arrives. Defaults to 'click'. */\n do?: 'click' | 'type'\n /** Text to type for `do: 'type'`. */\n value?: string\n /** Narration toast shown when the step runs. */\n note?: string\n /** Pause (ms) AFTER this step, before the next. */\n pauseMs?: number\n /** Max ms to wait for the target to appear (it may follow a prior step). */\n waitMs?: number\n}\n\n/** A remote-control run requested by a backend agent (name always present so the consent prompt\n * can name who is asking \u2014 GUARANTEE #3). Carries either a registered `sequenceId` or an inline\n * `steps` list to execute. */\nexport interface RemoteControlRequest {\n /** Display name of the requesting assistant, e.g. \"Research Assistant\". */\n agentName: string\n /** The assistant's `agt-\u2026` external id, shown so the user knows which agent. */\n agentExtId?: string\n /** A registered guided-run id to execute. */\n sequenceId?: string\n /** An ad-hoc guided run to execute (used when no registered sequence fits). */\n steps?: GuidedStep[]\n}\n\n/** The agent whose run is actively executing \u2014 drives the \"controlling\" banner. */\nexport interface ControllingAgent {\n name: string\n extId?: string\n}\n\n/** Session-only remote-control state (never saved \u2014 see the file header). */\nexport interface RemoteControlState {\n /** Whether WS-driven runs may execute without re-prompting this session. */\n enabled: boolean\n /** The in-flight consent request awaiting the user's decision, or null. */\n pending: RemoteControlRequest | null\n /** Set while a WS-driven run is actively executing (labels the banner). */\n controllingAgent: ControllingAgent | null\n}\n\n/** The session the state lives in. */\nexport type RemoteControlSession = Pick<ArbiSessionStore, 'getState' | 'setTransientView'>\n\n/** The transient view that holds the state. */\nexport const REMOTE_CONTROL_VIEW = 'actions.remoteControl'\nconst OFF: RemoteControlState = { enabled: false, pending: null, controllingAgent: null }\n\n/** The remote-control state of a session state. */\nexport const remoteControlStateOf = (state: Pick<ArbiSessionState, 'views'>): RemoteControlState =>\n (state.views.transient[REMOTE_CONTROL_VIEW] as RemoteControlState | undefined) ?? OFF\n\n/** A slice of the remote-control state of the host's session; re-renders when it changes. */\nexport function useRemoteControl<T>(selector: (state: RemoteControlState) => T): T {\n return useArbiSessionState((state) => selector(remoteControlStateOf(state)))\n}\n\n/** The state's actions on a session. */\nexport function remoteControlActions(session: RemoteControlSession) {\n const update = (change: (state: RemoteControlState) => Partial<RemoteControlState>): void => {\n const state = remoteControlStateOf(session.getState())\n session.setTransientView(REMOTE_CONTROL_VIEW, { ...state, ...change(state) })\n }\n return {\n /** Stash a requested run and open the consent prompt (`pending` set). */\n request: (req: RemoteControlRequest): void => update(() => ({ pending: req })),\n /** Resolve the pending request: `forSession` enables it for the whole session; either way\n * the pending request is cleared. Running it is the caller's job. */\n grant: ({ forSession }: { forSession: boolean }): void =>\n update((state) => ({ enabled: forSession || state.enabled, pending: null })),\n /** Reject the pending request \u2014 clears it, changes nothing else. */\n deny: (): void => update(() => ({ pending: null })),\n /** Directly set the session enabled flag. Turning it OFF revokes immediately: clears any\n * pending prompt and the controlling banner (GUARANTEE #5). */\n setEnabled: (enabled: boolean): void =>\n update(() => (enabled ? { enabled } : { enabled, pending: null, controllingAgent: null })),\n /** Set (or clear) the agent whose run is currently executing. */\n setControllingAgent: (agent: ControllingAgent | null): void =>\n update(() => ({ controllingAgent: agent })),\n /** Back to the session start: off, nothing pending, nobody driving (a sign-in or sign-out). */\n reset: (): void => session.setTransientView(REMOTE_CONTROL_VIEW, undefined),\n }\n}\n\n/** A runnable steps list: a non-empty array whose every step has a real target selector \u2014 the\n * one field the runner cannot act without. Operates on the wire step (nullable JSON fields). */\nfunction hasRunnableSteps(\n steps: RemoteControlStep[] | null | undefined\n): steps is RemoteControlStep[] {\n return (\n Array.isArray(steps) &&\n steps.length > 0 &&\n steps.every((s) => typeof s?.target === 'string' && s.target.length > 0)\n )\n}\n\n/** Normalise wire steps (nullable JSON fields) into plain optionals \u2014 a `null` off the socket\n * becomes an absent field. */\nfunction toGuidedSteps(steps: RemoteControlStep[]): GuidedStep[] {\n return steps.map((s) => ({\n target: s.target,\n do: s.do ?? undefined,\n value: s.value ?? undefined,\n note: s.note ?? undefined,\n pauseMs: s.pauseMs ?? undefined,\n waitMs: s.waitMs ?? undefined,\n }))\n}\n\n/**\n * Narrow an incoming message into a request, or null if nothing is runnable: inline steps that\n * all have a target, or a `sequence_id` the site registered (`isSequenceId`).\n */\nexport function toRemoteControlRequest(\n msg: RemoteControlMessage,\n isSequenceId: (id: string) => boolean\n): RemoteControlRequest | null {\n const steps = hasRunnableSteps(msg.steps) ? toGuidedSteps(msg.steps) : undefined\n const sequenceId =\n typeof msg.sequence_id === 'string' && isSequenceId(msg.sequence_id)\n ? msg.sequence_id\n : undefined\n if (!steps && !sequenceId) {\n logger.warn('[RemoteControl] Ignoring message with no runnable action', msg.sequence_id)\n return null\n }\n return {\n // The agent is always named in the prompt; fall back to a neutral label rather than leaving\n // the consent dialog anonymous.\n agentName: msg.agent_name.trim() || 'An assistant',\n agentExtId: msg.agent_ext_id ?? undefined,\n sequenceId,\n steps,\n }\n}\n"],
5
- "mappings": "AA2BA,SAAS,cAAc;AAEvB,SAAS,2BAA2B;AA0D7B,MAAM,sBAAsB;AACnC,MAAM,MAA0B,EAAE,SAAS,OAAO,SAAS,MAAM,kBAAkB,KAAK;AAGjF,MAAM,uBAAuB,CAAC,UAClC,MAAM,MAAM,UAAU,mBAAmB,KAAwC;AAG7E,SAAS,iBAAoB,UAA+C;AACjF,SAAO,oBAAoB,CAAC,UAAU,SAAS,qBAAqB,KAAK,CAAC,CAAC;AAC7E;AAGO,SAAS,qBAAqB,SAA+B;AAClE,QAAM,SAAS,CAAC,WAA6E;AAC3F,UAAM,QAAQ,qBAAqB,QAAQ,SAAS,CAAC;AACrD,YAAQ,iBAAiB,qBAAqB,EAAE,GAAG,OAAO,GAAG,OAAO,KAAK,EAAE,CAAC;AAAA,EAC9E;AACA,SAAO;AAAA;AAAA,IAEL,SAAS,CAAC,QAAoC,OAAO,OAAO,EAAE,SAAS,IAAI,EAAE;AAAA;AAAA;AAAA,IAG7E,OAAO,CAAC,EAAE,WAAW,MACnB,OAAO,CAAC,WAAW,EAAE,SAAS,cAAc,MAAM,SAAS,SAAS,KAAK,EAAE;AAAA;AAAA,IAE7E,MAAM,MAAY,OAAO,OAAO,EAAE,SAAS,KAAK,EAAE;AAAA;AAAA;AAAA,IAGlD,YAAY,CAAC,YACX,OAAO,MAAO,UAAU,EAAE,QAAQ,IAAI,EAAE,SAAS,SAAS,MAAM,kBAAkB,KAAK,CAAE;AAAA;AAAA,IAE3F,qBAAqB,CAAC,UACpB,OAAO,OAAO,EAAE,kBAAkB,MAAM,EAAE;AAAA;AAAA,IAE5C,OAAO,MAAY,QAAQ,iBAAiB,qBAAqB,MAAS;AAAA,EAC5E;AACF;AAIA,SAAS,iBACP,OAC8B;AAC9B,SACE,MAAM,QAAQ,KAAK,KACnB,MAAM,SAAS,KACf,MAAM,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,YAAY,EAAE,OAAO,SAAS,CAAC;AAE3E;AAIA,SAAS,cAAc,OAA0C;AAC/D,SAAO,MAAM,IAAI,CAAC,OAAO;AAAA,IACvB,QAAQ,EAAE;AAAA,IACV,IAAI,EAAE,MAAM;AAAA,IACZ,OAAO,EAAE,SAAS;AAAA,IAClB,MAAM,EAAE,QAAQ;AAAA,IAChB,SAAS,EAAE,WAAW;AAAA,IACtB,QAAQ,EAAE,UAAU;AAAA,EACtB,EAAE;AACJ;AAMO,SAAS,uBACd,KACA,cAC6B;AAC7B,QAAM,QAAQ,iBAAiB,IAAI,KAAK,IAAI,cAAc,IAAI,KAAK,IAAI;AACvE,QAAM,aACJ,OAAO,IAAI,gBAAgB,YAAY,aAAa,IAAI,WAAW,IAC/D,IAAI,cACJ;AACN,MAAI,CAAC,SAAS,CAAC,YAAY;AACzB,WAAO,KAAK,4DAA4D,IAAI,WAAW;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AAAA;AAAA;AAAA,IAGL,WAAW,IAAI,WAAW,KAAK,KAAK;AAAA,IACpC,YAAY,IAAI,gBAAgB;AAAA,IAChC;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["/**\n * Remote control's session state and its websocket message: an `agt-\u2026` assistant asks to drive\n * the UI over the live connection (`remote_control`), and the user's consent decides whether it\n * may. The guided run itself (the cursor, the clicks) is `@arbidocs/blocks`' (`createRemoteControl`).\n *\n * GUARANTEE #1: `enabled` is `false` at the start of EVERY session and is NEVER saved. The state is\n * a transient view of the session's layout (`views.transient`), which the layout never saves. Every\n * sign-in and sign-out drops it: `@arbidocs/blocks`' remote control resets it (`reset`) on the\n * host's sign-in, sign-out, expiry and change of user, on every host, and a host's own\n * `resetLayout` drops it too.\n *\n * The actions here are pure state. Running the requested run (and labelling the driver for its\n * duration) is the orchestration layer's.\n *\n * \u2500\u2500 BACKEND WS CONTRACT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Message `type`: `'remote_control'`. Payload (snake_case, matching the other WS messages):\n * {\n * type: 'remote_control',\n * agent_name: string, // display name of the requesting agent\n * agent_ext_id?: string, // the agent's `agt-\u2026` external id\n * sequence_id?: string, // a REGISTERED guided-run id\n * steps?: GuidedStep[], // OR an inline guided run (target-based)\n * }\n * Exactly one of `sequence_id` / `steps` is expected. An unknown `sequence_id`, a `steps` list with\n * no valid target, and an empty/absent run are all ignored.\n */\nimport type { components } from '@arbidocs/client'\nimport { logger } from '@arbidocs/client'\nimport type { ArbiSessionState, ArbiSessionStore } from './session'\nimport { useArbiSessionState } from './session'\n\n/** The websocket message: an `agt-\u2026` agent asks to drive the UI (exactly one of `sequence_id` /\n * `steps`). The generated schema type is the single source of truth. */\nexport type RemoteControlMessage = components['schemas']['RemoteControlMessage']\n/** One guided-cursor step, as on the wire (nullable JSON fields). */\ntype RemoteControlStep = components['schemas']['RemoteControlStep']\n\n/** One UI operation: glide the cursor to `target`, then perform `do` on it. */\nexport interface GuidedStep {\n /** `[data-testid=...]` (or any CSS selector) the cursor glides to and acts on. */\n target: string\n /** Interaction once the cursor arrives. Defaults to 'click'. */\n do?: 'click' | 'type'\n /** Text to type for `do: 'type'`. */\n value?: string\n /** Narration toast shown when the step runs. */\n note?: string\n /** Pause (ms) AFTER this step, before the next. */\n pauseMs?: number\n /** Max ms to wait for the target to appear (it may follow a prior step). */\n waitMs?: number\n}\n\n/** A remote-control run requested by a backend agent (name always present so the consent prompt\n * can name who is asking \u2014 GUARANTEE #3). Carries either a registered `sequenceId` or an inline\n * `steps` list to execute. */\nexport interface RemoteControlRequest {\n /** Display name of the requesting assistant, e.g. \"Research Assistant\". */\n agentName: string\n /** The assistant's `agt-\u2026` external id, shown so the user knows which agent. */\n agentExtId?: string\n /** A registered guided-run id to execute. */\n sequenceId?: string\n /** An ad-hoc guided run to execute (used when no registered sequence fits). */\n steps?: GuidedStep[]\n actionRequestId?: string\n screenRequestId?: string\n screenQuestion?: string\n workspaceExtId?: string\n}\n\n/** The agent whose run is actively executing \u2014 drives the \"controlling\" banner. */\nexport interface ControllingAgent {\n name: string\n extId?: string\n}\n\n/** Session-only remote-control state (never saved \u2014 see the file header). */\nexport interface RemoteControlState {\n /** Whether WS-driven runs may execute without re-prompting this session. */\n enabled: boolean\n /** A browser-authorized screen stream is active. Never persisted. */\n sharing?: boolean\n /** The in-flight consent request awaiting the user's decision, or null. */\n pending: RemoteControlRequest | null\n /** Set while a WS-driven run is actively executing (labels the banner). */\n controllingAgent: ControllingAgent | null\n}\n\n/** The session the state lives in. */\nexport type RemoteControlSession = Pick<ArbiSessionStore, 'getState' | 'setTransientView'>\n\n/** The transient view that holds the state. */\nexport const REMOTE_CONTROL_VIEW = 'actions.remoteControl'\nconst OFF: RemoteControlState = { enabled: false, pending: null, controllingAgent: null }\n\n/** The remote-control state of a session state. */\nexport const remoteControlStateOf = (state: Pick<ArbiSessionState, 'views'>): RemoteControlState =>\n (state.views.transient[REMOTE_CONTROL_VIEW] as RemoteControlState | undefined) ?? OFF\n\n/** A slice of the remote-control state of the host's session; re-renders when it changes. */\nexport function useRemoteControl<T>(selector: (state: RemoteControlState) => T): T {\n return useArbiSessionState((state) => selector(remoteControlStateOf(state)))\n}\n\n/** The state's actions on a session. */\nexport function remoteControlActions(session: RemoteControlSession) {\n const update = (change: (state: RemoteControlState) => Partial<RemoteControlState>): void => {\n const state = remoteControlStateOf(session.getState())\n session.setTransientView(REMOTE_CONTROL_VIEW, { ...state, ...change(state) })\n }\n return {\n /** Stash a requested run and open the consent prompt (`pending` set). */\n request: (req: RemoteControlRequest): void => update(() => ({ pending: req })),\n /** Resolve the pending request: `forSession` enables it for the whole session; either way\n * the pending request is cleared. Running it is the caller's job. */\n grant: ({ forSession }: { forSession: boolean }): void =>\n update((state) => ({ enabled: forSession || state.enabled, pending: null })),\n /** Reject the pending request \u2014 clears it, changes nothing else. */\n deny: (): void => update(() => ({ pending: null })),\n /** Directly set the session enabled flag. Turning it OFF revokes immediately: clears any\n * pending prompt and the controlling banner (GUARANTEE #5). */\n setEnabled: (enabled: boolean): void =>\n update(() => (enabled ? { enabled } : { enabled, pending: null, controllingAgent: null })),\n setSharing: (sharing: boolean): void => update(() => ({ sharing })),\n /** Set (or clear) the agent whose run is currently executing. */\n setControllingAgent: (agent: ControllingAgent | null): void =>\n update(() => ({ controllingAgent: agent })),\n /** Back to the session start: off, nothing pending, nobody driving (a sign-in or sign-out). */\n reset: (): void => session.setTransientView(REMOTE_CONTROL_VIEW, undefined),\n }\n}\n\n/** A runnable steps list: a non-empty array whose every step has a real target selector \u2014 the\n * one field the runner cannot act without. Operates on the wire step (nullable JSON fields). */\nfunction hasRunnableSteps(\n steps: RemoteControlStep[] | null | undefined\n): steps is RemoteControlStep[] {\n return (\n Array.isArray(steps) &&\n steps.length > 0 &&\n steps.every((s) => typeof s?.target === 'string' && s.target.length > 0)\n )\n}\n\n/** Normalise wire steps (nullable JSON fields) into plain optionals \u2014 a `null` off the socket\n * becomes an absent field. */\nfunction toGuidedSteps(steps: RemoteControlStep[]): GuidedStep[] {\n return steps.map((s) => ({\n target: s.target,\n do: s.do ?? undefined,\n value: s.value ?? undefined,\n note: s.note ?? undefined,\n pauseMs: s.pauseMs ?? undefined,\n waitMs: s.waitMs ?? undefined,\n }))\n}\n\n/**\n * Narrow an incoming message into a request, or null if nothing is runnable: inline steps that\n * all have a target, or a `sequence_id` the site registered (`isSequenceId`).\n */\nexport function toRemoteControlRequest(\n msg: RemoteControlMessage,\n isSequenceId: (id: string) => boolean\n): RemoteControlRequest | null {\n const steps = hasRunnableSteps(msg.steps) ? toGuidedSteps(msg.steps) : undefined\n const sequenceId =\n typeof msg.sequence_id === 'string' && isSequenceId(msg.sequence_id)\n ? msg.sequence_id\n : undefined\n if (!steps && !sequenceId && !(msg.screen_request_id && msg.workspace_ext_id)) {\n logger.warn('[RemoteControl] Ignoring message with no runnable action', msg.sequence_id)\n return null\n }\n return {\n // The agent is always named in the prompt; fall back to a neutral label rather than leaving\n // the consent dialog anonymous.\n agentName: msg.agent_name.trim() || 'An assistant',\n agentExtId: msg.agent_ext_id ?? undefined,\n sequenceId,\n steps,\n ...(msg.action_request_id\n ? {\n actionRequestId: msg.action_request_id,\n workspaceExtId: msg.workspace_ext_id ?? undefined,\n }\n : {}),\n ...(msg.screen_request_id\n ? {\n screenRequestId: msg.screen_request_id,\n screenQuestion: msg.screen_question ?? undefined,\n workspaceExtId: msg.workspace_ext_id ?? undefined,\n }\n : {}),\n }\n}\n"],
5
+ "mappings": "AA2BA,SAAS,cAAc;AAEvB,SAAS,2BAA2B;AAgE7B,MAAM,sBAAsB;AACnC,MAAM,MAA0B,EAAE,SAAS,OAAO,SAAS,MAAM,kBAAkB,KAAK;AAGjF,MAAM,uBAAuB,CAAC,UAClC,MAAM,MAAM,UAAU,mBAAmB,KAAwC;AAG7E,SAAS,iBAAoB,UAA+C;AACjF,SAAO,oBAAoB,CAAC,UAAU,SAAS,qBAAqB,KAAK,CAAC,CAAC;AAC7E;AAGO,SAAS,qBAAqB,SAA+B;AAClE,QAAM,SAAS,CAAC,WAA6E;AAC3F,UAAM,QAAQ,qBAAqB,QAAQ,SAAS,CAAC;AACrD,YAAQ,iBAAiB,qBAAqB,EAAE,GAAG,OAAO,GAAG,OAAO,KAAK,EAAE,CAAC;AAAA,EAC9E;AACA,SAAO;AAAA;AAAA,IAEL,SAAS,CAAC,QAAoC,OAAO,OAAO,EAAE,SAAS,IAAI,EAAE;AAAA;AAAA;AAAA,IAG7E,OAAO,CAAC,EAAE,WAAW,MACnB,OAAO,CAAC,WAAW,EAAE,SAAS,cAAc,MAAM,SAAS,SAAS,KAAK,EAAE;AAAA;AAAA,IAE7E,MAAM,MAAY,OAAO,OAAO,EAAE,SAAS,KAAK,EAAE;AAAA;AAAA;AAAA,IAGlD,YAAY,CAAC,YACX,OAAO,MAAO,UAAU,EAAE,QAAQ,IAAI,EAAE,SAAS,SAAS,MAAM,kBAAkB,KAAK,CAAE;AAAA,IAC3F,YAAY,CAAC,YAA2B,OAAO,OAAO,EAAE,QAAQ,EAAE;AAAA;AAAA,IAElE,qBAAqB,CAAC,UACpB,OAAO,OAAO,EAAE,kBAAkB,MAAM,EAAE;AAAA;AAAA,IAE5C,OAAO,MAAY,QAAQ,iBAAiB,qBAAqB,MAAS;AAAA,EAC5E;AACF;AAIA,SAAS,iBACP,OAC8B;AAC9B,SACE,MAAM,QAAQ,KAAK,KACnB,MAAM,SAAS,KACf,MAAM,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,YAAY,EAAE,OAAO,SAAS,CAAC;AAE3E;AAIA,SAAS,cAAc,OAA0C;AAC/D,SAAO,MAAM,IAAI,CAAC,OAAO;AAAA,IACvB,QAAQ,EAAE;AAAA,IACV,IAAI,EAAE,MAAM;AAAA,IACZ,OAAO,EAAE,SAAS;AAAA,IAClB,MAAM,EAAE,QAAQ;AAAA,IAChB,SAAS,EAAE,WAAW;AAAA,IACtB,QAAQ,EAAE,UAAU;AAAA,EACtB,EAAE;AACJ;AAMO,SAAS,uBACd,KACA,cAC6B;AAC7B,QAAM,QAAQ,iBAAiB,IAAI,KAAK,IAAI,cAAc,IAAI,KAAK,IAAI;AACvE,QAAM,aACJ,OAAO,IAAI,gBAAgB,YAAY,aAAa,IAAI,WAAW,IAC/D,IAAI,cACJ;AACN,MAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,qBAAqB,IAAI,mBAAmB;AAC7E,WAAO,KAAK,4DAA4D,IAAI,WAAW;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AAAA;AAAA;AAAA,IAGL,WAAW,IAAI,WAAW,KAAK,KAAK;AAAA,IACpC,YAAY,IAAI,gBAAgB;AAAA,IAChC;AAAA,IACA;AAAA,IACA,GAAI,IAAI,oBACJ;AAAA,MACE,iBAAiB,IAAI;AAAA,MACrB,gBAAgB,IAAI,oBAAoB;AAAA,IAC1C,IACA,CAAC;AAAA,IACL,GAAI,IAAI,oBACJ;AAAA,MACE,iBAAiB,IAAI;AAAA,MACrB,gBAAgB,IAAI,mBAAmB;AAAA,MACvC,gBAAgB,IAAI,oBAAoB;AAAA,IAC1C,IACA,CAAC;AAAA,EACP;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkWUYSVTKE_cjs = require('../chunk-WUYSVTKE.cjs');
3
+ var chunk6RRKO4ZK_cjs = require('../chunk-6RRKO4ZK.cjs');
4
4
  var chunkIX4HOS5Z_cjs = require('../chunk-IX4HOS5Z.cjs');
5
5
  require('../chunk-N73IMVFF.cjs');
6
- require('../chunk-NDIKMOBJ.cjs');
6
+ require('../chunk-KULS4YWP.cjs');
7
7
  require('../chunk-VOFNX4P6.cjs');
8
8
  require('../chunk-KC474WVG.cjs');
9
9
  require('../chunk-HJDR5HEO.cjs');
@@ -14,147 +14,147 @@ require('../chunk-S6A6FSG7.cjs');
14
14
 
15
15
  Object.defineProperty(exports, "ArbiHost", {
16
16
  enumerable: true,
17
- get: function () { return chunkWUYSVTKE_cjs.ArbiHost; }
17
+ get: function () { return chunk6RRKO4ZK_cjs.ArbiHost; }
18
18
  });
19
19
  Object.defineProperty(exports, "DEFAULT_ASSISTANT_NAME", {
20
20
  enumerable: true,
21
- get: function () { return chunkWUYSVTKE_cjs.DEFAULT_ASSISTANT_NAME; }
21
+ get: function () { return chunk6RRKO4ZK_cjs.DEFAULT_ASSISTANT_NAME; }
22
22
  });
23
23
  Object.defineProperty(exports, "LEGACY_THREAD_DOCUMENTS_KEY", {
24
24
  enumerable: true,
25
- get: function () { return chunkWUYSVTKE_cjs.LEGACY_THREAD_DOCUMENTS_KEY; }
25
+ get: function () { return chunk6RRKO4ZK_cjs.LEGACY_THREAD_DOCUMENTS_KEY; }
26
26
  });
27
27
  Object.defineProperty(exports, "MENTION_HREF_PREFIX", {
28
28
  enumerable: true,
29
- get: function () { return chunkWUYSVTKE_cjs.MENTION_HREF_PREFIX; }
29
+ get: function () { return chunk6RRKO4ZK_cjs.MENTION_HREF_PREFIX; }
30
30
  });
31
31
  Object.defineProperty(exports, "NotificationBell", {
32
32
  enumerable: true,
33
- get: function () { return chunkWUYSVTKE_cjs.NotificationBell; }
33
+ get: function () { return chunk6RRKO4ZK_cjs.NotificationBell; }
34
34
  });
35
35
  Object.defineProperty(exports, "Toaster", {
36
36
  enumerable: true,
37
- get: function () { return chunkWUYSVTKE_cjs.Toaster; }
37
+ get: function () { return chunk6RRKO4ZK_cjs.Toaster; }
38
38
  });
39
39
  Object.defineProperty(exports, "UNBOUND", {
40
40
  enumerable: true,
41
- get: function () { return chunkWUYSVTKE_cjs.UNBOUND; }
41
+ get: function () { return chunk6RRKO4ZK_cjs.UNBOUND; }
42
42
  });
43
43
  Object.defineProperty(exports, "assistantCopy", {
44
44
  enumerable: true,
45
- get: function () { return chunkWUYSVTKE_cjs.assistantCopy; }
45
+ get: function () { return chunk6RRKO4ZK_cjs.assistantCopy; }
46
46
  });
47
47
  Object.defineProperty(exports, "bindingOfRow", {
48
48
  enumerable: true,
49
- get: function () { return chunkWUYSVTKE_cjs.bindingOfRow; }
49
+ get: function () { return chunk6RRKO4ZK_cjs.bindingOfRow; }
50
50
  });
51
51
  Object.defineProperty(exports, "clearSearchSession", {
52
52
  enumerable: true,
53
- get: function () { return chunkWUYSVTKE_cjs.clearSearchSession; }
53
+ get: function () { return chunk6RRKO4ZK_cjs.clearSearchSession; }
54
54
  });
55
55
  Object.defineProperty(exports, "createSearchSession", {
56
56
  enumerable: true,
57
- get: function () { return chunkWUYSVTKE_cjs.createSearchSession; }
57
+ get: function () { return chunk6RRKO4ZK_cjs.createSearchSession; }
58
58
  });
59
59
  Object.defineProperty(exports, "extractMentions", {
60
60
  enumerable: true,
61
- get: function () { return chunkWUYSVTKE_cjs.extractMentions; }
61
+ get: function () { return chunk6RRKO4ZK_cjs.extractMentions; }
62
62
  });
63
63
  Object.defineProperty(exports, "filterMentionCandidates", {
64
64
  enumerable: true,
65
- get: function () { return chunkWUYSVTKE_cjs.filterMentionCandidates; }
65
+ get: function () { return chunk6RRKO4ZK_cjs.filterMentionCandidates; }
66
66
  });
67
67
  Object.defineProperty(exports, "findMentionQuery", {
68
68
  enumerable: true,
69
- get: function () { return chunkWUYSVTKE_cjs.findMentionQuery; }
69
+ get: function () { return chunk6RRKO4ZK_cjs.findMentionQuery; }
70
70
  });
71
71
  Object.defineProperty(exports, "forgetLegacyThreadDocuments", {
72
72
  enumerable: true,
73
- get: function () { return chunkWUYSVTKE_cjs.forgetLegacyThreadDocuments; }
73
+ get: function () { return chunk6RRKO4ZK_cjs.forgetLegacyThreadDocuments; }
74
74
  });
75
75
  Object.defineProperty(exports, "hasMessageBody", {
76
76
  enumerable: true,
77
- get: function () { return chunkWUYSVTKE_cjs.hasMessageBody; }
77
+ get: function () { return chunk6RRKO4ZK_cjs.hasMessageBody; }
78
78
  });
79
79
  Object.defineProperty(exports, "insertMention", {
80
80
  enumerable: true,
81
- get: function () { return chunkWUYSVTKE_cjs.insertMention; }
81
+ get: function () { return chunk6RRKO4ZK_cjs.insertMention; }
82
82
  });
83
83
  Object.defineProperty(exports, "isSlideDeck", {
84
84
  enumerable: true,
85
- get: function () { return chunkWUYSVTKE_cjs.isSlideDeck; }
85
+ get: function () { return chunk6RRKO4ZK_cjs.isSlideDeck; }
86
86
  });
87
87
  Object.defineProperty(exports, "latestThreadOfDocument", {
88
88
  enumerable: true,
89
- get: function () { return chunkWUYSVTKE_cjs.latestThreadOfDocument; }
89
+ get: function () { return chunk6RRKO4ZK_cjs.latestThreadOfDocument; }
90
90
  });
91
91
  Object.defineProperty(exports, "linkMentions", {
92
92
  enumerable: true,
93
- get: function () { return chunkWUYSVTKE_cjs.linkMentions; }
93
+ get: function () { return chunk6RRKO4ZK_cjs.linkMentions; }
94
94
  });
95
95
  Object.defineProperty(exports, "mentionFromHref", {
96
96
  enumerable: true,
97
- get: function () { return chunkWUYSVTKE_cjs.mentionFromHref; }
97
+ get: function () { return chunk6RRKO4ZK_cjs.mentionFromHref; }
98
98
  });
99
99
  Object.defineProperty(exports, "openDocumentId", {
100
100
  enumerable: true,
101
- get: function () { return chunkWUYSVTKE_cjs.openDocumentId; }
101
+ get: function () { return chunk6RRKO4ZK_cjs.openDocumentId; }
102
102
  });
103
103
  Object.defineProperty(exports, "opensInWord", {
104
104
  enumerable: true,
105
- get: function () { return chunkWUYSVTKE_cjs.opensInWord; }
105
+ get: function () { return chunk6RRKO4ZK_cjs.opensInWord; }
106
106
  });
107
107
  Object.defineProperty(exports, "persistSearchSession", {
108
108
  enumerable: true,
109
- get: function () { return chunkWUYSVTKE_cjs.persistSearchSession; }
109
+ get: function () { return chunk6RRKO4ZK_cjs.persistSearchSession; }
110
110
  });
111
111
  Object.defineProperty(exports, "readLegacyThreadDocuments", {
112
112
  enumerable: true,
113
- get: function () { return chunkWUYSVTKE_cjs.readLegacyThreadDocuments; }
113
+ get: function () { return chunk6RRKO4ZK_cjs.readLegacyThreadDocuments; }
114
114
  });
115
115
  Object.defineProperty(exports, "requestSearch", {
116
116
  enumerable: true,
117
- get: function () { return chunkWUYSVTKE_cjs.requestSearch; }
117
+ get: function () { return chunk6RRKO4ZK_cjs.requestSearch; }
118
118
  });
119
119
  Object.defineProperty(exports, "savedDocumentIdFor", {
120
120
  enumerable: true,
121
- get: function () { return chunkWUYSVTKE_cjs.savedDocumentIdFor; }
121
+ get: function () { return chunk6RRKO4ZK_cjs.savedDocumentIdFor; }
122
122
  });
123
123
  Object.defineProperty(exports, "sharedSearchSession", {
124
124
  enumerable: true,
125
- get: function () { return chunkWUYSVTKE_cjs.sharedSearchSession; }
125
+ get: function () { return chunk6RRKO4ZK_cjs.sharedSearchSession; }
126
126
  });
127
127
  Object.defineProperty(exports, "takeDocumentForTurn", {
128
128
  enumerable: true,
129
- get: function () { return chunkWUYSVTKE_cjs.takeDocumentForTurn; }
129
+ get: function () { return chunk6RRKO4ZK_cjs.takeDocumentForTurn; }
130
130
  });
131
131
  Object.defineProperty(exports, "takePendingSearch", {
132
132
  enumerable: true,
133
- get: function () { return chunkWUYSVTKE_cjs.takePendingSearch; }
133
+ get: function () { return chunk6RRKO4ZK_cjs.takePendingSearch; }
134
134
  });
135
135
  Object.defineProperty(exports, "toMessageMentions", {
136
136
  enumerable: true,
137
- get: function () { return chunkWUYSVTKE_cjs.toMessageMentions; }
137
+ get: function () { return chunk6RRKO4ZK_cjs.toMessageMentions; }
138
138
  });
139
139
  Object.defineProperty(exports, "useAssistantCopy", {
140
140
  enumerable: true,
141
- get: function () { return chunkWUYSVTKE_cjs.useAssistantCopy; }
141
+ get: function () { return chunk6RRKO4ZK_cjs.useAssistantCopy; }
142
142
  });
143
143
  Object.defineProperty(exports, "useAssistantName", {
144
144
  enumerable: true,
145
- get: function () { return chunkWUYSVTKE_cjs.useAssistantName; }
145
+ get: function () { return chunk6RRKO4ZK_cjs.useAssistantName; }
146
146
  });
147
147
  Object.defineProperty(exports, "useOpenDocumentId", {
148
148
  enumerable: true,
149
- get: function () { return chunkWUYSVTKE_cjs.useOpenDocumentId; }
149
+ get: function () { return chunk6RRKO4ZK_cjs.useOpenDocumentId; }
150
150
  });
151
151
  Object.defineProperty(exports, "useRegisterOpenDocument", {
152
152
  enumerable: true,
153
- get: function () { return chunkWUYSVTKE_cjs.useRegisterOpenDocument; }
153
+ get: function () { return chunk6RRKO4ZK_cjs.useRegisterOpenDocument; }
154
154
  });
155
155
  Object.defineProperty(exports, "useTurnDocumentId", {
156
156
  enumerable: true,
157
- get: function () { return chunkWUYSVTKE_cjs.useTurnDocumentId; }
157
+ get: function () { return chunk6RRKO4ZK_cjs.useTurnDocumentId; }
158
158
  });
159
159
  Object.defineProperty(exports, "clearChatArtifacts", {
160
160
  enumerable: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbidocs/react",
3
- "version": "0.5.125",
3
+ "version": "0.5.127",
4
4
  "description": "React hooks and provider for the ARBI SDK",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -117,8 +117,8 @@
117
117
  "build-storybook": "storybook build"
118
118
  },
119
119
  "dependencies": {
120
- "@arbidocs/client": "0.5.125",
121
- "@arbidocs/sdk": "0.5.125",
120
+ "@arbidocs/client": "0.5.127",
121
+ "@arbidocs/sdk": "0.5.127",
122
122
  "@didit-protocol/sdk-web": "0.4.0",
123
123
  "@livekit/components-react": "2.9.24",
124
124
  "@radix-ui/react-avatar": "^1.2.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/documents/documents-cache.ts","../src/entity-extraction.ts","../src/queued-writes.ts","../src/tags.ts","../src/documents/documents-loader.ts","../src/documents/processing-order.ts","../src/websocket/store.ts","../src/documents/documents-data.ts"],"names":["arbiQueryKeys","update","create","isAbortError","ArbiWorkspaceUnavailableError","useRef","useCallback","useArbi","useQueryClient","arbiMutationKeys","tagOps","useMutation","useQuery","useSyncExternalStore","controller","openWorkspaceId"],"mappings":"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","file":"chunk-GKGAPU6T.cjs","sourcesContent":["/**\n * The workspace documents list in the query cache: one entry per workspace\n * (`arbiQueryKeys.documents(workspaceId)`), read once (progressively, see `documents-loader.ts`)\n * and then kept current in place. Every write goes through {@link patchDocuments}, which also\n * tells row listeners (a grid that applies row transactions instead of re-diffing the whole list)\n * exactly which rows were added, changed or removed.\n *\n * A single document's own entry (`arbiQueryKeys.document(id)`, read by a viewer) is patched next to\n * the list by {@link setCachedDocument}, so a viewer never blanks while a write settles.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { components } from '@arbidocs/client'\nimport { arbiQueryKeys } from '../hooks'\n\n/** A document as the server lists it. */\nexport type WorkspaceDocument = components['schemas']['DocResponse']\n\n/** The rows one write added, changed and removed (removed: by id). */\nexport interface DocumentRowChange {\n workspaceId: string\n add: WorkspaceDocument[]\n update: WorkspaceDocument[]\n remove: string[]\n}\n\ntype RowListener = (change: DocumentRowChange) => void\n\nconst rowListeners = new Set<RowListener>()\n\n/**\n * Follow the row-level changes of every write to a workspace documents list (a grid applying them\n * as transactions). Returns the unsubscribe.\n */\nexport function subscribeDocumentRows(listener: RowListener): () => void {\n rowListeners.add(listener)\n return () => {\n rowListeners.delete(listener)\n }\n}\n\n/** The cached documents of a workspace (`undefined` before its list has been read). */\nexport function getCachedDocuments(\n qc: QueryClient,\n workspaceId: string | null | undefined\n): WorkspaceDocument[] | undefined {\n if (!workspaceId) return undefined\n return qc.getQueryData<WorkspaceDocument[]>(arbiQueryKeys.documents(workspaceId))\n}\n\n/** Every cached workspace documents list, with its workspace. */\nfunction cachedLists(qc: QueryClient): Array<[string, WorkspaceDocument[]]> {\n return qc\n .getQueriesData<WorkspaceDocument[]>({ queryKey: arbiQueryKeys.allDocuments() })\n .flatMap(([key, data]) =>\n typeof key[2] === 'string' && Array.isArray(data) ? [[key[2], data]] : []\n )\n}\n\n/** Diff two versions of a list by id. */\nfunction diffRows(\n workspaceId: string,\n before: WorkspaceDocument[],\n after: WorkspaceDocument[]\n): DocumentRowChange {\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n const add: WorkspaceDocument[] = []\n const update: WorkspaceDocument[] = []\n const seen = new Set<string>()\n for (const doc of after) {\n seen.add(doc.external_id)\n const previous = beforeById.get(doc.external_id)\n if (!previous) add.push(doc)\n else if (previous !== doc) update.push(doc)\n }\n const remove = [...beforeById.keys()].filter((id) => !seen.has(id))\n return { workspaceId, add, update, remove }\n}\n\n/**\n * Apply `reducer` to a workspace's documents list, or (no `workspaceId`) to every cached one: the\n * one place a list is written after it was read. Returning the same array is a no-op. Row\n * listeners get the diff; a document that moved to a new version makes the open version lists\n * re-read. A workspace whose list has not been read is left alone (its first read brings it).\n */\nexport function patchDocuments(\n qc: QueryClient,\n reducer: (documents: WorkspaceDocument[]) => WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n const lists: Array<[string, WorkspaceDocument[]]> = workspaceId\n ? (() => {\n const current = getCachedDocuments(qc, workspaceId)\n return current ? [[workspaceId, current] as [string, WorkspaceDocument[]]] : []\n })()\n : cachedLists(qc)\n for (const [id, before] of lists) {\n const after = reducer(before)\n if (after === before) continue\n qc.setQueryData(arbiQueryKeys.documents(id), after)\n const change = diffRows(id, before, after)\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n if (\n change.update.some(\n (doc) => doc.current_version !== beforeById.get(doc.external_id)?.current_version\n )\n )\n void qc.invalidateQueries({ queryKey: arbiQueryKeys.allDocumentVersions() })\n if (change.add.length || change.update.length || change.remove.length)\n for (const listener of rowListeners) listener(change)\n }\n}\n\n/** Put `doc` in its list in place, or at the end when the list does not hold it yet. */\nexport function upsertDocuments(\n qc: QueryClient,\n documents: WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n if (!documents.length) return\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const byWorkspace = new Map<string, WorkspaceDocument[]>()\n for (const doc of documents) {\n const ws = workspaceId ?? doc.workspace_ext_id\n byWorkspace.set(ws, [...(byWorkspace.get(ws) ?? []), doc])\n }\n for (const [ws, incoming] of byWorkspace) {\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n return [\n ...old.map((doc) => byId.get(doc.external_id) ?? doc),\n ...incoming.filter((doc) => !known.has(doc.external_id)),\n ]\n },\n ws\n )\n }\n}\n\n/** Write a document's own entry (what `useDocument` reads), keeping a viewer current. */\nexport function setCachedDocument(qc: QueryClient, doc: WorkspaceDocument): void {\n qc.setQueryData(arbiQueryKeys.document(doc.external_id), doc)\n}\n\n/** Apply `reducer` to a document's own entry, when one is cached. */\nexport function patchCachedDocument(\n qc: QueryClient,\n docId: string,\n reducer: (doc: WorkspaceDocument) => WorkspaceDocument\n): void {\n const current = qc.getQueryData<WorkspaceDocument | null>(arbiQueryKeys.document(docId))\n if (current) qc.setQueryData(arbiQueryKeys.document(docId), reducer(current))\n}\n\n/** A deleted tag leaves every cached document that carried it: the lists' rows and their entries. */\nexport function dropTagFromCachedDocuments(qc: QueryClient, tagId: string): void {\n const strip = (doc: WorkspaceDocument): WorkspaceDocument => {\n const doctags = doc.doctags?.filter((dt) => dt.tag_ext_id !== tagId)\n return doctags && doctags.length !== doc.doctags?.length ? { ...doc, doctags } : doc\n }\n const carriers: string[] = []\n patchDocuments(qc, (docs) => {\n const next = docs.map(strip)\n next.forEach((doc, i) => doc !== docs[i] && carriers.push(doc.external_id))\n return carriers.length ? next : docs\n })\n for (const id of carriers) patchCachedDocument(qc, id, strip)\n}\n\n/** Forget everything cached about deleted documents, so nothing re-reads them into a 404. */\nexport function forgetDocuments(qc: QueryClient, docIds: string[]): void {\n for (const id of docIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.document(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.documentVersions(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.parsedDocument(id) })\n }\n}\n","/**\n * The documents whose people and organisations are being found (`useExtractEntities`), from the\n * request until the live connection says the batch is done (`batch_complete`, `entity_extract`):\n * the package's WebSocket (`ArbiWebSocketProvider`) ends it, and a host on its own connection calls\n * `finishEntityExtraction` from its handler.\n */\n\nimport { create } from 'zustand'\n\nconst useEntityExtractionStore = create<{ docIds: readonly string[] }>(() => ({ docIds: [] }))\n\nfunction update(docIds: readonly string[], running: boolean): void {\n if (!docIds.length) return\n useEntityExtractionStore.setState((state) => {\n const ids = new Set(state.docIds)\n docIds.forEach((id) => (running ? ids.add(id) : ids.delete(id)))\n return { docIds: [...ids] }\n })\n}\n\n/** The documents an extraction was started on are running. */\nexport function startEntityExtraction(docIds: readonly string[]): void {\n update(docIds, true)\n}\n\n/** The extraction of these documents is done. */\nexport function finishEntityExtraction(docIds: readonly string[]): void {\n update(docIds, false)\n}\n\n/** The documents being extracted now. */\nexport function useEntityExtractionDocIds(): readonly string[] {\n return useEntityExtractionStore((state) => state.docIds)\n}\n","/**\n * The workspace of a write that may be queued (offline, then replayed on reconnect or after a\n * reload). The workspace is captured when the write is made and kept with it, and the write is\n * sent in that workspace: it is opened for this session first (its key deposited, without\n * switching to it), and the request names it or acts on resources the server keys by their own\n * workspace. So a replay never lands in whatever workspace happens to be open by then.\n *\n * When the workspace cannot be opened (signed out, access removed), nothing is sent: the write\n * fails with `ArbiWorkspaceUnavailableError`, is retried a few times (a reload replays before the\n * sign-in has finished), and then stays in the pending changes as not sent, with its local edit\n * kept, rather than going anywhere else.\n */\n\nimport { useCallback, useRef } from 'react'\nimport { isAbortError, type ArbiClient } from '@arbidocs/client'\nimport { ArbiWorkspaceUnavailableError } from '@arbidocs/sdk/browser'\n\n/** A queued write's own workspace (`wrk-…`), captured when it was made. */\nexport interface QueuedWriteWorkspace {\n /** The workspace the write belongs to. Filled in when it is made; absent on older queued writes. */\n workspaceId?: string\n}\n\n/** What a write that could not be sent in its workspace says. */\nexport const QUEUED_WRITE_BLOCKED_MESSAGE =\n \"This change belongs to a workspace that can't be opened right now, so it was not sent. It is kept here until it can be.\"\n\n/** Opens a workspace for this server session without switching to it (nothing for the current one). */\nexport type WorkspacePrimer = (workspaceId: string) => Promise<void> | void\n\n/** {@link WorkspacePrimer} on a bare client (a replay after a reload): its key, via `/prime-key`. */\nexport function primeOnClient(client: ArbiClient): WorkspacePrimer {\n return (workspaceId) =>\n workspaceId === client.session.getState().selectedWorkspaceId\n ? undefined\n : client.workspaceKeys.prime(workspaceId)\n}\n\n/** {@link WorkspacePrimer} on an `Arbi` (`workspaces.open`, which never switches). */\nexport function primeOnArbi(arbi: {\n hasWorkspace: boolean\n getWorkspaceId(): string\n workspaces: { open(workspaceId: string): Promise<void> }\n}): WorkspacePrimer {\n return (workspaceId) =>\n arbi.hasWorkspace && workspaceId === arbi.getWorkspaceId()\n ? undefined\n : arbi.workspaces.open(workspaceId)\n}\n\n/**\n * Run `write` in `workspaceId`: that workspace is opened for this server session first (`prime`).\n * When it can't be, nothing is sent. No workspace (a write queued before workspaces were\n * recorded): as before.\n */\nexport async function inWorkspace<T>(\n prime: WorkspacePrimer,\n workspaceId: string | null | undefined,\n write: () => Promise<T>\n): Promise<T> {\n if (workspaceId) {\n try {\n await prime(workspaceId)\n } catch (error) {\n if (isAbortError(error)) throw error\n throw new ArbiWorkspaceUnavailableError(workspaceId, error, QUEUED_WRITE_BLOCKED_MESSAGE)\n }\n }\n return write()\n}\n\n/** Whether a write failed only because its workspace could not be opened (nothing was sent). */\nexport function isWorkspaceUnavailable(error: unknown): boolean {\n return error instanceof ArbiWorkspaceUnavailableError\n}\n\n/** How many times a write whose workspace cannot be opened is tried again, and how long apart. */\nexport const QUEUED_WRITE_RETRY = {\n retry: (failureCount: number, error: unknown) =>\n isWorkspaceUnavailable(error) && failureCount < 8,\n retryDelay: (attempt: number) => Math.min(1000 * 2 ** attempt, 30_000),\n} as const\n\n/** Whether a queued write is held back because its workspace cannot be opened. */\nexport function isBlockedOnWorkspace(mutation: {\n state: { error?: unknown; failureReason?: unknown }\n}): boolean {\n return isWorkspaceUnavailable(mutation.state.error ?? mutation.state.failureReason)\n}\n\n/**\n * Fill in the workspace of each write a mutation makes, when its caller gave none: `mutate` and\n * `mutateAsync` pass `capture(variables)` on. Read when the write is made, so a write queued\n * offline keeps the workspace it was made in. The wrapped functions are as stable as the mutation's.\n */\nexport function useCapturingWorkspace<\n V,\n T extends { mutate: (variables: V, ...rest: never[]) => unknown; mutateAsync: unknown },\n>(mutation: T, capture: (variables: V) => V): T {\n const captureRef = useRef(capture)\n captureRef.current = capture\n const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation\n const mutate = useCallback(\n (variables: V, ...rest: never[]) =>\n (rawMutate as (v: V, ...r: never[]) => unknown)(captureRef.current(variables), ...rest),\n [rawMutate]\n ) as T['mutate']\n const mutateAsync = useCallback(\n (variables: V, ...rest: never[]) =>\n (rawMutateAsync as (v: V, ...r: never[]) => Promise<unknown>)(\n captureRef.current(variables),\n ...rest\n ),\n [rawMutateAsync]\n ) as T['mutateAsync']\n return { ...mutation, mutate, mutateAsync }\n}\n","/**\n * Tags: the open workspace's tag list (`useTags()`), the writes (create, update, delete, values,\n * entity extraction), and tag kinds — a kind's fields in the workspace are the columns of a table\n * of its tags (`useTagKindSchema('issue')`), whose rows are the tag list filtered by kind with\n * links (`useTags(workspaceId, { kind, include })`).\n *\n * Everything is cached under the workspace's tags (`arbiQueryKeys.tags`). The whole list is kept\n * current in place: every write here patches it ({@link patchWorkspaceTags}, which a host also\n * uses for its own writes that move a tag's counts, e.g. applying it to documents) and refreshes\n * the filtered lists (the tables). Anything that invalidates the workspace's tags (a document batch\n * finishing, {@link useInvalidateTagData} after a doctag or fact change) refreshes them all.\n *\n * Creating a tag can be queued while offline and replayed after a reload: see `offline.ts`.\n *\n * Requires an `ArbiHost` (with an `arbi`) and a React Query client above it.\n */\n\nimport { useCallback } from 'react'\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { ArbiClient } from '@arbidocs/client'\nimport {\n tags as tagOps,\n type TagChange,\n type TagFieldDefinition,\n type TagKind,\n type TagKindSchema,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport { dropTagFromCachedDocuments } from './documents/documents-cache'\nimport { startEntityExtraction } from './entity-extraction'\nimport { arbiMutationKeys, arbiQueryKeys } from './hooks'\nimport {\n QUEUED_WRITE_RETRY,\n inWorkspace,\n primeOnArbi,\n primeOnClient,\n useCapturingWorkspace,\n} from './queued-writes'\n\n/** The workspace open on `arbi`, or `null` (`getWorkspaceId()` throws when none is open). */\n/** The workspace whose cached tag list holds `tagId`, if any. */\nfunction workspaceOfTag(qc: QueryClient, tagId: string): string | null {\n for (const [key, tags] of qc.getQueriesData<TagResponse[]>({\n queryKey: arbiQueryKeys.allTags(),\n })) {\n if (Array.isArray(tags) && tags.some((t) => t.external_id === tagId))\n return (key[2] as string | undefined) ?? null\n }\n return null\n}\n\nfunction openWorkspaceId(arbi: ReturnType<typeof useArbi>): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * Apply `reducer` to a workspace's cached tag list (nothing cached: nothing to do). The list is\n * read once, then kept current by these patches; a host's own write that changes a tag (applying\n * it to documents moves its `doctag_count`) patches it here too.\n */\nexport function patchWorkspaceTags(\n qc: QueryClient,\n workspaceId: string,\n reducer: (tags: TagResponse[]) => TagResponse[]\n): void {\n const key = arbiQueryKeys.tags(workspaceId)\n const current = qc.getQueryData<TagResponse[]>(key)\n if (!current) return\n const next = reducer(current)\n if (next !== current) qc.setQueryData(key, next)\n}\n\n/** Refetch a workspace's tables of tags (its filtered lists), not the whole list. */\nexport function invalidateTagTables(qc: QueryClient, workspaceId: string): Promise<void> {\n return qc.invalidateQueries({ queryKey: arbiQueryKeys.tagLists(workspaceId) })\n}\n\n/** Refresh what a tag, doctag or fact change affects: the workspace's tags, tables and facts. */\nexport function invalidateTagData(qc: QueryClient, workspaceId: string): Promise<unknown> {\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.tags(workspaceId) }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n}\n\n/** {@link invalidateTagData} for the open workspace: call it after a doctag or fact write. */\nexport function useInvalidateTagData(): () => Promise<unknown> {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useCallback(() => {\n const workspaceId = openWorkspaceId(arbi)\n return workspaceId ? invalidateTagData(qc, workspaceId) : Promise.resolve()\n }, [arbi, qc])\n}\n\n/**\n * What a new tag is: its name, and optionally kind, format, parent, values, sharing, and the workspace it goes in\n * (absent: the open one).\n */\nexport type CreateTagInput = Parameters<typeof tagOps.createTag>[1]\n\n/** A created tag joins its workspace's list; the tables re-read. */\nfunction settleCreatedTag(qc: QueryClient, created: TagResponse): Promise<void> {\n const workspaceId = created.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.some((t) => t.external_id === created.external_id) ? old : [...old, created]\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/** A changed tag replaces its entry in the list; the tables re-read. */\nfunction settleChangedTag(qc: QueryClient, tag: TagResponse): Promise<void> {\n const workspaceId = tag.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.map((t) => (t.external_id === tag.external_id ? { ...t, ...tag } : t))\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/**\n * The tag writes a host may queue while offline and replay after a reload (`offline.ts`): each\n * key's request on a bare client, and what its success does to the cache.\n */\nexport const replayableTagMutations = [\n {\n mutationKey: arbiMutationKeys.createTag(),\n // In the workspace it was made in (named on the request), opened for this session first.\n run: (client: ArbiClient, input: CreateTagInput) =>\n inWorkspace(primeOnClient(client), input.workspaceId, () => tagOps.createTag(client, input)),\n settle: (qc: QueryClient, created: TagResponse) => settleCreatedTag(qc, created),\n },\n] as const\n\n/**\n * Create a tag in the open workspace, or `workspaceId` (`{ name, kind: 'issue' }`, `{ name, parentId }`, …): it is\n * added to the tag list and the tables re-read. Resolves with the new tag. Offline it is held and\n * sent on reconnect (a host that registers `registerArbiMutationDefaults` keeps it across reloads).\n */\nexport function useCreateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n // The workspace is captured when the tag is made, so a create queued offline keeps it.\n const capture = (input: CreateTagInput): CreateTagInput =>\n input.workspaceId || !arbi.hasWorkspace\n ? input\n : { ...input, workspaceId: arbi.getWorkspaceId() }\n return useCapturingWorkspace(\n useMutation({\n mutationKey: arbiMutationKeys.createTag(),\n mutationFn: (input: CreateTagInput): Promise<TagResponse> =>\n inWorkspace(primeOnArbi(arbi), input.workspaceId, () => arbi.tags.create(input)),\n onSuccess: (created) => settleCreatedTag(qc, created),\n ...QUEUED_WRITE_RETRY,\n }),\n capture\n )\n}\n\n/**\n * Whether a tag of this name (any case) is being created right now: a second create of the same\n * name (a double Enter) is skipped instead of making a duplicate.\n */\nexport function useIsCreatingTag(): (name: string) => boolean {\n const qc = useQueryClient()\n return useCallback(\n (name: string) => {\n const wanted = name.trim().toLowerCase()\n return (\n qc.getMutationCache().findAll({\n mutationKey: arbiMutationKeys.createTag(),\n predicate: (m) =>\n m.state.status === 'pending' &&\n (m.state.variables as CreateTagInput | undefined)?.name.trim().toLowerCase() === wanted,\n }).length > 0\n )\n },\n [qc]\n )\n}\n\n/** Change a tag (name, format, instruction, parent, sharing, values): patched in the list. */\nexport function useUpdateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({ tagId, change }: { tagId: string; change: TagChange }): Promise<TagResponse> =>\n arbi.tags.update(tagId, change),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/** Merge-patch a tag's values for its kind's fields (`null` clears one); its tables refresh. */\nexport function useSetTagValues() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({\n tagId,\n values,\n }: {\n tagId: string\n values: Record<string, unknown>\n }): Promise<TagResponse> => arbi.tags.setValues(tagId, values),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/**\n * Delete a tag: it leaves the list (its sub-tags move to the top level on the server, so the list\n * re-reads them), and the tables and facts re-read. A host that shows the tag on its own items\n * (documents' tags) follows `arbiMutationKeys.deleteTag()` to drop it there.\n */\nexport function useDeleteTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.deleteTag(),\n mutationFn: (tagId: string) => arbi.tags.delete(tagId),\n // The tag's own workspace (the cached list holding it), else the one open when it is sent: a\n // switch while the delete runs must not patch the next workspace's list.\n onMutate: (tagId) => ({ workspaceId: workspaceOfTag(qc, tagId) ?? openWorkspaceId(arbi) }),\n onSuccess: (_data, tagId, context) => {\n // Its pills come off the documents grid in place (and off any open document).\n dropTagFromCachedDocuments(qc, tagId)\n const workspaceId = context?.workspaceId\n if (!workspaceId) return\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old\n .filter((t) => t.external_id !== tagId)\n .map((t) => (t.parent_ext_id === tagId ? { ...t, parent_ext_id: null } : t))\n )\n return Promise.all([\n invalidateTagTables(qc, workspaceId),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n },\n })\n}\n\n/**\n * Find the people and organisations documents name and link each to its entity tag. Accepted at\n * once with the documents' ids, which show as running (`useEntityExtractionDocIds`) until a\n * `batch_complete` (`entity_extract`) WebSocket message says they are done.\n */\nexport function useExtractEntities() {\n const arbi = useArbi()\n return useMutation({\n mutationKey: arbiMutationKeys.extractEntities(),\n mutationFn: (docIds: string[]) => arbi.tags.extractEntities(docIds),\n onSuccess: (data) => startEntityExtraction(data.doc_ext_ids),\n })\n}\n\n/**\n * A kind's fields in the open workspace (`'issue'`: its issue fields): the columns of a table of\n * that kind's tags. The built-in ones (`is_default`) until the workspace sets its own.\n */\nexport function useTagKindSchema(\n kind: TagKind | null | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const workspaceId = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.tagKind(workspaceId, kind ?? ''),\n queryFn: (): Promise<TagKindSchema> =>\n arbi.readInWorkspace(workspaceId, () => arbi.tagKinds.get(kind as TagKind)),\n enabled: (options?.enabled ?? true) && !!kind && !!workspaceId,\n })\n}\n\n/**\n * Set a kind's fields in full (a field with its `id` keeps its values; one without is new; one\n * left out is removed). The kind's schema and the workspace's tags refresh.\n */\nexport function useUpdateTagKindSchema() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTagKindSchema(),\n mutationFn: ({\n kind,\n fields,\n }: {\n kind: TagKind\n fields: TagFieldDefinition[]\n }): Promise<TagKindSchema> => arbi.tagKinds.update(kind, fields),\n // The workspace open when it is sent (the server writes the open workspace's schema until\n // the request can name it): a switch meanwhile must not rewrite the next workspace's columns.\n onMutate: () => ({ workspaceId: openWorkspaceId(arbi) }),\n onSuccess: (schema, _input, context) => {\n const workspaceId = context?.workspaceId\n if (!workspaceId) return\n qc.setQueryData(arbiQueryKeys.tagKind(workspaceId, schema.kind), schema)\n return invalidateTagData(qc, workspaceId)\n },\n })\n}\n","/**\n * Reading a workspace's documents progressively: the first page is the query's result, so the\n * list shows within a few hundred milliseconds even for 100k documents, and the remaining pages\n * are appended to the same cache entry in the background as they arrive. One background read per\n * workspace; opening another workspace stops the previous one. Whether a background read is\n * running is observable ({@link useDocumentsLoading}), for a \"still loading\" indicator.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { patchDocuments, type WorkspaceDocument } from './documents-cache'\n\n/** First page: small, so rows are on screen in a few hundred ms even in a large workspace. */\nexport const DOCUMENTS_FIRST_PAGE_SIZE = 500\n\n/** Later pages: larger, fewer round trips (the server caps a page at 10 000). */\nexport const DOCUMENTS_PAGE_SIZE = 2000\n\n/**\n * The time to the first page, as a `performance` measure of this name (a host reporting\n * performance can observe it).\n */\nexport const DOCUMENTS_FIRST_PAGE_MEASURE = 'arbi:document-list:page1'\nconst FIRST_PAGE_MEASURE = DOCUMENTS_FIRST_PAGE_MEASURE\nconst FIRST_PAGE_START = 'arbi:document-list:start'\n\nfunction mark(name: string): void {\n try {\n performance.mark(name)\n } catch {\n // No performance timeline here (an old runtime, a test): nothing to record.\n }\n}\n\nfunction measure(name: string, start: string): void {\n try {\n performance.measure(name, start)\n } catch {\n // The start mark is missing: nothing to record.\n }\n}\n\nconst backgroundReads = new Map<string, AbortController>()\nconst loadingListeners = new Set<() => void>()\n\nfunction emitLoading(): void {\n for (const listener of loadingListeners) listener()\n}\n\nfunction subscribeLoading(listener: () => void): () => void {\n loadingListeners.add(listener)\n return () => {\n loadingListeners.delete(listener)\n }\n}\n\n/** Whether a workspace's remaining document pages are being read in the background. */\nexport function isDocumentsLoading(): boolean {\n return backgroundReads.size > 0\n}\n\n/** True while the remaining pages of a documents list are still arriving. */\nexport function useDocumentsLoading(): boolean {\n return useSyncExternalStore(subscribeLoading, isDocumentsLoading, () => false)\n}\n\n/** Stop a workspace's background read (closing the workspace). */\nexport function stopDocumentsLoading(workspaceId: string): void {\n const controller = backgroundReads.get(workspaceId)\n if (!controller) return\n controller.abort()\n backgroundReads.delete(workspaceId)\n emitLoading()\n}\n\n/**\n * Read a workspace's documents: resolves with the first page and appends the rest to\n * `arbiQueryKeys.documents(workspaceId)` in the background. The query function of `useDocuments`.\n */\nexport async function loadDocuments(\n qc: QueryClient,\n arbi: Arbi,\n workspaceId: string,\n signal?: AbortSignal\n): Promise<WorkspaceDocument[]> {\n let stopped = false\n for (const [id, controller] of backgroundReads) {\n if (id === workspaceId) continue\n controller.abort()\n backgroundReads.delete(id)\n stopped = true\n }\n if (stopped) emitLoading()\n\n const controller = new AbortController()\n signal?.addEventListener('abort', () => controller.abort(), { once: true })\n // Named, not the session's open workspace: the pages are this workspace's whatever the server\n // session is in, so a list read across a workspace switch can never be another's.\n const pages = arbi.documents.listPaginated({\n workspaceId,\n pageSize: DOCUMENTS_PAGE_SIZE,\n firstPageSize: DOCUMENTS_FIRST_PAGE_SIZE,\n signal: controller.signal,\n })\n mark(FIRST_PAGE_START)\n const first = await pages.next()\n const firstPage = first.done ? [] : first.value\n measure(FIRST_PAGE_MEASURE, FIRST_PAGE_START)\n if (first.done || firstPage.length < DOCUMENTS_FIRST_PAGE_SIZE) return firstPage\n if (backgroundReads.has(workspaceId)) {\n controller.abort()\n return firstPage\n }\n\n backgroundReads.set(workspaceId, controller)\n emitLoading()\n void appendRemainingPages(qc, workspaceId, pages, controller.signal).finally(() => {\n if (backgroundReads.get(workspaceId) !== controller) return\n backgroundReads.delete(workspaceId)\n emitLoading()\n })\n return firstPage\n}\n\nasync function appendRemainingPages(\n qc: QueryClient,\n workspaceId: string,\n pages: AsyncGenerator<WorkspaceDocument[]>,\n signal: AbortSignal\n): Promise<void> {\n // Let the query store the first page before the second is appended to it.\n await Promise.resolve()\n try {\n for await (const page of pages) {\n if (signal.aborted) return\n // A write may already have added some of these (an upload finishing meanwhile).\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n const fresh = page.filter((doc) => !known.has(doc.external_id))\n return fresh.length ? [...old, ...fresh] : old\n },\n workspaceId\n )\n }\n } catch (error) {\n if (!signal.aborted) console.error(`Reading the documents of ${workspaceId} failed:`, error)\n }\n}\n\n/** Test-only: stop every background read. @internal */\nexport function resetDocumentsLoadingForTests(): void {\n for (const controller of backgroundReads.values()) controller.abort()\n backgroundReads.clear()\n emitLoading()\n}\n","/**\n * Which is newer: a document's live processing status or its row as last read?\n *\n * Every `task_update` carries `seq`, taken by the server from one sequence for all documents and\n * all of its instances, so a higher seq is a later event however the events arrive. A document row\n * carries `status_seq`: the seq of the last time its processing ended (a finished status written or\n * broadcast). The two compare:\n * - an event at or below the seq of the one already held is stale (overtaken), and is dropped;\n * - a row whose `status_seq` is above the live status's seq finished after it: the live status is\n * over (its final event was lost), and the row wins;\n * - a live status above the row's `status_seq` is newer than the row: the document is being\n * processed again (AI fields being filled) although the row still says it finished.\n *\n * Without the seqs (an optimistic \"queued\" set here, a server before them) the older rule stands:\n * a live in-flight status wins, then a finished row, then whatever was heard live.\n */\n\n/** Statuses after which a document's processing is over (`low-content`: indexed, little text). */\nexport const FINISHED_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'completed',\n 'low-content',\n 'failed',\n 'skipped',\n 'empty',\n])\n\n/** A live processing status and its order (`task_update.seq`). */\nexport interface SequencedTask {\n status: string\n seq?: number | null\n}\n\n/** A document row's status and the order of its last finished status (`status_seq`). */\nexport interface SequencedRow {\n status?: string | null\n status_seq?: number | null\n}\n\n/** Statuses of a document still being processed. */\nexport const IN_FLIGHT_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'uploading',\n 'queued',\n 'parsing',\n 'encrypting',\n 'indexing',\n 'analysing',\n])\n\nfunction ordered(value: number | null | undefined): value is number {\n return typeof value === 'number'\n}\n\n/** Whether `next` is older than (or the same event as) the live status already held. */\nexport function isStaleTaskUpdate(held: SequencedTask | undefined, next: SequencedTask): boolean {\n return !!held && ordered(held.seq) && ordered(next.seq) && next.seq <= held.seq\n}\n\n/**\n * Whether the row is newer than the live status: `true` / `false` when both are ordered, `undefined`\n * when they cannot be compared.\n */\nexport function isRowNewer(row: SequencedRow, task: SequencedTask): boolean | undefined {\n if (!ordered(row.status_seq) || !ordered(task.seq)) return undefined\n return row.status_seq > task.seq\n}\n\n/** The status a document shows now: its row's, or the live one when that is newer. */\nexport function resolveDocumentStatus(row: SequencedRow, task: SequencedTask | undefined): string {\n const rowStatus = (row.status ?? '').toLowerCase()\n const live = task?.status\n if (!task || !live) return rowStatus\n const rowNewer = isRowNewer(row, task)\n if (rowNewer !== undefined) return rowNewer ? rowStatus || live : live\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(live)) return live\n if (FINISHED_DOCUMENT_STATUSES.has(rowStatus)) return rowStatus\n return live\n}\n\n/**\n * The live statuses a read of `rows` ends: each in-flight one whose row has since finished. Ordered,\n * the row must be newer (so a reprocess the row predates keeps its progress); unordered, a finished\n * row is enough (the older rule). Returns each such task with the row's status and order. Cheap when\n * nothing is in flight (it runs on every read of a list).\n */\nexport function settledByRows<T extends SequencedTask & { doc_ext_id: string }>(\n tasks: Readonly<Record<string, T>>,\n rows: ReadonlyArray<SequencedRow & { external_id: string }>\n): T[] {\n const inFlight = new Map<string, T>()\n for (const task of Object.values(tasks))\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(task.status)) inFlight.set(task.doc_ext_id, task)\n if (!inFlight.size) return []\n const settled: T[] = []\n for (const row of rows) {\n const task = inFlight.get(row.external_id)\n if (!task) continue\n const rowStatus = (row.status ?? '').toLowerCase()\n if (!FINISHED_DOCUMENT_STATUSES.has(rowStatus) || isRowNewer(row, task) === false) continue\n settled.push({ ...task, status: rowStatus, seq: row.status_seq ?? task.seq })\n }\n return settled\n}\n","/**\n * Canonical WebSocket state, shared across apps.\n *\n * One store for every site's live connection: its status, people's presence and each document's\n * live processing. `ArbiWebSocketProvider` feeds it; components read it with the selector hooks in\n * `./hooks` and the documents hooks (`useProcessingTasks`, `useWorkspaceProcessing`).\n */\n\nimport { create } from 'zustand'\nimport type { WsTaskUpdateMessage, WsPresenceUpdateMessage } from '@arbidocs/client'\nimport {\n FINISHED_DOCUMENT_STATUSES,\n isStaleTaskUpdate,\n settledByRows,\n type SequencedRow,\n} from '../documents/processing-order'\n\n/** `error`: the host's socket failed. */\nexport type ArbiWsStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'\n\n/**\n * A document's live processing: its last `task_update` (or a status set here, such as \"queued\"\n * while a write sends it back into processing), with when it was first seen (`startTime`) and\n * when it finished (`endTime`), both on this device's clock.\n */\nexport type LiveTask = Omit<WsTaskUpdateMessage, 'type' | 'seq'> & {\n type?: 'task_update'\n seq?: number | null\n startTime?: number\n endTime?: number\n}\n\n/** How long a document's tasks stay dismissed (late updates of a deleted upload are dropped). */\nexport const DISMISSED_TASK_TTL_MS = 10 * 60 * 1000\n\nexport interface ArbiWsState {\n /** Live connection status of the shared socket. */\n status: ArbiWsStatus\n /** Latest processing status per document id (the `task_update` stream). */\n tasks: Record<string, LiveTask>\n /** Documents whose processing rows were dismissed (deleted, cleared), with when. */\n dismissed: Record<string, number>\n /** The most recent `task_update` — a convenient single-value change trigger. */\n lastTaskUpdate: WsTaskUpdateMessage | null\n /** Online status keyed by user id (the `presence_update` stream). */\n presence: Record<string, string>\n /**\n * The server closed this socket for a newer session of the same user (another device, close\n * code 1008). The socket stays closed: reconnecting would only be evicted again.\n */\n evicted: boolean\n setStatus: (status: ArbiWsStatus) => void\n setEvicted: (evicted: boolean) => void\n /**\n * Take a `task_update`, unless it is older than the one held for its document (`seq`) or the\n * document was dismissed a moment ago. Resolves whether it was taken.\n */\n applyTaskUpdate: (msg: WsTaskUpdateMessage) => boolean\n /** Set a document's live processing directly (an optimistic status, or an undo). */\n putTask: (task: LiveTask) => void\n /** Drop a document's processing row, and ignore its late updates for a while. */\n clearTask: (docId: string) => void\n /** Drop every finished processing row (the in-flight ones stay). */\n clearFinishedTasks: () => void\n /** End the in-flight statuses that documents read since say finished after them. */\n settleTasks: (rows: ReadonlyArray<SequencedRow & { external_id: string }>) => void\n applyPresence: (msg: WsPresenceUpdateMessage) => void\n reset: () => void\n}\n\nconst finished = (status: string) => FINISHED_DOCUMENT_STATUSES.has(status)\n\nexport const useArbiWsStore = create<ArbiWsState>((set, get) => ({\n status: 'disconnected',\n tasks: {},\n dismissed: {},\n lastTaskUpdate: null,\n presence: {},\n evicted: false,\n setStatus: (status) => set({ status }),\n setEvicted: (evicted) => set({ evicted }),\n applyTaskUpdate: (msg) => {\n const { tasks, dismissed } = get()\n const dismissedAt = dismissed[msg.doc_ext_id]\n if (dismissedAt !== undefined && Date.now() - dismissedAt < DISMISSED_TASK_TTL_MS) return false\n const held = tasks[msg.doc_ext_id]\n if (isStaleTaskUpdate(held, msg)) return false\n const now = Date.now()\n const task: LiveTask = {\n ...msg,\n startTime: held?.startTime ?? now,\n endTime: finished(msg.status) ? (held?.endTime ?? now) : undefined,\n }\n set({ tasks: { ...tasks, [msg.doc_ext_id]: task }, lastTaskUpdate: msg })\n return true\n },\n putTask: (task) => set((s) => ({ tasks: { ...s.tasks, [task.doc_ext_id]: task } })),\n clearTask: (docId) =>\n set((s) => {\n const tasks = { ...s.tasks }\n delete tasks[docId]\n return { tasks, dismissed: { ...s.dismissed, [docId]: Date.now() } }\n }),\n clearFinishedTasks: () =>\n set((s) => ({\n tasks: Object.fromEntries(Object.entries(s.tasks).filter(([, t]) => !finished(t.status))),\n })),\n settleTasks: (rows) =>\n set((s) => {\n const settled = settledByRows(s.tasks, rows)\n if (!settled.length) return s\n const tasks = { ...s.tasks }\n const now = Date.now()\n for (const task of settled)\n tasks[task.doc_ext_id] = { ...(task as LiveTask), endTime: task.endTime ?? now }\n return { tasks }\n }),\n applyPresence: (msg) => set((s) => ({ presence: { ...s.presence, [msg.user_id]: msg.status } })),\n reset: () =>\n set({ status: 'disconnected', tasks: {}, dismissed: {}, lastTaskUpdate: null, presence: {} }),\n}))\n","/**\n * Reading documents: a workspace's list (`useDocuments`, progressive, read once and then patched in\n * place), one document (`useDocument`, for a viewer), a set of documents by id, near-duplicate pairs\n * (`useSimilarDocuments`), and {@link refreshDocuments}, which re-reads just the documents an event\n * named and patches them into every cache that shows them.\n */\n\nimport { useCallback } from 'react'\nimport { useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { invalidateTagTables, patchWorkspaceTags } from '../tags'\nimport {\n getCachedDocuments,\n setCachedDocument,\n upsertDocuments,\n type WorkspaceDocument,\n} from './documents-cache'\nimport { loadDocuments } from './documents-loader'\nimport { FINISHED_DOCUMENT_STATUSES, isRowNewer } from './processing-order'\nimport { useArbiWsStore } from '../websocket/store'\n\nexport { FINISHED_DOCUMENT_STATUSES }\n\n/** The workspace open on `arbi`, or `null`. */\nfunction openWorkspaceId(arbi: Arbi): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * A workspace's documents (default: the open one). Read progressively: the first page is the\n * result, the remaining pages arrive in the background (`useDocumentsLoading`). After that the list\n * is never re-read on its own (mounting, focus, reconnecting): writes, processing events and\n * {@link refreshDocuments} patch it in place, as re-reading 100k documents is slow and tells\n * nothing new. Invalidating it re-reads it.\n */\nexport function useDocuments(workspaceId?: string | null, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const qc = useQueryClient()\n const workspace = workspaceId ?? openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspace),\n queryFn: ({ signal }) => {\n if (openWorkspaceId(arbi) !== workspace)\n return Promise.reject(new Error('The selected workspace changed.'))\n return loadDocuments(qc, arbi, workspace, signal)\n },\n enabled: (options?.enabled ?? true) && !!workspace && arbi.hasWorkspace,\n staleTime: Infinity,\n refetchOnMount: false,\n refetchOnReconnect: false,\n refetchOnWindowFocus: false,\n })\n}\n\n/** How often a document still being processed is re-read (`useDocument`'s `pollWhileProcessing`). */\nexport const DOCUMENT_STATUS_POLL_MS = 4000\n\n/** Re-read a document while it is processing (a viewer waiting for its pages). */\nfunction processingInterval(doc: WorkspaceDocument | null | undefined): number | false {\n return doc?.status && !FINISHED_DOCUMENT_STATUSES.has(doc.status)\n ? DOCUMENT_STATUS_POLL_MS\n : false\n}\n\n/**\n * One document (`null`: not found or not visible). `pollWhileProcessing` re-reads it every few\n * seconds until its processing is over. Writes here keep it current.\n */\nexport function useDocument(\n docId: string | null | undefined,\n options?: { enabled?: boolean; pollWhileProcessing?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.document(docId ?? ''),\n queryFn: async (): Promise<WorkspaceDocument | null> =>\n (await arbi.documents.get([docId as string]))[0] ?? null,\n enabled: (options?.enabled ?? true) && !!docId && arbi.isLoggedIn,\n refetchInterval: options?.pollWhileProcessing\n ? (query) => processingInterval(query.state.data)\n : false,\n })\n}\n\n/**\n * The similarity at or above which two documents count as near duplicates (the Related column).\n * The server keeps every pair above 0.75 but returns only those at or above what is asked.\n */\nexport const SIMILARITY_THRESHOLD = 0.98\n\n/** Near-duplicate document pairs in the open workspace, at or above {@link SIMILARITY_THRESHOLD}. */\nexport function useSimilarDocuments(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const workspace = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.similarDocuments(workspace, SIMILARITY_THRESHOLD),\n queryFn: () =>\n arbi.readInWorkspace(workspace, () =>\n arbi.documents.similar({ threshold: SIMILARITY_THRESHOLD })\n ),\n enabled: (options?.enabled ?? true) && !!workspace,\n })\n}\n\n// Each re-read gets a number; only the latest one issued for a document may write it. Events can\n// return out of order, and an older read must not undo tags a newer one applied.\nlet readSeq = 0\nconst latestReadByDoc = new Map<string, number>()\n\n/**\n * Re-read `docIds` and patch them into the caches that show them: their workspace's list (added\n * when new), their own entries, and the tag list's document counts (tags the server applied, e.g.\n * AI fields). For events that name documents (a batch finished, a version saved, an upload): the\n * list is never re-read for them. A failed read leaves the caches as they were.\n */\nexport async function refreshDocuments(\n qc: QueryClient,\n arbi: Arbi,\n docIds: string[]\n): Promise<WorkspaceDocument[]> {\n if (!docIds.length) return []\n const seq = ++readSeq\n for (const id of docIds) latestReadByDoc.set(id, seq)\n try {\n const read = await arbi.documents.get(docIds)\n const fresh = read\n .filter((doc) => latestReadByDoc.get(doc.external_id) === seq)\n .map((doc) => {\n // A finished status heard live wins over a read that predates it (the row may not be\n // committed yet), never over a row that finished after it.\n const live = useArbiWsStore.getState().tasks[doc.external_id]\n return live &&\n FINISHED_DOCUMENT_STATUSES.has(live.status) &&\n doc.status !== live.status &&\n isRowNewer(doc, live) !== true\n ? { ...doc, status: live.status }\n : doc\n })\n if (!fresh.length) return []\n reconcileTagCounts(qc, fresh)\n upsertDocuments(qc, fresh)\n for (const doc of fresh) setCachedDocument(qc, doc)\n return fresh\n } catch (error) {\n // Leave the caches as they were: re-reading the whole list would shrink it to its first page.\n console.error('Re-reading documents failed; the cached ones are kept:', error)\n return []\n } finally {\n for (const id of docIds) if (latestReadByDoc.get(id) === seq) latestReadByDoc.delete(id)\n }\n}\n\n/** `refreshDocuments` on this host's cache and `Arbi`, for a component or a hook. */\nexport function useRefreshDocuments(): (docIds: string[]) => Promise<WorkspaceDocument[]> {\n const qc = useQueryClient()\n const arbi = useArbi()\n return useCallback((docIds: string[]) => refreshDocuments(qc, arbi, docIds), [qc, arbi])\n}\n\n/** Move each tag's document count by the tags the re-read documents gained or lost. */\nfunction reconcileTagCounts(qc: QueryClient, fresh: WorkspaceDocument[]): void {\n const byWorkspace = new Map<string, Map<string, number>>()\n for (const doc of fresh) {\n const cached = getCachedDocuments(qc, doc.workspace_ext_id)?.find(\n (d) => d.external_id === doc.external_id\n )\n const before = new Set((cached?.doctags ?? []).map((dt) => dt.tag_ext_id))\n const after = new Set((doc.doctags ?? []).map((dt) => dt.tag_ext_id))\n const delta = byWorkspace.get(doc.workspace_ext_id) ?? new Map<string, number>()\n for (const id of after) if (!before.has(id)) delta.set(id, (delta.get(id) ?? 0) + 1)\n for (const id of before) if (!after.has(id)) delta.set(id, (delta.get(id) ?? 0) - 1)\n byWorkspace.set(doc.workspace_ext_id, delta)\n }\n for (const [workspaceId, delta] of byWorkspace) adjustTagCounts(qc, workspaceId, delta)\n}\n\n/** Add `delta` (tag id → change) to the tags' document counts; the tag tables re-read. */\nexport function adjustTagCounts(\n qc: QueryClient,\n workspaceId: string,\n delta: Map<string, number>\n): void {\n if (![...delta.values()].some(Boolean)) return\n patchWorkspaceTags(qc, workspaceId, (tags) =>\n tags.map((tag) => {\n const change = delta.get(tag.external_id)\n return change ? { ...tag, doctag_count: Math.max(0, tag.doctag_count + change) } : tag\n })\n )\n void invalidateTagTables(qc, workspaceId)\n}\n"]}