@arbidocs/blocks 0.4.72 → 0.4.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/index.cjs +400 -261
- package/dist/agents/index.js +6 -3
- package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
- package/dist/agents/tasks/WorkflowThreadStrip.d.ts +58 -0
- package/dist/agents/tasks/index.d.ts +1 -0
- package/dist/agents/workflows/WorkflowRunner.d.ts +70 -0
- package/dist/agents/workflows/index.d.ts +7 -1
- package/dist/agents/workflows/planSteps.d.ts +28 -0
- package/dist/agents/workflows/run.d.ts +97 -0
- package/dist/agents/workflows/skillMarkdown.d.ts +15 -0
- package/dist/agents/workflows/types.d.ts +109 -0
- package/dist/agents/workflows/useWorkflowPreview.d.ts +14 -0
- package/dist/agents/workflows/useWorkflowView.d.ts +54 -0
- package/dist/agents/workflows/workflow.d.ts +3 -1
- package/dist/chunk-2P3T23C7.js +1250 -0
- package/dist/chunk-2P3T23C7.js.map +1 -0
- package/dist/chunk-7D737FLE.cjs +43 -0
- package/dist/chunk-7D737FLE.cjs.map +1 -0
- package/dist/{chunk-LFGJAZ5H.js → chunk-DDF5GPIJ.js} +6 -36
- package/dist/chunk-DDF5GPIJ.js.map +1 -0
- package/dist/chunk-DETZZBG2.cjs +91 -0
- package/dist/chunk-DETZZBG2.cjs.map +1 -0
- package/dist/chunk-EVUEIBNU.js +89 -0
- package/dist/chunk-EVUEIBNU.js.map +1 -0
- package/dist/chunk-GTNUQBXI.cjs +1296 -0
- package/dist/chunk-GTNUQBXI.cjs.map +1 -0
- package/dist/{chunk-DH7C2UJO.cjs → chunk-IUR565UW.cjs} +297 -524
- package/dist/chunk-IUR565UW.cjs.map +1 -0
- package/dist/{chunk-THO7DZNN.cjs → chunk-MUMH3Z6K.cjs} +20 -15
- package/dist/chunk-MUMH3Z6K.cjs.map +1 -0
- package/dist/{chunk-KOXUBCLL.js → chunk-ORA2XE7U.js} +3 -3
- package/dist/{chunk-KOXUBCLL.js.map → chunk-ORA2XE7U.js.map} +1 -1
- package/dist/{chunk-5HOAOKZL.js → chunk-OYMWV45N.js} +21 -16
- package/dist/chunk-OYMWV45N.js.map +1 -0
- package/dist/{chunk-IMC2Z32C.js → chunk-QDNXEB3T.js} +268 -484
- package/dist/chunk-QDNXEB3T.js.map +1 -0
- package/dist/{chunk-G5QTGKDJ.cjs → chunk-WOYUXVVQ.cjs} +6 -6
- package/dist/{chunk-G5QTGKDJ.cjs.map → chunk-WOYUXVVQ.cjs.map} +1 -1
- package/dist/chunk-XD2M6LIG.js +41 -0
- package/dist/chunk-XD2M6LIG.js.map +1 -0
- package/dist/{chunk-WBDK4PIA.cjs → chunk-Z5VUZ6YD.cjs} +6 -37
- package/dist/chunk-Z5VUZ6YD.cjs.map +1 -0
- package/dist/connect/docx.cjs +2 -2
- package/dist/connect/docx.js +1 -1
- package/dist/connect/index.cjs +316 -23
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.ts +1 -0
- package/dist/connect/index.js +300 -8
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedWorkflowBuilder.d.ts +44 -0
- package/dist/connection/ConnectedWorkflowRunner.d.ts +27 -0
- package/dist/connection/useWorkflowThread.d.ts +34 -0
- package/dist/facts/index.cjs +1 -1
- package/dist/facts/index.js +1 -1
- package/dist/files/index.cjs +9 -83
- package/dist/files/index.cjs.map +1 -1
- package/dist/files/index.js +6 -83
- package/dist/files/index.js.map +1 -1
- package/dist/home/index.cjs +22 -21
- package/dist/home/index.cjs.map +1 -1
- package/dist/home/index.js +4 -3
- package/dist/home/index.js.map +1 -1
- package/dist/index.cjs +450 -311
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +5 -5
- package/dist/studio/index.js +3 -3
- package/dist/workflow-canvas/StepInspector.d.ts +46 -0
- package/dist/workflow-canvas/TriggerInspector.d.ts +46 -0
- package/dist/workflow-canvas/WorkflowBuilder.d.ts +55 -0
- package/dist/workflow-canvas/WorkflowCanvas.d.ts +65 -0
- package/dist/workflow-canvas/edit.d.ts +54 -0
- package/dist/workflow-canvas/index.cjs +1609 -0
- package/dist/workflow-canvas/index.cjs.map +1 -0
- package/dist/workflow-canvas/index.d.ts +13 -0
- package/dist/workflow-canvas/index.js +1579 -0
- package/dist/workflow-canvas/index.js.map +1 -0
- package/dist/workflow-canvas/trigger.d.ts +51 -0
- package/package.json +25 -14
- package/src/workflow-canvas/canvas.css +113 -0
- package/dist/chunk-5HOAOKZL.js.map +0 -1
- package/dist/chunk-DH7C2UJO.cjs.map +0 -1
- package/dist/chunk-IMC2Z32C.js.map +0 -1
- package/dist/chunk-LFGJAZ5H.js.map +0 -1
- package/dist/chunk-THO7DZNN.cjs.map +0 -1
- package/dist/chunk-WBDK4PIA.cjs.map +0 -1
|
@@ -57,7 +57,12 @@ function ConnectionProvider({
|
|
|
57
57
|
isLiveConfigured ? "connecting" : "disconnected"
|
|
58
58
|
);
|
|
59
59
|
const [user, setUser] = react.useState(null);
|
|
60
|
-
const [workspaceId,
|
|
60
|
+
const [workspaceId, setWorkspaceIdState] = react.useState(null);
|
|
61
|
+
const workspaceIdRef = react.useRef(null);
|
|
62
|
+
const selectWorkspaceId = react.useCallback((id) => {
|
|
63
|
+
workspaceIdRef.current = id;
|
|
64
|
+
setWorkspaceIdState(id);
|
|
65
|
+
}, []);
|
|
61
66
|
const [mode, setMode] = react.useState("demo");
|
|
62
67
|
const [error, setError] = react.useState(null);
|
|
63
68
|
const storageUserRef = react.useRef(null);
|
|
@@ -66,11 +71,11 @@ function ConnectionProvider({
|
|
|
66
71
|
rememberSessionUser(config.apiUrl, null);
|
|
67
72
|
storageUserRef.current = null;
|
|
68
73
|
setUser(null);
|
|
69
|
-
|
|
74
|
+
selectWorkspaceId(null);
|
|
70
75
|
setStatus("disconnected");
|
|
71
76
|
setError(SESSION_EXPIRED_MESSAGE);
|
|
72
77
|
}),
|
|
73
|
-
[arbi, config.apiUrl]
|
|
78
|
+
[arbi, config.apiUrl, selectWorkspaceId]
|
|
74
79
|
);
|
|
75
80
|
react.useEffect(
|
|
76
81
|
() => arbi.user.onProfileChange?.(
|
|
@@ -83,8 +88,8 @@ function ConnectionProvider({
|
|
|
83
88
|
setStatus("demo");
|
|
84
89
|
setError(null);
|
|
85
90
|
setUser({ name: config.demoUser.name, email: config.demoUser.email });
|
|
86
|
-
|
|
87
|
-
}, [config.demoUser.name, config.demoUser.email, demoWorkspaceId]);
|
|
91
|
+
selectWorkspaceId(demoWorkspaceId);
|
|
92
|
+
}, [config.demoUser.name, config.demoUser.email, demoWorkspaceId, selectWorkspaceId]);
|
|
88
93
|
const login = react.useCallback(
|
|
89
94
|
async (email, password, restoring = false) => {
|
|
90
95
|
setError(null);
|
|
@@ -109,7 +114,7 @@ function ConnectionProvider({
|
|
|
109
114
|
const preferred = persisted ?? config.workspaceId;
|
|
110
115
|
const target = (preferred ? workspaces.find((w) => w.external_id === preferred) : void 0) ?? workspaces[0];
|
|
111
116
|
await arbi.selectWorkspace(target.external_id);
|
|
112
|
-
|
|
117
|
+
selectWorkspaceId(target.external_id);
|
|
113
118
|
persistWorkspace(config.apiUrl, storageUserRef.current, target.external_id);
|
|
114
119
|
}
|
|
115
120
|
let resolved = { name: email.split("@")[0], email };
|
|
@@ -143,7 +148,7 @@ function ConnectionProvider({
|
|
|
143
148
|
setStatus("error");
|
|
144
149
|
}
|
|
145
150
|
},
|
|
146
|
-
[arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl]
|
|
151
|
+
[arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl, selectWorkspaceId]
|
|
147
152
|
);
|
|
148
153
|
const recoveryStarted = react.useRef(false);
|
|
149
154
|
react.useEffect(() => {
|
|
@@ -163,27 +168,27 @@ function ConnectionProvider({
|
|
|
163
168
|
void arbi.logout?.();
|
|
164
169
|
}
|
|
165
170
|
setUser(null);
|
|
166
|
-
|
|
171
|
+
selectWorkspaceId(null);
|
|
167
172
|
persistWorkspace(config.apiUrl, storageUserRef.current, null);
|
|
168
173
|
storageUserRef.current = null;
|
|
169
174
|
setStatus("disconnected");
|
|
170
175
|
setError(null);
|
|
171
|
-
}, [arbi, mode, config.apiUrl]);
|
|
176
|
+
}, [arbi, mode, config.apiUrl, selectWorkspaceId]);
|
|
172
177
|
const setWorkspace = react.useCallback(
|
|
173
178
|
async (id) => {
|
|
174
179
|
if (mode === "live" && arbi.isLoggedIn) {
|
|
175
180
|
await arbi.selectWorkspace(id);
|
|
176
181
|
}
|
|
177
|
-
|
|
182
|
+
selectWorkspaceId(id);
|
|
178
183
|
persistWorkspace(config.apiUrl, storageUserRef.current, id);
|
|
179
184
|
},
|
|
180
|
-
[arbi, mode, config.apiUrl]
|
|
185
|
+
[arbi, mode, config.apiUrl, selectWorkspaceId]
|
|
181
186
|
);
|
|
182
187
|
const ensureWorkspaceOpen = react.useCallback(async () => {
|
|
183
188
|
if (mode !== "live" || !arbi.isLoggedIn) return;
|
|
184
|
-
const id =
|
|
189
|
+
const id = workspaceIdRef.current ?? readPersistedWorkspace(config.apiUrl, storageUserRef.current) ?? config.workspaceId;
|
|
185
190
|
if (id) await arbi.selectWorkspace(id);
|
|
186
|
-
}, [arbi, mode,
|
|
191
|
+
}, [arbi, mode, config.apiUrl, config.workspaceId]);
|
|
187
192
|
const value = react.useMemo(
|
|
188
193
|
() => ({
|
|
189
194
|
mode,
|
|
@@ -233,5 +238,5 @@ exports.ConnectionProvider = ConnectionProvider;
|
|
|
233
238
|
exports.SESSION_EXPIRED_MESSAGE = SESSION_EXPIRED_MESSAGE;
|
|
234
239
|
exports.isAuthenticated = isAuthenticated;
|
|
235
240
|
exports.useConnection = useConnection;
|
|
236
|
-
//# sourceMappingURL=chunk-
|
|
237
|
-
//# sourceMappingURL=chunk-
|
|
241
|
+
//# sourceMappingURL=chunk-MUMH3Z6K.cjs.map
|
|
242
|
+
//# sourceMappingURL=chunk-MUMH3Z6K.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection/ConnectionProvider.tsx"],"names":["createContext","useArbi","useState","useRef","useCallback","useEffect","useMemo","jsx","useContext"],"mappings":"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","file":"chunk-MUMH3Z6K.cjs","sourcesContent":["/**\n * The demo/live connection layer for a host app. Holds auth + workspace\n * selection state and exposes it via {@link useConnection}, so every surface\n * works identically whether it's talking to a live ARBI backend or the seeded\n * demo workspace. Host-specific values (backend URL, demo identity, default\n * workspace/assistant ids) arrive once through {@link ArbiConnectionConfig}.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { useArbi, type LoginProfile } from '@arbidocs/react'\nimport type { ArbiMode, ArbiUser, ConnectionStatus, ArbiConnectionConfig } from './types'\n\ninterface ConnectionValue {\n mode: ArbiMode\n status: ConnectionStatus\n user: ArbiUser | null\n workspaceId: string | null\n apiConfigured: boolean\n apiUrl: string\n /**\n * The deployment domain the user's keys are derived for (`arbi.getDeploymentDomain()`), for the\n * document tools' e-signing. `undefined` in demo mode.\n */\n deploymentDomain: string | undefined\n error: string | null\n /** Default assistant config ext_id (for the AI hooks). */\n assistantConfig?: string\n /** Fallback workspace ext_id when none is actively selected. */\n fallbackWorkspaceId?: string\n /** Authenticate. Live login when a backend is configured, otherwise the demo workspace. */\n login: (email: string, password: string) => Promise<void>\n /** One-click demo entry (no backend required). */\n enterDemo: () => void\n logout: () => void\n /**\n * Affirmatively select a workspace: opens it on the server (via the SDK),\n * updates the app-wide state, and persists the choice so it survives future\n * logins. This is the single entry point for \"the user is now in workspace X\".\n */\n setWorkspace: (id: string) => Promise<void>\n /**\n * Re-assert the selected workspace on the server session (idempotent `/open`).\n * Call before a workspace-scoped write when the session may have lost its open\n * workspace (token re-login, backend restart, session expiry) — the server\n * resolves the workspace from the session, so a dropped `/open` yields\n * \"No active workspace\" until it's re-opened.\n */\n ensureWorkspaceOpen: () => Promise<void>\n}\n\nconst ConnectionContext = createContext<ConnectionValue | null>(null)\n\n/**\n * Persist the affirmatively-selected workspace per backend AND per signed-in user, so a returning\n * user lands back in the workspace they last chose, while the next person on a shared browser\n * never starts from someone else's workspace id. Namespaced by apiUrl so distinct deployments\n * (and the demo workspace) don't clobber each other. Cleared on logout.\n */\nconst WORKSPACE_STORAGE_PREFIX = 'arbi:selectedWorkspace'\nconst sessionUserKey = (apiUrl: string) => `arbi:sessionUser:${apiUrl}`\nfunction rememberSessionUser(apiUrl: string, email: string | null) {\n try {\n if (email) window.localStorage.setItem(sessionUserKey(apiUrl), normalizeUserKey(email))\n else window.localStorage.removeItem(sessionUserKey(apiUrl))\n } catch {\n /* Storage may be unavailable. */\n }\n}\nconst normalizeUserKey = (email: string) => email.trim().toLowerCase()\n\n/** Exported for tests. */\nexport const workspaceStorageKey = (apiUrl: string, userKey: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}:${normalizeUserKey(userKey)}`\n\n/** The pre-isolation key (apiUrl only). Never read: removed so it cannot leak across users. */\nconst legacyWorkspaceStorageKey = (apiUrl: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}`\n\nfunction readPersistedWorkspace(apiUrl: string, userKey: string | null): string | null {\n if (!userKey) return null\n try {\n return window.localStorage.getItem(workspaceStorageKey(apiUrl, userKey))\n } catch {\n return null\n }\n}\n\nfunction persistWorkspace(apiUrl: string, userKey: string | null, id: string | null): void {\n if (!userKey) return\n try {\n if (id) window.localStorage.setItem(workspaceStorageKey(apiUrl, userKey), id)\n else window.localStorage.removeItem(workspaceStorageKey(apiUrl, userKey))\n window.localStorage.removeItem(legacyWorkspaceStorageKey(apiUrl))\n } catch {\n // Storage unavailable (private mode, SSR) — selection stays in-memory only.\n }\n}\n\n/** Shown on the sign-in screen after the session could not be recovered. */\nexport const SESSION_EXPIRED_MESSAGE = 'Your session expired. Sign in again.'\n\n/** The connection user for a profile: its full name, falling back to the email local part. */\nfunction userFromProfile(profile: LoginProfile, externalId?: string): ArbiUser {\n const fullName = [profile.givenName, profile.familyName]\n .map((part) => part?.trim())\n .filter(Boolean)\n .join(' ')\n return {\n name: fullName || profile.email.split('@')[0],\n email: profile.email,\n externalId,\n picture: profile.picture,\n }\n}\n\nexport function ConnectionProvider({\n config,\n children,\n}: {\n config: ArbiConnectionConfig\n children: ReactNode\n}) {\n const arbi = useArbi()\n const isLiveConfigured = config.apiUrl.length > 0\n const demoWorkspaceId = config.demoWorkspaceId ?? 'demo-workspace'\n\n const [status, setStatus] = useState<ConnectionStatus>(\n isLiveConfigured ? 'connecting' : 'disconnected'\n )\n const [user, setUser] = useState<ArbiUser | null>(null)\n const [workspaceId, setWorkspaceIdState] = useState<string | null>(null)\n // The selected workspace as of now, not as of the last render: a flow that switches workspace\n // and then re-opens it in the same async chain (a step that creates a matter, then starts its\n // thread) must not re-open the one it just left.\n const workspaceIdRef = useRef<string | null>(null)\n const selectWorkspaceId = useCallback((id: string | null) => {\n workspaceIdRef.current = id\n setWorkspaceIdState(id)\n }, [])\n const [mode, setMode] = useState<ArbiMode>('demo')\n const [error, setError] = useState<string | null>(null)\n // Who the persisted workspace belongs to; set at sign-in, cleared at logout.\n const storageUserRef = useRef<string | null>(null)\n\n // The SDK could not recover the session (token refused, workspace not re-openable): drop to\n // 'disconnected' with a plain message, so the host's gate sends the user to sign in instead of\n // every call failing with a raw backend error. The remembered workspace is kept for next login.\n useEffect(\n () =>\n arbi.onSessionExpired?.(() => {\n rememberSessionUser(config.apiUrl, null)\n storageUserRef.current = null\n setUser(null)\n selectWorkspaceId(null)\n setStatus('disconnected')\n setError(SESSION_EXPIRED_MESSAGE)\n }),\n [arbi, config.apiUrl, selectWorkspaceId]\n )\n\n // A saved name, picture or email reaches every surface reading `useConnection().user`.\n useEffect(\n () =>\n arbi.user.onProfileChange?.((profile) =>\n setUser((current) => (current ? userFromProfile(profile, current.externalId) : current))\n ),\n [arbi]\n )\n\n const enterDemo = useCallback(() => {\n setMode('demo')\n setStatus('demo')\n setError(null)\n setUser({ name: config.demoUser.name, email: config.demoUser.email })\n selectWorkspaceId(demoWorkspaceId)\n }, [config.demoUser.name, config.demoUser.email, demoWorkspaceId, selectWorkspaceId])\n\n const login = useCallback(\n async (email: string, password: string, restoring = false) => {\n setError(null)\n // No backend configured → run the seeded demo workspace.\n if (!isLiveConfigured) {\n enterDemo()\n return\n }\n setStatus('connecting')\n setMode('live')\n try {\n if (restoring) {\n if (!(await arbi.restoreSession(email))) {\n rememberSessionUser(config.apiUrl, null)\n setStatus('disconnected')\n return\n }\n } else await arbi.login(email, password)\n storageUserRef.current = normalizeUserKey(email)\n const workspaces = await arbi.workspaces.list()\n if (workspaces?.length) {\n // Prefer the workspace the user last affirmatively selected (persisted),\n // then the configured workspace (there may be several — e.g. a\n // marketing/KM workspace), then whichever happens to be first. Ternary\n // (not `&&`) so an empty value can't leak `\"\"` into `target`.\n const persisted = readPersistedWorkspace(config.apiUrl, storageUserRef.current)\n const preferred = persisted ?? config.workspaceId\n const target =\n (preferred ? workspaces.find((w) => w.external_id === preferred) : undefined) ??\n workspaces[0]\n await arbi.selectWorkspace(target.external_id)\n selectWorkspaceId(target.external_id)\n persistWorkspace(config.apiUrl, storageUserRef.current, target.external_id)\n }\n // The profile (name + avatar) comes with the login response. A session restored without\n // a login has none, so fall back to finding ourselves in the workspace roster; the email\n // local part is only the last resort, never the answer when a profile name exists.\n let resolved: ArbiUser = { name: email.split('@')[0], email }\n const me = arbi.user.identity()\n const profile = arbi.user.profile?.()\n if (profile) {\n resolved = userFromProfile(profile, me?.externalId)\n } else {\n try {\n const members = await arbi.workspaces.listUsers()\n const self = members.find((m) => m.user.external_id === me?.externalId)?.user\n if (self) {\n const fullName = [self.given_name, self.family_name].filter(Boolean).join(' ').trim()\n resolved = {\n name: fullName || email.split('@')[0],\n email: self.email || email,\n externalId: self.external_id,\n picture: self.picture ?? null,\n }\n } else if (me?.externalId) {\n resolved.externalId = me.externalId\n }\n } catch {\n // Roster not available (e.g. no workspace) — keep the fallback identity.\n }\n }\n setUser(resolved)\n rememberSessionUser(config.apiUrl, email)\n setStatus('authenticated')\n } catch (e) {\n // Surface the real error — no silent fallback to a fake session.\n setError(e instanceof Error ? e.message : 'Sign-in failed. Check your credentials.')\n setStatus('error')\n }\n },\n [arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl, selectWorkspaceId]\n )\n\n // Run once even under StrictMode; passwords and signing keys are never stored here.\n const recoveryStarted = useRef(false)\n useEffect(() => {\n if (recoveryStarted.current || !isLiveConfigured) return\n recoveryStarted.current = true\n let email: string | null = null\n try {\n email = window.localStorage.getItem(sessionUserKey(config.apiUrl))\n } catch {\n /* unavailable */\n }\n if (email) void login(email, '', true)\n else setStatus('disconnected')\n }, [isLiveConfigured, config.apiUrl, login])\n\n const logout = useCallback(() => {\n rememberSessionUser(config.apiUrl, null)\n if (mode === 'live') {\n void arbi.logout?.()\n }\n setUser(null)\n selectWorkspaceId(null)\n persistWorkspace(config.apiUrl, storageUserRef.current, null)\n storageUserRef.current = null\n setStatus('disconnected')\n setError(null)\n }, [arbi, mode, config.apiUrl, selectWorkspaceId])\n\n // Affirmative selection: open the workspace on the server (live), then remember\n // it in state + storage so every surface — and the next login — is in sync.\n const setWorkspace = useCallback(\n async (id: string) => {\n if (mode === 'live' && arbi.isLoggedIn) {\n await arbi.selectWorkspace(id)\n }\n selectWorkspaceId(id)\n persistWorkspace(config.apiUrl, storageUserRef.current, id)\n },\n [arbi, mode, config.apiUrl, selectWorkspaceId]\n )\n\n // Re-open the selected workspace on the session if the server may have dropped\n // it. Idempotent: re-running `/open` for the already-selected workspace is safe.\n const ensureWorkspaceOpen = useCallback(async () => {\n if (mode !== 'live' || !arbi.isLoggedIn) return\n const id =\n workspaceIdRef.current ??\n readPersistedWorkspace(config.apiUrl, storageUserRef.current) ??\n config.workspaceId\n if (id) await arbi.selectWorkspace(id)\n }, [arbi, mode, config.apiUrl, config.workspaceId])\n\n const value = useMemo<ConnectionValue>(\n () => ({\n mode,\n status,\n user,\n workspaceId,\n apiConfigured: isLiveConfigured,\n apiUrl: config.apiUrl,\n deploymentDomain: isLiveConfigured ? arbi.getDeploymentDomain() : undefined,\n error,\n assistantConfig: config.assistantConfig,\n fallbackWorkspaceId: config.workspaceId,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n }),\n [\n mode,\n status,\n user,\n workspaceId,\n isLiveConfigured,\n config.apiUrl,\n arbi,\n config.assistantConfig,\n config.workspaceId,\n error,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n ]\n )\n\n return <ConnectionContext.Provider value={value}>{children}</ConnectionContext.Provider>\n}\n\nexport function useConnection(): ConnectionValue {\n const ctx = useContext(ConnectionContext)\n if (!ctx) throw new Error('useConnection must be used within ConnectionProvider')\n return ctx\n}\n\nexport const isAuthenticated = (s: ConnectionStatus) => s === 'demo' || s === 'authenticated'\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useConnection } from './chunk-
|
|
2
|
+
import { useConnection } from './chunk-OYMWV45N.js';
|
|
3
3
|
import { AssistantDock } from './chunk-G5DP27DU.js';
|
|
4
4
|
import { useCallback } from 'react';
|
|
5
5
|
import { useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, useWorkspaceUsers, useArbiChat } from '@arbidocs/react';
|
|
@@ -64,5 +64,5 @@ function ConnectedAssistantDock(props) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export { ConnectedAssistantDock, useConnectedAiTask, useConnectedChat, useSemanticSearch, useWorkspaceDocs };
|
|
67
|
-
//# sourceMappingURL=chunk-
|
|
68
|
-
//# sourceMappingURL=chunk-
|
|
67
|
+
//# sourceMappingURL=chunk-ORA2XE7U.js.map
|
|
68
|
+
//# sourceMappingURL=chunk-ORA2XE7U.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection/ai.tsx"],"names":["useKitAiTask","useKitWorkspaceDocs","useKitSemanticSearch"],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/connection/ai.tsx"],"names":["useKitAiTask","useKitWorkspaceDocs","useKitSemanticSearch"],"mappings":"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","file":"chunk-ORA2XE7U.js","sourcesContent":["/**\n * The connected agent hooks — thin adapters over the reusable AI kit in\n * `@arbidocs/react`. The streaming/accumulation/search plumbing lives once in\n * the SDK; these hooks only bind the *workspace source* (from the connection\n * context, falling back to the configured workspace) and inject the host's\n * default assistant *configuration* so call sites needn't know the config\n * ext_id. An explicit `opts.model` still wins.\n */\nimport { useCallback } from 'react'\nimport {\n useAiTask as useKitAiTask,\n useWorkspaceDocs as useKitWorkspaceDocs,\n useSemanticSearch as useKitSemanticSearch,\n useArbiChat,\n useWorkspaceUsers,\n type ArbiChat,\n type UseArbiChatOptions,\n type AiRunOptions,\n} from '@arbidocs/react'\nimport { useConnection } from './ConnectionProvider'\nimport { AssistantDock, type AssistantDockProps } from '../chat/AssistantDock'\nimport type { MentionCandidate } from '../chat/mentions'\n\nexport type { AiTaskStatus, AiRunOptions, SearchChunk, ArtifactEvent } from '@arbidocs/react'\n\n/** Client-side redlining, re-exported so a host app has one import surface. */\nexport { toRedlineMarkdown, redlineStats, textToArtifact } from '@arbidocs/react'\n\n/**\n * The kit's `useAiTask` with the host's default assistant configuration\n * injected, so call sites needn't know the config ext_id.\n */\nexport function useConnectedAiTask() {\n const { assistantConfig } = useConnection()\n const task = useKitAiTask()\n const kitRun = task.run\n const run = useCallback(\n (question: string, docIds: string[], opts?: AiRunOptions) =>\n kitRun(question, docIds, { ...opts, model: opts?.model ?? assistantConfig }),\n [kitRun, assistantConfig]\n )\n return { ...task, run }\n}\n\n/** Resolve the active workspace + its document ids (what we ground the agent on). */\nexport function useWorkspaceDocs() {\n const { workspaceId, fallbackWorkspaceId } = useConnection()\n return useKitWorkspaceDocs(workspaceId ?? fallbackWorkspaceId)\n}\n\n/** Search the active workspace's documents and return the top matching passages. */\nexport function useSemanticSearch() {\n const { docIds } = useWorkspaceDocs()\n return useKitSemanticSearch(docIds)\n}\n\n/**\n * The chat controller for `ChatPage` bound to the connection: the active workspace and the host's\n * default assistant configuration are injected, so a host writes\n * `<ChatPage chat={useConnectedChat()} />`.\n */\nexport function useConnectedChat(\n options?: Omit<UseArbiChatOptions, 'workspaceId'>\n): ArbiChat & { mentionCandidates: MentionCandidate[] } {\n const { workspaceId, fallbackWorkspaceId, assistantConfig, user, status, ensureWorkspaceOpen } =\n useConnection()\n const wsId = workspaceId ?? fallbackWorkspaceId\n const { data: members = [] } = useWorkspaceUsers(wsId, {\n enabled: status === 'authenticated' && !!wsId,\n beforeFetch: ensureWorkspaceOpen,\n })\n const mentionCandidates: MentionCandidate[] = [\n { id: 'assistant', kind: 'assistant', label: 'Assistant' },\n ...(status === 'authenticated' ? members : [])\n .filter(\n (member) =>\n !member.agent_ext_id &&\n member.user.external_id !== user?.externalId &&\n !member.user.external_id.startsWith('agt-')\n )\n .map((member) => ({\n id: member.user.external_id,\n kind: 'user' as const,\n label:\n [member.user.given_name, member.user.family_name].filter(Boolean).join(' ') ||\n member.user.email,\n description: member.user.email,\n }))\n .sort((a, b) => a.label.localeCompare(b.label)),\n ]\n const chat = useArbiChat({\n ...options,\n workspaceId: workspaceId ?? fallbackWorkspaceId,\n model: options?.model ?? assistantConfig,\n })\n return {\n ...chat,\n mentionCandidates,\n messages: chat.messages.map((message) => ({\n ...message,\n ...(message.authorId\n ? {\n senderName:\n message.authorId === user?.externalId\n ? user?.name || user?.email\n : mentionCandidates.find((candidate) => candidate.id === message.authorId)?.label,\n }\n : {}),\n })),\n }\n}\n\n/**\n * The assistant dock bound to the connection: mount it once in the layout (`Shell.Root`'s `aside`)\n * and put `AssistantDockToggle` in the topbar. Chat state lives here, so it survives closing the dock.\n */\nexport function ConnectedAssistantDock(props: Omit<AssistantDockProps, 'chat'>) {\n const chat = useConnectedChat()\n return <AssistantDock {...props} chat={chat} />\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext, useState, useRef,
|
|
2
|
+
import { createContext, useState, useRef, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
3
3
|
import { useArbi } from '@arbidocs/react';
|
|
4
4
|
import { jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -55,7 +55,12 @@ function ConnectionProvider({
|
|
|
55
55
|
isLiveConfigured ? "connecting" : "disconnected"
|
|
56
56
|
);
|
|
57
57
|
const [user, setUser] = useState(null);
|
|
58
|
-
const [workspaceId,
|
|
58
|
+
const [workspaceId, setWorkspaceIdState] = useState(null);
|
|
59
|
+
const workspaceIdRef = useRef(null);
|
|
60
|
+
const selectWorkspaceId = useCallback((id) => {
|
|
61
|
+
workspaceIdRef.current = id;
|
|
62
|
+
setWorkspaceIdState(id);
|
|
63
|
+
}, []);
|
|
59
64
|
const [mode, setMode] = useState("demo");
|
|
60
65
|
const [error, setError] = useState(null);
|
|
61
66
|
const storageUserRef = useRef(null);
|
|
@@ -64,11 +69,11 @@ function ConnectionProvider({
|
|
|
64
69
|
rememberSessionUser(config.apiUrl, null);
|
|
65
70
|
storageUserRef.current = null;
|
|
66
71
|
setUser(null);
|
|
67
|
-
|
|
72
|
+
selectWorkspaceId(null);
|
|
68
73
|
setStatus("disconnected");
|
|
69
74
|
setError(SESSION_EXPIRED_MESSAGE);
|
|
70
75
|
}),
|
|
71
|
-
[arbi, config.apiUrl]
|
|
76
|
+
[arbi, config.apiUrl, selectWorkspaceId]
|
|
72
77
|
);
|
|
73
78
|
useEffect(
|
|
74
79
|
() => arbi.user.onProfileChange?.(
|
|
@@ -81,8 +86,8 @@ function ConnectionProvider({
|
|
|
81
86
|
setStatus("demo");
|
|
82
87
|
setError(null);
|
|
83
88
|
setUser({ name: config.demoUser.name, email: config.demoUser.email });
|
|
84
|
-
|
|
85
|
-
}, [config.demoUser.name, config.demoUser.email, demoWorkspaceId]);
|
|
89
|
+
selectWorkspaceId(demoWorkspaceId);
|
|
90
|
+
}, [config.demoUser.name, config.demoUser.email, demoWorkspaceId, selectWorkspaceId]);
|
|
86
91
|
const login = useCallback(
|
|
87
92
|
async (email, password, restoring = false) => {
|
|
88
93
|
setError(null);
|
|
@@ -107,7 +112,7 @@ function ConnectionProvider({
|
|
|
107
112
|
const preferred = persisted ?? config.workspaceId;
|
|
108
113
|
const target = (preferred ? workspaces.find((w) => w.external_id === preferred) : void 0) ?? workspaces[0];
|
|
109
114
|
await arbi.selectWorkspace(target.external_id);
|
|
110
|
-
|
|
115
|
+
selectWorkspaceId(target.external_id);
|
|
111
116
|
persistWorkspace(config.apiUrl, storageUserRef.current, target.external_id);
|
|
112
117
|
}
|
|
113
118
|
let resolved = { name: email.split("@")[0], email };
|
|
@@ -141,7 +146,7 @@ function ConnectionProvider({
|
|
|
141
146
|
setStatus("error");
|
|
142
147
|
}
|
|
143
148
|
},
|
|
144
|
-
[arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl]
|
|
149
|
+
[arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl, selectWorkspaceId]
|
|
145
150
|
);
|
|
146
151
|
const recoveryStarted = useRef(false);
|
|
147
152
|
useEffect(() => {
|
|
@@ -161,27 +166,27 @@ function ConnectionProvider({
|
|
|
161
166
|
void arbi.logout?.();
|
|
162
167
|
}
|
|
163
168
|
setUser(null);
|
|
164
|
-
|
|
169
|
+
selectWorkspaceId(null);
|
|
165
170
|
persistWorkspace(config.apiUrl, storageUserRef.current, null);
|
|
166
171
|
storageUserRef.current = null;
|
|
167
172
|
setStatus("disconnected");
|
|
168
173
|
setError(null);
|
|
169
|
-
}, [arbi, mode, config.apiUrl]);
|
|
174
|
+
}, [arbi, mode, config.apiUrl, selectWorkspaceId]);
|
|
170
175
|
const setWorkspace = useCallback(
|
|
171
176
|
async (id) => {
|
|
172
177
|
if (mode === "live" && arbi.isLoggedIn) {
|
|
173
178
|
await arbi.selectWorkspace(id);
|
|
174
179
|
}
|
|
175
|
-
|
|
180
|
+
selectWorkspaceId(id);
|
|
176
181
|
persistWorkspace(config.apiUrl, storageUserRef.current, id);
|
|
177
182
|
},
|
|
178
|
-
[arbi, mode, config.apiUrl]
|
|
183
|
+
[arbi, mode, config.apiUrl, selectWorkspaceId]
|
|
179
184
|
);
|
|
180
185
|
const ensureWorkspaceOpen = useCallback(async () => {
|
|
181
186
|
if (mode !== "live" || !arbi.isLoggedIn) return;
|
|
182
|
-
const id =
|
|
187
|
+
const id = workspaceIdRef.current ?? readPersistedWorkspace(config.apiUrl, storageUserRef.current) ?? config.workspaceId;
|
|
183
188
|
if (id) await arbi.selectWorkspace(id);
|
|
184
|
-
}, [arbi, mode,
|
|
189
|
+
}, [arbi, mode, config.apiUrl, config.workspaceId]);
|
|
185
190
|
const value = useMemo(
|
|
186
191
|
() => ({
|
|
187
192
|
mode,
|
|
@@ -228,5 +233,5 @@ function useConnection() {
|
|
|
228
233
|
var isAuthenticated = (s) => s === "demo" || s === "authenticated";
|
|
229
234
|
|
|
230
235
|
export { ConnectionProvider, SESSION_EXPIRED_MESSAGE, isAuthenticated, useConnection };
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
232
|
-
//# sourceMappingURL=chunk-
|
|
236
|
+
//# sourceMappingURL=chunk-OYMWV45N.js.map
|
|
237
|
+
//# sourceMappingURL=chunk-OYMWV45N.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection/ConnectionProvider.tsx"],"names":[],"mappings":"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","file":"chunk-OYMWV45N.js","sourcesContent":["/**\n * The demo/live connection layer for a host app. Holds auth + workspace\n * selection state and exposes it via {@link useConnection}, so every surface\n * works identically whether it's talking to a live ARBI backend or the seeded\n * demo workspace. Host-specific values (backend URL, demo identity, default\n * workspace/assistant ids) arrive once through {@link ArbiConnectionConfig}.\n */\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { useArbi, type LoginProfile } from '@arbidocs/react'\nimport type { ArbiMode, ArbiUser, ConnectionStatus, ArbiConnectionConfig } from './types'\n\ninterface ConnectionValue {\n mode: ArbiMode\n status: ConnectionStatus\n user: ArbiUser | null\n workspaceId: string | null\n apiConfigured: boolean\n apiUrl: string\n /**\n * The deployment domain the user's keys are derived for (`arbi.getDeploymentDomain()`), for the\n * document tools' e-signing. `undefined` in demo mode.\n */\n deploymentDomain: string | undefined\n error: string | null\n /** Default assistant config ext_id (for the AI hooks). */\n assistantConfig?: string\n /** Fallback workspace ext_id when none is actively selected. */\n fallbackWorkspaceId?: string\n /** Authenticate. Live login when a backend is configured, otherwise the demo workspace. */\n login: (email: string, password: string) => Promise<void>\n /** One-click demo entry (no backend required). */\n enterDemo: () => void\n logout: () => void\n /**\n * Affirmatively select a workspace: opens it on the server (via the SDK),\n * updates the app-wide state, and persists the choice so it survives future\n * logins. This is the single entry point for \"the user is now in workspace X\".\n */\n setWorkspace: (id: string) => Promise<void>\n /**\n * Re-assert the selected workspace on the server session (idempotent `/open`).\n * Call before a workspace-scoped write when the session may have lost its open\n * workspace (token re-login, backend restart, session expiry) — the server\n * resolves the workspace from the session, so a dropped `/open` yields\n * \"No active workspace\" until it's re-opened.\n */\n ensureWorkspaceOpen: () => Promise<void>\n}\n\nconst ConnectionContext = createContext<ConnectionValue | null>(null)\n\n/**\n * Persist the affirmatively-selected workspace per backend AND per signed-in user, so a returning\n * user lands back in the workspace they last chose, while the next person on a shared browser\n * never starts from someone else's workspace id. Namespaced by apiUrl so distinct deployments\n * (and the demo workspace) don't clobber each other. Cleared on logout.\n */\nconst WORKSPACE_STORAGE_PREFIX = 'arbi:selectedWorkspace'\nconst sessionUserKey = (apiUrl: string) => `arbi:sessionUser:${apiUrl}`\nfunction rememberSessionUser(apiUrl: string, email: string | null) {\n try {\n if (email) window.localStorage.setItem(sessionUserKey(apiUrl), normalizeUserKey(email))\n else window.localStorage.removeItem(sessionUserKey(apiUrl))\n } catch {\n /* Storage may be unavailable. */\n }\n}\nconst normalizeUserKey = (email: string) => email.trim().toLowerCase()\n\n/** Exported for tests. */\nexport const workspaceStorageKey = (apiUrl: string, userKey: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}:${normalizeUserKey(userKey)}`\n\n/** The pre-isolation key (apiUrl only). Never read: removed so it cannot leak across users. */\nconst legacyWorkspaceStorageKey = (apiUrl: string) =>\n `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || 'demo'}`\n\nfunction readPersistedWorkspace(apiUrl: string, userKey: string | null): string | null {\n if (!userKey) return null\n try {\n return window.localStorage.getItem(workspaceStorageKey(apiUrl, userKey))\n } catch {\n return null\n }\n}\n\nfunction persistWorkspace(apiUrl: string, userKey: string | null, id: string | null): void {\n if (!userKey) return\n try {\n if (id) window.localStorage.setItem(workspaceStorageKey(apiUrl, userKey), id)\n else window.localStorage.removeItem(workspaceStorageKey(apiUrl, userKey))\n window.localStorage.removeItem(legacyWorkspaceStorageKey(apiUrl))\n } catch {\n // Storage unavailable (private mode, SSR) — selection stays in-memory only.\n }\n}\n\n/** Shown on the sign-in screen after the session could not be recovered. */\nexport const SESSION_EXPIRED_MESSAGE = 'Your session expired. Sign in again.'\n\n/** The connection user for a profile: its full name, falling back to the email local part. */\nfunction userFromProfile(profile: LoginProfile, externalId?: string): ArbiUser {\n const fullName = [profile.givenName, profile.familyName]\n .map((part) => part?.trim())\n .filter(Boolean)\n .join(' ')\n return {\n name: fullName || profile.email.split('@')[0],\n email: profile.email,\n externalId,\n picture: profile.picture,\n }\n}\n\nexport function ConnectionProvider({\n config,\n children,\n}: {\n config: ArbiConnectionConfig\n children: ReactNode\n}) {\n const arbi = useArbi()\n const isLiveConfigured = config.apiUrl.length > 0\n const demoWorkspaceId = config.demoWorkspaceId ?? 'demo-workspace'\n\n const [status, setStatus] = useState<ConnectionStatus>(\n isLiveConfigured ? 'connecting' : 'disconnected'\n )\n const [user, setUser] = useState<ArbiUser | null>(null)\n const [workspaceId, setWorkspaceIdState] = useState<string | null>(null)\n // The selected workspace as of now, not as of the last render: a flow that switches workspace\n // and then re-opens it in the same async chain (a step that creates a matter, then starts its\n // thread) must not re-open the one it just left.\n const workspaceIdRef = useRef<string | null>(null)\n const selectWorkspaceId = useCallback((id: string | null) => {\n workspaceIdRef.current = id\n setWorkspaceIdState(id)\n }, [])\n const [mode, setMode] = useState<ArbiMode>('demo')\n const [error, setError] = useState<string | null>(null)\n // Who the persisted workspace belongs to; set at sign-in, cleared at logout.\n const storageUserRef = useRef<string | null>(null)\n\n // The SDK could not recover the session (token refused, workspace not re-openable): drop to\n // 'disconnected' with a plain message, so the host's gate sends the user to sign in instead of\n // every call failing with a raw backend error. The remembered workspace is kept for next login.\n useEffect(\n () =>\n arbi.onSessionExpired?.(() => {\n rememberSessionUser(config.apiUrl, null)\n storageUserRef.current = null\n setUser(null)\n selectWorkspaceId(null)\n setStatus('disconnected')\n setError(SESSION_EXPIRED_MESSAGE)\n }),\n [arbi, config.apiUrl, selectWorkspaceId]\n )\n\n // A saved name, picture or email reaches every surface reading `useConnection().user`.\n useEffect(\n () =>\n arbi.user.onProfileChange?.((profile) =>\n setUser((current) => (current ? userFromProfile(profile, current.externalId) : current))\n ),\n [arbi]\n )\n\n const enterDemo = useCallback(() => {\n setMode('demo')\n setStatus('demo')\n setError(null)\n setUser({ name: config.demoUser.name, email: config.demoUser.email })\n selectWorkspaceId(demoWorkspaceId)\n }, [config.demoUser.name, config.demoUser.email, demoWorkspaceId, selectWorkspaceId])\n\n const login = useCallback(\n async (email: string, password: string, restoring = false) => {\n setError(null)\n // No backend configured → run the seeded demo workspace.\n if (!isLiveConfigured) {\n enterDemo()\n return\n }\n setStatus('connecting')\n setMode('live')\n try {\n if (restoring) {\n if (!(await arbi.restoreSession(email))) {\n rememberSessionUser(config.apiUrl, null)\n setStatus('disconnected')\n return\n }\n } else await arbi.login(email, password)\n storageUserRef.current = normalizeUserKey(email)\n const workspaces = await arbi.workspaces.list()\n if (workspaces?.length) {\n // Prefer the workspace the user last affirmatively selected (persisted),\n // then the configured workspace (there may be several — e.g. a\n // marketing/KM workspace), then whichever happens to be first. Ternary\n // (not `&&`) so an empty value can't leak `\"\"` into `target`.\n const persisted = readPersistedWorkspace(config.apiUrl, storageUserRef.current)\n const preferred = persisted ?? config.workspaceId\n const target =\n (preferred ? workspaces.find((w) => w.external_id === preferred) : undefined) ??\n workspaces[0]\n await arbi.selectWorkspace(target.external_id)\n selectWorkspaceId(target.external_id)\n persistWorkspace(config.apiUrl, storageUserRef.current, target.external_id)\n }\n // The profile (name + avatar) comes with the login response. A session restored without\n // a login has none, so fall back to finding ourselves in the workspace roster; the email\n // local part is only the last resort, never the answer when a profile name exists.\n let resolved: ArbiUser = { name: email.split('@')[0], email }\n const me = arbi.user.identity()\n const profile = arbi.user.profile?.()\n if (profile) {\n resolved = userFromProfile(profile, me?.externalId)\n } else {\n try {\n const members = await arbi.workspaces.listUsers()\n const self = members.find((m) => m.user.external_id === me?.externalId)?.user\n if (self) {\n const fullName = [self.given_name, self.family_name].filter(Boolean).join(' ').trim()\n resolved = {\n name: fullName || email.split('@')[0],\n email: self.email || email,\n externalId: self.external_id,\n picture: self.picture ?? null,\n }\n } else if (me?.externalId) {\n resolved.externalId = me.externalId\n }\n } catch {\n // Roster not available (e.g. no workspace) — keep the fallback identity.\n }\n }\n setUser(resolved)\n rememberSessionUser(config.apiUrl, email)\n setStatus('authenticated')\n } catch (e) {\n // Surface the real error — no silent fallback to a fake session.\n setError(e instanceof Error ? e.message : 'Sign-in failed. Check your credentials.')\n setStatus('error')\n }\n },\n [arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl, selectWorkspaceId]\n )\n\n // Run once even under StrictMode; passwords and signing keys are never stored here.\n const recoveryStarted = useRef(false)\n useEffect(() => {\n if (recoveryStarted.current || !isLiveConfigured) return\n recoveryStarted.current = true\n let email: string | null = null\n try {\n email = window.localStorage.getItem(sessionUserKey(config.apiUrl))\n } catch {\n /* unavailable */\n }\n if (email) void login(email, '', true)\n else setStatus('disconnected')\n }, [isLiveConfigured, config.apiUrl, login])\n\n const logout = useCallback(() => {\n rememberSessionUser(config.apiUrl, null)\n if (mode === 'live') {\n void arbi.logout?.()\n }\n setUser(null)\n selectWorkspaceId(null)\n persistWorkspace(config.apiUrl, storageUserRef.current, null)\n storageUserRef.current = null\n setStatus('disconnected')\n setError(null)\n }, [arbi, mode, config.apiUrl, selectWorkspaceId])\n\n // Affirmative selection: open the workspace on the server (live), then remember\n // it in state + storage so every surface — and the next login — is in sync.\n const setWorkspace = useCallback(\n async (id: string) => {\n if (mode === 'live' && arbi.isLoggedIn) {\n await arbi.selectWorkspace(id)\n }\n selectWorkspaceId(id)\n persistWorkspace(config.apiUrl, storageUserRef.current, id)\n },\n [arbi, mode, config.apiUrl, selectWorkspaceId]\n )\n\n // Re-open the selected workspace on the session if the server may have dropped\n // it. Idempotent: re-running `/open` for the already-selected workspace is safe.\n const ensureWorkspaceOpen = useCallback(async () => {\n if (mode !== 'live' || !arbi.isLoggedIn) return\n const id =\n workspaceIdRef.current ??\n readPersistedWorkspace(config.apiUrl, storageUserRef.current) ??\n config.workspaceId\n if (id) await arbi.selectWorkspace(id)\n }, [arbi, mode, config.apiUrl, config.workspaceId])\n\n const value = useMemo<ConnectionValue>(\n () => ({\n mode,\n status,\n user,\n workspaceId,\n apiConfigured: isLiveConfigured,\n apiUrl: config.apiUrl,\n deploymentDomain: isLiveConfigured ? arbi.getDeploymentDomain() : undefined,\n error,\n assistantConfig: config.assistantConfig,\n fallbackWorkspaceId: config.workspaceId,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n }),\n [\n mode,\n status,\n user,\n workspaceId,\n isLiveConfigured,\n config.apiUrl,\n arbi,\n config.assistantConfig,\n config.workspaceId,\n error,\n login,\n enterDemo,\n logout,\n setWorkspace,\n ensureWorkspaceOpen,\n ]\n )\n\n return <ConnectionContext.Provider value={value}>{children}</ConnectionContext.Provider>\n}\n\nexport function useConnection(): ConnectionValue {\n const ctx = useContext(ConnectionContext)\n if (!ctx) throw new Error('useConnection must be used within ConnectionProvider')\n return ctx\n}\n\nexport const isAuthenticated = (s: ConnectionStatus) => s === 'demo' || s === 'authenticated'\n"]}
|