@assistant-ui/react 0.7.23 → 0.7.25
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/api/AssistantRuntime.d.ts +1 -1
- package/dist/api/AssistantRuntime.d.ts.map +1 -1
- package/dist/api/AssistantRuntime.js +1 -1
- package/dist/api/AssistantRuntime.js.map +1 -1
- package/dist/api/AssistantRuntime.mjs +1 -1
- package/dist/api/AssistantRuntime.mjs.map +1 -1
- package/dist/api/ComposerRuntime.d.ts +4 -2
- package/dist/api/ComposerRuntime.d.ts.map +1 -1
- package/dist/api/ComposerRuntime.js +6 -1
- package/dist/api/ComposerRuntime.js.map +1 -1
- package/dist/api/ComposerRuntime.mjs +6 -1
- package/dist/api/ComposerRuntime.mjs.map +1 -1
- package/dist/api/ThreadListItemRuntime.d.ts +3 -1
- package/dist/api/ThreadListItemRuntime.d.ts.map +1 -1
- package/dist/api/ThreadListItemRuntime.js.map +1 -1
- package/dist/api/ThreadListItemRuntime.mjs.map +1 -1
- package/dist/api/ThreadListRuntime.d.ts +8 -8
- package/dist/api/ThreadListRuntime.d.ts.map +1 -1
- package/dist/api/ThreadListRuntime.js +7 -5
- package/dist/api/ThreadListRuntime.js.map +1 -1
- package/dist/api/ThreadListRuntime.mjs +7 -5
- package/dist/api/ThreadListRuntime.mjs.map +1 -1
- package/dist/api/ThreadRuntime.d.ts +59 -32
- package/dist/api/ThreadRuntime.d.ts.map +1 -1
- package/dist/api/ThreadRuntime.js +2 -2
- package/dist/api/ThreadRuntime.js.map +1 -1
- package/dist/api/ThreadRuntime.mjs +2 -2
- package/dist/api/ThreadRuntime.mjs.map +1 -1
- package/dist/context/providers/AssistantRuntimeProvider.d.ts.map +1 -1
- package/dist/context/providers/AssistantRuntimeProvider.js +8 -3
- package/dist/context/providers/AssistantRuntimeProvider.js.map +1 -1
- package/dist/context/providers/AssistantRuntimeProvider.mjs +8 -3
- package/dist/context/providers/AssistantRuntimeProvider.mjs.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.js +2 -4
- package/dist/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.mjs +2 -4
- package/dist/primitives/threadList/ThreadListItems.mjs.map +1 -1
- package/dist/runtimes/composer/BaseComposerRuntimeCore.d.ts +6 -6
- package/dist/runtimes/composer/BaseComposerRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/composer/BaseComposerRuntimeCore.js +29 -20
- package/dist/runtimes/composer/BaseComposerRuntimeCore.js.map +1 -1
- package/dist/runtimes/composer/BaseComposerRuntimeCore.mjs +29 -20
- package/dist/runtimes/composer/BaseComposerRuntimeCore.mjs.map +1 -1
- package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.js +2 -3
- package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.js.map +1 -1
- package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.mjs +2 -3
- package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.mjs.map +1 -1
- package/dist/runtimes/composer/DefaultThreadComposerRuntimeCore.js +1 -1
- package/dist/runtimes/composer/DefaultThreadComposerRuntimeCore.js.map +1 -1
- package/dist/runtimes/composer/DefaultThreadComposerRuntimeCore.mjs +1 -1
- package/dist/runtimes/composer/DefaultThreadComposerRuntimeCore.mjs.map +1 -1
- package/dist/runtimes/core/AssistantRuntimeCore.d.ts +2 -0
- package/dist/runtimes/core/AssistantRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/core/AssistantRuntimeCore.js.map +1 -1
- package/dist/runtimes/core/ComposerRuntimeCore.d.ts +2 -1
- package/dist/runtimes/core/ComposerRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/core/ComposerRuntimeCore.js.map +1 -1
- package/dist/runtimes/core/ThreadListRuntimeCore.d.ts +4 -1
- package/dist/runtimes/core/ThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/core/ThreadListRuntimeCore.js.map +1 -1
- package/dist/runtimes/external-store/ExternalStoreAdapter.d.ts +1 -1
- package/dist/runtimes/external-store/ExternalStoreAdapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/ExternalStoreAdapter.js.map +1 -1
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.d.ts +1 -0
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.js +5 -1
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.js.map +1 -1
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.mjs +5 -1
- package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.mjs.map +1 -1
- package/dist/runtimes/index.d.ts +5 -4
- package/dist/runtimes/index.d.ts.map +1 -1
- package/dist/runtimes/index.js +11 -9
- package/dist/runtimes/index.js.map +1 -1
- package/dist/runtimes/index.mjs +5 -4
- package/dist/runtimes/index.mjs.map +1 -1
- package/dist/runtimes/local/LocalThreadListRuntimeCore.d.ts +2 -1
- package/dist/runtimes/local/LocalThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/local/LocalThreadListRuntimeCore.js +12 -8
- package/dist/runtimes/local/LocalThreadListRuntimeCore.js.map +1 -1
- package/dist/runtimes/local/LocalThreadListRuntimeCore.mjs +12 -8
- package/dist/runtimes/local/LocalThreadListRuntimeCore.mjs.map +1 -1
- package/dist/runtimes/remote-thread-list/BaseSubscribable.d.ts +8 -0
- package/dist/runtimes/remote-thread-list/BaseSubscribable.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/BaseSubscribable.js +62 -0
- package/dist/runtimes/remote-thread-list/BaseSubscribable.js.map +1 -0
- package/dist/runtimes/remote-thread-list/BaseSubscribable.mjs +37 -0
- package/dist/runtimes/remote-thread-list/BaseSubscribable.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.d.ts +3 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js +150 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js.map +1 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs +125 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.d.ts +23 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.js +83 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.js.map +1 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.mjs +58 -0
- package/dist/runtimes/remote-thread-list/OptimisticState.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts +75 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.js +127 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.js.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.mjs +102 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts +76 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js +396 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js.map +1 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.mjs +371 -0
- package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.d.ts +7 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.js +39 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.mjs +14 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloud.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.d.ts +19 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.js +79 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.mjs +57 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAPI.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.d.ts +20 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.js +95 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.mjs +69 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.d.ts +46 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.js +50 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.mjs +25 -0
- package/dist/runtimes/remote-thread-list/cloud/AssistantCloudThreads.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.d.ts +10 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.js +32 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.mjs +7 -0
- package/dist/runtimes/remote-thread-list/cloud/CloudContext.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/index.d.ts +4 -0
- package/dist/runtimes/remote-thread-list/cloud/index.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/index.js +37 -0
- package/dist/runtimes/remote-thread-list/cloud/index.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/index.mjs +10 -0
- package/dist/runtimes/remote-thread-list/cloud/index.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.d.ts +4 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.js +46 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.mjs +22 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.d.ts +14 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.js +103 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.js.map +1 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.mjs +79 -0
- package/dist/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/index.d.ts +2 -0
- package/dist/runtimes/remote-thread-list/index.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/index.js +25 -0
- package/dist/runtimes/remote-thread-list/index.js.map +1 -0
- package/dist/runtimes/remote-thread-list/index.mjs +3 -0
- package/dist/runtimes/remote-thread-list/index.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts +25 -0
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/types.js +19 -0
- package/dist/runtimes/remote-thread-list/types.js.map +1 -0
- package/dist/runtimes/remote-thread-list/types.mjs +1 -0
- package/dist/runtimes/remote-thread-list/types.mjs.map +1 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.d.ts +3 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.js +51 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.js.map +1 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.mjs +26 -0
- package/dist/runtimes/remote-thread-list/useRemoteThreadListRuntime.mjs.map +1 -0
- package/dist/styles/index.css +2 -0
- package/dist/styles/index.css.map +1 -1
- package/dist/styles/tailwindcss/thread.css +5 -1
- package/dist/styles/tailwindcss/thread.css.json +4 -1
- package/dist/ui/attachment-ui.d.ts.map +1 -1
- package/dist/ui/attachment-ui.js +12 -7
- package/dist/ui/attachment-ui.js.map +1 -1
- package/dist/ui/attachment-ui.mjs +12 -7
- package/dist/ui/attachment-ui.mjs.map +1 -1
- package/dist/utils/createActionButton.d.ts +2 -2
- package/dist/utils/createActionButton.d.ts.map +1 -1
- package/dist/utils/createActionButton.js +2 -4
- package/dist/utils/createActionButton.js.map +1 -1
- package/dist/utils/createActionButton.mjs +5 -5
- package/dist/utils/createActionButton.mjs.map +1 -1
- package/package.json +3 -3
- package/src/api/AssistantRuntime.ts +2 -6
- package/src/api/ComposerRuntime.ts +10 -2
- package/src/api/ThreadListItemRuntime.ts +3 -1
- package/src/api/ThreadListRuntime.ts +11 -9
- package/src/api/ThreadRuntime.ts +3 -3
- package/src/context/providers/AssistantRuntimeProvider.tsx +21 -6
- package/src/primitives/threadList/ThreadListItems.tsx +3 -5
- package/src/runtimes/composer/BaseComposerRuntimeCore.tsx +43 -25
- package/src/runtimes/composer/DefaultEditComposerRuntimeCore.tsx +2 -3
- package/src/runtimes/composer/DefaultThreadComposerRuntimeCore.tsx +1 -1
- package/src/runtimes/core/AssistantRuntimeCore.tsx +3 -0
- package/src/runtimes/core/ComposerRuntimeCore.tsx +2 -1
- package/src/runtimes/core/ThreadListRuntimeCore.tsx +5 -2
- package/src/runtimes/external-store/ExternalStoreAdapter.tsx +1 -1
- package/src/runtimes/external-store/ExternalStoreThreadListRuntimeCore.tsx +6 -1
- package/src/runtimes/index.ts +5 -4
- package/src/runtimes/local/LocalThreadListRuntimeCore.tsx +14 -9
- package/src/runtimes/remote-thread-list/BaseSubscribable.tsx +38 -0
- package/src/runtimes/remote-thread-list/EMPTY_THREAD_CORE.tsx +158 -0
- package/src/runtimes/remote-thread-list/OptimisticState.ts +82 -0
- package/src/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.tsx +132 -0
- package/src/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.tsx +486 -0
- package/src/runtimes/remote-thread-list/cloud/AssistantCloud.tsx +11 -0
- package/src/runtimes/remote-thread-list/cloud/AssistantCloudAPI.tsx +81 -0
- package/src/runtimes/remote-thread-list/cloud/AssistantCloudAuthStrategy.tsx +95 -0
- package/src/runtimes/remote-thread-list/cloud/AssistantCloudThreads.tsx +72 -0
- package/src/runtimes/remote-thread-list/cloud/CloudContext.tsx +12 -0
- package/src/runtimes/remote-thread-list/cloud/index.ts +3 -0
- package/src/runtimes/remote-thread-list/cloud/useCloudGetOrCreateThread.tsx +19 -0
- package/src/runtimes/remote-thread-list/cloud/useCloudThreadListRuntime.tsx +100 -0
- package/src/runtimes/remote-thread-list/index.ts +2 -0
- package/src/runtimes/remote-thread-list/types.tsx +34 -0
- package/src/runtimes/remote-thread-list/useRemoteThreadListRuntime.tsx +28 -0
- package/src/styles/tailwindcss/thread.css +5 -1
- package/src/ui/attachment-ui.tsx +20 -14
- package/src/utils/createActionButton.tsx +11 -6
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { ThreadListRuntimeCore } from "../core/ThreadListRuntimeCore";
|
|
2
|
+
import { generateId } from "../../internal";
|
|
3
|
+
import { RemoteThreadListAdapter } from "./types";
|
|
4
|
+
import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
|
|
5
|
+
import { BaseSubscribable } from "./BaseSubscribable";
|
|
6
|
+
import { EMPTY_THREAD_CORE } from "./EMPTY_THREAD_CORE";
|
|
7
|
+
import { OptimisticState } from "./OptimisticState";
|
|
8
|
+
import { FC, PropsWithChildren, useEffect, useId } from "react";
|
|
9
|
+
import { create } from "zustand";
|
|
10
|
+
import { CloudInitializeResponse } from "./cloud/CloudContext";
|
|
11
|
+
|
|
12
|
+
type RemoteThreadData =
|
|
13
|
+
| {
|
|
14
|
+
readonly threadId: string;
|
|
15
|
+
readonly remoteId?: undefined;
|
|
16
|
+
readonly externalId?: undefined;
|
|
17
|
+
readonly status: "new";
|
|
18
|
+
readonly title: undefined;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
readonly threadId: string;
|
|
22
|
+
readonly remoteId: string;
|
|
23
|
+
readonly externalId: string | undefined;
|
|
24
|
+
readonly status: "regular" | "archived";
|
|
25
|
+
readonly title?: string | undefined;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const DEFAULT_RENDER_COMPONENT: FC<PropsWithChildren> = ({ children }) => {
|
|
29
|
+
return children;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type THREAD_MAPPING_ID = string & { __brand: "THREAD_MAPPING_ID" };
|
|
33
|
+
function createThreadMappingId(id: string): THREAD_MAPPING_ID {
|
|
34
|
+
return id as THREAD_MAPPING_ID;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RemoteThreadState = {
|
|
38
|
+
readonly isLoading: boolean;
|
|
39
|
+
readonly newThreadId: string | undefined;
|
|
40
|
+
readonly threadIds: readonly string[];
|
|
41
|
+
readonly archivedThreadIds: readonly string[];
|
|
42
|
+
readonly threadIdMap: Readonly<Record<string, THREAD_MAPPING_ID>>;
|
|
43
|
+
readonly threadData: Readonly<Record<THREAD_MAPPING_ID, RemoteThreadData>>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getThreadData = (
|
|
47
|
+
state: RemoteThreadState,
|
|
48
|
+
threadIdOrRemoteId: string,
|
|
49
|
+
) => {
|
|
50
|
+
const idx = state.threadIdMap[threadIdOrRemoteId];
|
|
51
|
+
if (idx === undefined) return undefined;
|
|
52
|
+
return state.threadData[idx];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const updateStatusReducer = (
|
|
56
|
+
state: RemoteThreadState,
|
|
57
|
+
threadIdOrRemoteId: string,
|
|
58
|
+
newStatus: "regular" | "archived" | "deleted",
|
|
59
|
+
) => {
|
|
60
|
+
const data = getThreadData(state, threadIdOrRemoteId);
|
|
61
|
+
if (!data) return state;
|
|
62
|
+
|
|
63
|
+
const { threadId, remoteId, status: lastStatus } = data;
|
|
64
|
+
if (lastStatus === newStatus) return state;
|
|
65
|
+
|
|
66
|
+
const newState = { ...state };
|
|
67
|
+
|
|
68
|
+
// lastStatus
|
|
69
|
+
switch (lastStatus) {
|
|
70
|
+
case "new":
|
|
71
|
+
newState.newThreadId = undefined;
|
|
72
|
+
break;
|
|
73
|
+
case "regular":
|
|
74
|
+
newState.threadIds = newState.threadIds.filter((t) => t !== threadId);
|
|
75
|
+
break;
|
|
76
|
+
case "archived":
|
|
77
|
+
newState.archivedThreadIds = newState.archivedThreadIds.filter(
|
|
78
|
+
(t) => t !== threadId,
|
|
79
|
+
);
|
|
80
|
+
break;
|
|
81
|
+
|
|
82
|
+
default: {
|
|
83
|
+
const _exhaustiveCheck: never = lastStatus;
|
|
84
|
+
throw new Error(`Unsupported state: ${_exhaustiveCheck}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// newStatus
|
|
89
|
+
switch (newStatus) {
|
|
90
|
+
case "regular":
|
|
91
|
+
newState.threadIds = [...newState.threadIds, threadId];
|
|
92
|
+
break;
|
|
93
|
+
|
|
94
|
+
case "archived":
|
|
95
|
+
newState.archivedThreadIds = [...newState.archivedThreadIds, threadId];
|
|
96
|
+
break;
|
|
97
|
+
|
|
98
|
+
case "deleted":
|
|
99
|
+
newState.threadData = Object.fromEntries(
|
|
100
|
+
Object.entries(newState.threadData).filter(([key]) => key !== threadId),
|
|
101
|
+
);
|
|
102
|
+
newState.threadIdMap = Object.fromEntries(
|
|
103
|
+
Object.entries(newState.threadIdMap).filter(
|
|
104
|
+
([key]) => key !== threadId && key !== remoteId,
|
|
105
|
+
),
|
|
106
|
+
);
|
|
107
|
+
break;
|
|
108
|
+
|
|
109
|
+
default: {
|
|
110
|
+
const _exhaustiveCheck: never = newStatus;
|
|
111
|
+
throw new Error(`Unsupported state: ${_exhaustiveCheck}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (newStatus !== "deleted") {
|
|
116
|
+
newState.threadData = {
|
|
117
|
+
...newState.threadData,
|
|
118
|
+
[threadId]: {
|
|
119
|
+
...data,
|
|
120
|
+
status: newStatus,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return newState;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export class RemoteThreadListThreadListRuntimeCore
|
|
129
|
+
extends BaseSubscribable
|
|
130
|
+
implements ThreadListRuntimeCore
|
|
131
|
+
{
|
|
132
|
+
private _adapter!: RemoteThreadListAdapter;
|
|
133
|
+
private _disposeOldAdapter?: () => void;
|
|
134
|
+
private readonly _hookManager: RemoteThreadListHookInstanceManager;
|
|
135
|
+
|
|
136
|
+
private readonly _loadThreadsPromise: Promise<void>;
|
|
137
|
+
|
|
138
|
+
private _mainThreadId!: string;
|
|
139
|
+
private readonly _state = new OptimisticState<RemoteThreadState>({
|
|
140
|
+
isLoading: false,
|
|
141
|
+
newThreadId: undefined,
|
|
142
|
+
threadIds: [],
|
|
143
|
+
archivedThreadIds: [],
|
|
144
|
+
threadIdMap: {},
|
|
145
|
+
threadData: {},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
public getLoadThreadsPromise() {
|
|
149
|
+
return this._loadThreadsPromise;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
constructor(adapter: RemoteThreadListAdapter) {
|
|
153
|
+
super();
|
|
154
|
+
|
|
155
|
+
this._state.subscribe(() => this._notifySubscribers());
|
|
156
|
+
this._hookManager = new RemoteThreadListHookInstanceManager(
|
|
157
|
+
adapter.runtimeHook,
|
|
158
|
+
);
|
|
159
|
+
this.useRenderComponent = create(() => ({
|
|
160
|
+
RenderComponent:
|
|
161
|
+
adapter.__internal_RenderComponent ?? DEFAULT_RENDER_COMPONENT,
|
|
162
|
+
}));
|
|
163
|
+
this.__internal_setAdapter(adapter);
|
|
164
|
+
|
|
165
|
+
this._loadThreadsPromise = this._state
|
|
166
|
+
.optimisticUpdate({
|
|
167
|
+
execute: () => adapter.list(),
|
|
168
|
+
loading: (state) => {
|
|
169
|
+
return {
|
|
170
|
+
...state,
|
|
171
|
+
isLoading: true,
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
then: (state, l) => {
|
|
175
|
+
const newThreadIds = [];
|
|
176
|
+
const newArchivedThreadIds = [];
|
|
177
|
+
const newThreadIdMap = {} as Record<string, THREAD_MAPPING_ID>;
|
|
178
|
+
const newThreadData = {} as Record<
|
|
179
|
+
THREAD_MAPPING_ID,
|
|
180
|
+
RemoteThreadData
|
|
181
|
+
>;
|
|
182
|
+
|
|
183
|
+
for (const thread of l.threads) {
|
|
184
|
+
switch (thread.status) {
|
|
185
|
+
case "regular":
|
|
186
|
+
newThreadIds.push(thread.remoteId);
|
|
187
|
+
break;
|
|
188
|
+
case "archived":
|
|
189
|
+
newArchivedThreadIds.push(thread.remoteId);
|
|
190
|
+
break;
|
|
191
|
+
default: {
|
|
192
|
+
const _exhaustiveCheck: never = thread.status;
|
|
193
|
+
throw new Error(`Unsupported state: ${_exhaustiveCheck}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const mappingId = createThreadMappingId(thread.remoteId);
|
|
198
|
+
newThreadIdMap[thread.remoteId] = mappingId;
|
|
199
|
+
newThreadData[mappingId] = {
|
|
200
|
+
threadId: thread.remoteId,
|
|
201
|
+
remoteId: thread.remoteId,
|
|
202
|
+
externalId: thread.externalId,
|
|
203
|
+
status: thread.status,
|
|
204
|
+
title: thread.title,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
...state,
|
|
210
|
+
threadIds: newThreadIds,
|
|
211
|
+
archivedThreadIds: newArchivedThreadIds,
|
|
212
|
+
threadIdMap: {
|
|
213
|
+
...state.threadIdMap,
|
|
214
|
+
...newThreadIdMap,
|
|
215
|
+
},
|
|
216
|
+
threadData: {
|
|
217
|
+
...state.threadData,
|
|
218
|
+
...newThreadData,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
.then(() => {});
|
|
224
|
+
|
|
225
|
+
this.switchToNewThread();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private useRenderComponent;
|
|
229
|
+
|
|
230
|
+
public __internal_setAdapter(adapter: RemoteThreadListAdapter) {
|
|
231
|
+
if (this._adapter === adapter) return;
|
|
232
|
+
|
|
233
|
+
this._adapter = adapter;
|
|
234
|
+
this._disposeOldAdapter?.();
|
|
235
|
+
this._disposeOldAdapter = this._adapter.onInitialize(this._onInitialize);
|
|
236
|
+
|
|
237
|
+
const RenderComponent =
|
|
238
|
+
adapter.__internal_RenderComponent ?? DEFAULT_RENDER_COMPONENT;
|
|
239
|
+
if (
|
|
240
|
+
RenderComponent !== this.useRenderComponent.getState().RenderComponent
|
|
241
|
+
) {
|
|
242
|
+
this.useRenderComponent.setState({ RenderComponent }, true);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this._hookManager.setRuntimeHook(adapter.runtimeHook);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
public get threadIds() {
|
|
249
|
+
return this._state.value.threadIds;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public get archivedThreadIds() {
|
|
253
|
+
return this._state.value.archivedThreadIds;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public get newThreadId() {
|
|
257
|
+
return this._state.value.newThreadId;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public get mainThreadId(): string {
|
|
261
|
+
return this._mainThreadId;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public getMainThreadRuntimeCore() {
|
|
265
|
+
const result = this._hookManager.getThreadRuntimeCore(this._mainThreadId);
|
|
266
|
+
if (!result) return EMPTY_THREAD_CORE;
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public getItemById(threadIdOrRemoteId: string) {
|
|
271
|
+
return getThreadData(this._state.value, threadIdOrRemoteId);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public async switchToThread(threadIdOrRemoteId: string): Promise<void> {
|
|
275
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
276
|
+
if (!data) throw new Error("Thread not found");
|
|
277
|
+
|
|
278
|
+
if (this._mainThreadId === data.threadId) return;
|
|
279
|
+
|
|
280
|
+
const task = this._hookManager.startThreadRuntime(data.threadId);
|
|
281
|
+
if (this.mainThreadId !== undefined) {
|
|
282
|
+
await task;
|
|
283
|
+
} else {
|
|
284
|
+
task.then(() => this._notifySubscribers());
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (data.status === "archived") await this.unarchive(data.threadId);
|
|
288
|
+
this._mainThreadId = data.threadId;
|
|
289
|
+
|
|
290
|
+
this._notifySubscribers();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
public async switchToNewThread(): Promise<void> {
|
|
294
|
+
// an initialization transaction is in progress, wait for it to settle
|
|
295
|
+
while (
|
|
296
|
+
this._state.baseValue.newThreadId !== undefined &&
|
|
297
|
+
this._state.value.newThreadId === undefined
|
|
298
|
+
) {
|
|
299
|
+
await this._state.waitForUpdate();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const state = this._state.value;
|
|
303
|
+
let threadId: string | undefined = this._state.value.newThreadId;
|
|
304
|
+
if (threadId === undefined) {
|
|
305
|
+
do {
|
|
306
|
+
threadId = `__LOCALID_${generateId()}`;
|
|
307
|
+
} while (state.threadIdMap[threadId]);
|
|
308
|
+
|
|
309
|
+
const mappingId = createThreadMappingId(threadId);
|
|
310
|
+
this._state.update({
|
|
311
|
+
...state,
|
|
312
|
+
newThreadId: threadId,
|
|
313
|
+
threadIdMap: {
|
|
314
|
+
...state.threadIdMap,
|
|
315
|
+
[threadId]: mappingId,
|
|
316
|
+
},
|
|
317
|
+
threadData: {
|
|
318
|
+
...state.threadData,
|
|
319
|
+
[threadId]: {
|
|
320
|
+
status: "new",
|
|
321
|
+
threadId,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return this.switchToThread(threadId);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private _onInitialize = async (task: Promise<CloudInitializeResponse>) => {
|
|
331
|
+
const threadId = this._state.value.newThreadId;
|
|
332
|
+
if (!threadId)
|
|
333
|
+
throw new Error(
|
|
334
|
+
"ThreadListAdapter called onInitialize before switching to new thread",
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
await this._state.optimisticUpdate({
|
|
338
|
+
execute: () => {
|
|
339
|
+
return task;
|
|
340
|
+
},
|
|
341
|
+
optimistic: (state) => {
|
|
342
|
+
return updateStatusReducer(state, threadId, "regular");
|
|
343
|
+
},
|
|
344
|
+
then: (state, { remoteId, externalId }) => {
|
|
345
|
+
const data = getThreadData(state, threadId);
|
|
346
|
+
if (!data) return state;
|
|
347
|
+
|
|
348
|
+
const mappingId = createThreadMappingId(remoteId);
|
|
349
|
+
return {
|
|
350
|
+
...state,
|
|
351
|
+
threadIdMap: {
|
|
352
|
+
...state.threadIdMap,
|
|
353
|
+
[remoteId]: mappingId,
|
|
354
|
+
},
|
|
355
|
+
threadData: {
|
|
356
|
+
...state.threadData,
|
|
357
|
+
[threadId]: {
|
|
358
|
+
...data,
|
|
359
|
+
remoteId,
|
|
360
|
+
externalId,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
public rename(threadIdOrRemoteId: string, newTitle: string): Promise<void> {
|
|
369
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
370
|
+
if (!data) throw new Error("Thread not found");
|
|
371
|
+
if (data.status === "new") throw new Error("Thread is not yet initialized");
|
|
372
|
+
|
|
373
|
+
return this._state.optimisticUpdate({
|
|
374
|
+
execute: () => {
|
|
375
|
+
return this._adapter.rename(data.remoteId, newTitle);
|
|
376
|
+
},
|
|
377
|
+
optimistic: (state) => {
|
|
378
|
+
const data = getThreadData(state, threadIdOrRemoteId);
|
|
379
|
+
if (!data) return state;
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
...state,
|
|
383
|
+
threadData: {
|
|
384
|
+
...state.threadData,
|
|
385
|
+
[data.threadId]: {
|
|
386
|
+
...data,
|
|
387
|
+
title: newTitle,
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private async _ensureThreadIsNotMain(threadId: string) {
|
|
396
|
+
// if thread is main thread, switch to another thread
|
|
397
|
+
if (threadId === this._mainThreadId) {
|
|
398
|
+
const lastThreadId = this._state.value.threadIds[0];
|
|
399
|
+
if (lastThreadId) {
|
|
400
|
+
await this.switchToThread(lastThreadId);
|
|
401
|
+
} else {
|
|
402
|
+
await this.switchToNewThread();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
public async archive(threadIdOrRemoteId: string) {
|
|
408
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
409
|
+
if (!data) throw new Error("Thread not found");
|
|
410
|
+
if (data.status !== "regular")
|
|
411
|
+
throw new Error("Thread is not yet initialized or already archived");
|
|
412
|
+
|
|
413
|
+
return this._state.optimisticUpdate({
|
|
414
|
+
execute: async () => {
|
|
415
|
+
await this._ensureThreadIsNotMain(data.threadId);
|
|
416
|
+
return this._adapter.archive(data.remoteId);
|
|
417
|
+
},
|
|
418
|
+
optimistic: (state) => {
|
|
419
|
+
return updateStatusReducer(state, data.threadId, "archived");
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
public unarchive(threadIdOrRemoteId: string): Promise<void> {
|
|
425
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
426
|
+
if (!data) throw new Error("Thread not found");
|
|
427
|
+
if (data.status !== "archived") throw new Error("Thread is not archived");
|
|
428
|
+
|
|
429
|
+
return this._state.optimisticUpdate({
|
|
430
|
+
execute: async () => {
|
|
431
|
+
try {
|
|
432
|
+
return await this._adapter.unarchive(data.remoteId);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
await this._ensureThreadIsNotMain(data.threadId);
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
optimistic: (state) => {
|
|
439
|
+
return updateStatusReducer(state, data.threadId, "regular");
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
public async delete(threadIdOrRemoteId: string) {
|
|
445
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
446
|
+
if (!data) throw new Error("Thread not found");
|
|
447
|
+
if (data.status !== "regular" && data.status !== "archived")
|
|
448
|
+
throw new Error("Thread is not yet initialized");
|
|
449
|
+
|
|
450
|
+
return this._state.optimisticUpdate({
|
|
451
|
+
execute: async () => {
|
|
452
|
+
await this._ensureThreadIsNotMain(data.threadId);
|
|
453
|
+
return await this._adapter.delete(data.remoteId);
|
|
454
|
+
},
|
|
455
|
+
optimistic: (state) => {
|
|
456
|
+
return updateStatusReducer(state, data.threadId, "deleted");
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private useBoundIds = create<string[]>(() => []);
|
|
462
|
+
|
|
463
|
+
public __internal_RenderComponent: FC<PropsWithChildren> = ({ children }) => {
|
|
464
|
+
const id = useId();
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
this.useBoundIds.setState((s) => [...s, id], true);
|
|
467
|
+
return () => {
|
|
468
|
+
this.useBoundIds.setState((s) => s.filter((i) => i !== id), true);
|
|
469
|
+
};
|
|
470
|
+
}, []);
|
|
471
|
+
|
|
472
|
+
const boundIds = this.useBoundIds();
|
|
473
|
+
const { RenderComponent } = this.useRenderComponent();
|
|
474
|
+
|
|
475
|
+
return (
|
|
476
|
+
<RenderComponent>
|
|
477
|
+
{(boundIds.length === 0 || boundIds[0] === id) && (
|
|
478
|
+
// only render if the component is the first one mounted
|
|
479
|
+
<this._hookManager.__internal_RenderThreadRuntimes />
|
|
480
|
+
)}
|
|
481
|
+
|
|
482
|
+
{children}
|
|
483
|
+
</RenderComponent>
|
|
484
|
+
);
|
|
485
|
+
};
|
|
486
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AssistantCloudAPI, AssistantCloudConfig } from "./AssistantCloudAPI";
|
|
2
|
+
import { AssistantCloudThreads } from "./AssistantCloudThreads";
|
|
3
|
+
|
|
4
|
+
export class AssistantCloud {
|
|
5
|
+
public readonly threads;
|
|
6
|
+
|
|
7
|
+
constructor(config: AssistantCloudConfig) {
|
|
8
|
+
const api = new AssistantCloudAPI(config);
|
|
9
|
+
this.threads = new AssistantCloudThreads(api);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssistantCloudAuthStrategy,
|
|
3
|
+
AssistantCloudJWTAuthStrategy,
|
|
4
|
+
AssistantCloudAPIKeyAuthStrategy,
|
|
5
|
+
} from "./AssistantCloudAuthStrategy";
|
|
6
|
+
|
|
7
|
+
export type AssistantCloudConfig =
|
|
8
|
+
| {
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
// TODO use baseUrl to construct the projectId
|
|
11
|
+
unstable_projectId: string;
|
|
12
|
+
authToken(): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
apiKey: string;
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class AssistantCloudAPI {
|
|
20
|
+
private _tokenManager: AssistantCloudAuthStrategy;
|
|
21
|
+
private _baseUrl;
|
|
22
|
+
|
|
23
|
+
constructor(config: AssistantCloudConfig) {
|
|
24
|
+
if ("authToken" in config) {
|
|
25
|
+
this._baseUrl = config.baseUrl;
|
|
26
|
+
this._tokenManager = new AssistantCloudJWTAuthStrategy(
|
|
27
|
+
config.unstable_projectId,
|
|
28
|
+
config.authToken,
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
this._baseUrl = "https://api.assistant-ui.com";
|
|
32
|
+
this._tokenManager = new AssistantCloudAPIKeyAuthStrategy(
|
|
33
|
+
config.apiKey,
|
|
34
|
+
config.workspaceId,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public async makeRequest(
|
|
40
|
+
endpoint: string,
|
|
41
|
+
options: {
|
|
42
|
+
method?: "POST" | "PUT" | "DELETE" | undefined;
|
|
43
|
+
query?: Record<string, string | number | boolean> | undefined;
|
|
44
|
+
body?: object | undefined;
|
|
45
|
+
} = {},
|
|
46
|
+
) {
|
|
47
|
+
const authHeaders = await this._tokenManager.getAuthHeaders();
|
|
48
|
+
const headers = {
|
|
49
|
+
...authHeaders,
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const queryParams = new URLSearchParams();
|
|
54
|
+
if (options.query) {
|
|
55
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
56
|
+
if (value === false) continue;
|
|
57
|
+
if (value === true) {
|
|
58
|
+
queryParams.set(key, "true");
|
|
59
|
+
} else {
|
|
60
|
+
queryParams.set(key, value.toString());
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const url = new URL(`${this._baseUrl}${endpoint}`);
|
|
66
|
+
url.search = queryParams.toString();
|
|
67
|
+
|
|
68
|
+
const response = await fetch(url, {
|
|
69
|
+
method: options.method ?? "GET",
|
|
70
|
+
headers,
|
|
71
|
+
body: options.body ? JSON.stringify(options.body) : null,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
// TODO better error handling
|
|
76
|
+
throw new Error(`Request failed with status ${response.status}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return response.json();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export type AssistantCloudAuthStrategy = {
|
|
2
|
+
readonly strategy: "jwt" | "api-key";
|
|
3
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export class AssistantCloudJWTAuthStrategy
|
|
7
|
+
implements AssistantCloudAuthStrategy
|
|
8
|
+
{
|
|
9
|
+
public readonly strategy = "jwt";
|
|
10
|
+
|
|
11
|
+
private cachedToken: string | null = null;
|
|
12
|
+
private tokenExpiry: number | null = null;
|
|
13
|
+
|
|
14
|
+
#projectId;
|
|
15
|
+
#authTokenCallback;
|
|
16
|
+
|
|
17
|
+
constructor(projectId: string, authTokenCallback: () => Promise<string>) {
|
|
18
|
+
this.#projectId = projectId;
|
|
19
|
+
this.#authTokenCallback = authTokenCallback;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private getJwtExpiry(jwt: string): number {
|
|
23
|
+
try {
|
|
24
|
+
const bodyPart = jwt.split(".").at(1);
|
|
25
|
+
if (!bodyPart) {
|
|
26
|
+
throw new Error("Invalid JWT format");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Base64Url decode
|
|
30
|
+
const payload = Buffer.from(
|
|
31
|
+
bodyPart.replace(/-/g, "+").replace(/_/g, "/"),
|
|
32
|
+
"base64",
|
|
33
|
+
).toString();
|
|
34
|
+
const payloadObj = JSON.parse(payload);
|
|
35
|
+
|
|
36
|
+
const exp = payloadObj.exp;
|
|
37
|
+
if (!exp || typeof exp !== "number") {
|
|
38
|
+
throw new Error('JWT does not contain a valid "exp" field');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Convert exp to milliseconds
|
|
42
|
+
return exp * 1000;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error("Unable to determine the token expiry " + error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async getAuthHeaders(): Promise<Record<string, string>> {
|
|
49
|
+
const currentTime = Date.now();
|
|
50
|
+
|
|
51
|
+
// Check if the cached token is valid for at least 30 seconds
|
|
52
|
+
if (
|
|
53
|
+
this.cachedToken &&
|
|
54
|
+
this.tokenExpiry &&
|
|
55
|
+
this.tokenExpiry - currentTime > 30 * 1000 // 30 seconds
|
|
56
|
+
) {
|
|
57
|
+
return {
|
|
58
|
+
Authorization: `Bearer ${this.cachedToken}`,
|
|
59
|
+
"Aui-Project-Id": this.#projectId,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Fetch a new token
|
|
64
|
+
const newToken = await this.#authTokenCallback();
|
|
65
|
+
const expiry = this.getJwtExpiry(newToken);
|
|
66
|
+
|
|
67
|
+
this.cachedToken = newToken;
|
|
68
|
+
this.tokenExpiry = expiry;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
Authorization: `Bearer ${newToken}`,
|
|
72
|
+
"Aui-Project-Id": this.#projectId,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export class AssistantCloudAPIKeyAuthStrategy
|
|
77
|
+
implements AssistantCloudAuthStrategy
|
|
78
|
+
{
|
|
79
|
+
public readonly strategy = "api-key";
|
|
80
|
+
|
|
81
|
+
#apiKey;
|
|
82
|
+
#workspaceId;
|
|
83
|
+
|
|
84
|
+
constructor(apiKey: string, workspaceId: string) {
|
|
85
|
+
this.#apiKey = apiKey;
|
|
86
|
+
this.#workspaceId = workspaceId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public async getAuthHeaders(): Promise<Record<string, string>> {
|
|
90
|
+
return {
|
|
91
|
+
Authorization: `Bearer ${this.#apiKey}`,
|
|
92
|
+
"Aui-Workspace-Id": this.#workspaceId,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|