@assistant-ui/core 0.2.22 → 0.2.23
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/adapters/thread-history.d.ts +8 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.js +3 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +36 -21
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +13 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -0
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/interactable-model-context.js +1 -0
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/react/interactables-legacy/useInteractableState.js +1 -0
- package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
- package/dist/react/model-context/useInteractableState.js +1 -0
- package/dist/react/model-context/useInteractableState.js.map +1 -1
- package/dist/react/model-context/useInteractableVersions.js +1 -0
- package/dist/react/model-context/useInteractableVersions.js.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +1 -0
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js +1 -0
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.js +1 -0
- package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarFeedback.js +1 -0
- package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.js +1 -0
- package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarSpeak.js +1 -0
- package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +1 -0
- package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.js +1 -0
- package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js +1 -0
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerAddAttachment.js +1 -0
- package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.js +1 -0
- package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerDictate.js +1 -0
- package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.js +1 -0
- package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerCancel.js +1 -0
- package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerSend.js +1 -0
- package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageBranching.js +1 -0
- package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageReload.js +1 -0
- package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.js +1 -0
- package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemArchive.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemDelete.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemTrigger.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.js +1 -0
- package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListNew.js +1 -0
- package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
- package/dist/react/providers/TextMessagePartProvider.js +1 -0
- package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +6 -4
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +11 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +2 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +1 -1
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
- package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.d.ts +0 -1
- package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
- package/dist/runtime/api/assistant-runtime.js +1 -1
- package/dist/runtime/api/assistant-runtime.js.map +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.js +1 -1
- package/dist/runtime/api/attachment-runtime.js.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +2 -2
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js +2 -2
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +4 -4
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.js +3 -3
- package/dist/runtime/api/message-part-runtime.js.map +1 -1
- package/dist/runtime/api/message-runtime.d.ts +1 -1
- package/dist/runtime/api/message-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-runtime.js +2 -2
- package/dist/runtime/api/message-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -2
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +1 -1
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +2 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +4 -2
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +2 -1
- package/dist/runtimes/internal.js +2 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +44 -13
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/no-op-composer-client.js +1 -0
- package/dist/store/clients/no-op-composer-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scopes/thread.d.ts +1 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +3 -3
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +3 -3
- package/dist/subscribable/subscribable.js.map +1 -1
- package/package.json +7 -7
- package/src/adapters/thread-history.ts +8 -0
- package/src/internal.ts +1 -1
- package/src/model-context/frame/host.test.ts +47 -0
- package/src/model-context/frame/host.ts +46 -19
- package/src/model-context/types.ts +16 -6
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +15 -5
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +20 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +26 -5
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +5 -1
- package/src/react/runtimes/cloud/auiV0.ts +14 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
- package/src/react/runtimes/external-message-converter.test.ts +346 -0
- package/src/react/runtimes/external-message-converter.ts +1 -1
- package/src/react/runtimes/useLocalRuntime.test.tsx +43 -0
- package/src/runtime/api/assistant-runtime.ts +4 -1
- package/src/runtime/api/attachment-runtime.ts +8 -2
- package/src/runtime/api/composer-runtime.ts +9 -5
- package/src/runtime/api/message-part-runtime.ts +10 -3
- package/src/runtime/api/message-runtime.ts +7 -2
- package/src/runtime/api/thread-list-item-runtime.ts +7 -2
- package/src/runtime/api/thread-list-runtime.ts +10 -2
- package/src/runtime/base/base-thread-runtime-core.ts +5 -1
- package/src/runtime/base/default-edit-composer-runtime-core.ts +14 -2
- package/src/runtime/base/default-thread-composer-runtime-core.ts +11 -1
- package/src/runtime/utils/message-repository.ts +19 -13
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
- package/src/runtimes/internal.ts +3 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +596 -0
- package/src/runtimes/local/local-thread-runtime-core.ts +85 -21
- package/src/runtimes/local/should-continue.test.ts +122 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +9 -10
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +38 -32
- package/src/store/clients/model-context-client.test.ts +21 -1
- package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
- package/src/store/scopes/thread.ts +1 -0
- package/src/subscribable/subscribable.ts +16 -8
- package/src/tests/MessageRepository.test.ts +12 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
- package/src/tests/auiV0Encode.test.ts +74 -0
- package/src/tests/base-composer-runtime-core.test.ts +422 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
- package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
- package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { OptimisticState } from "../runtimes/remote-thread-list/optimistic-state";
|
|
3
|
-
import {
|
|
4
|
-
type RemoteThreadState,
|
|
5
|
-
createThreadMappingId,
|
|
6
|
-
updateStatusReducer,
|
|
7
|
-
getThreadData,
|
|
8
|
-
} from "../runtimes/remote-thread-list/remote-thread-state";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* This test reproduces the crash from issue #3346:
|
|
12
|
-
* "Entry not available in the store" when deleting the active thread.
|
|
13
|
-
*
|
|
14
|
-
* Root cause: optimisticUpdate's `optimistic` callback runs synchronously
|
|
15
|
-
* and removes the thread from threadData, but mainThreadId still points to
|
|
16
|
-
* the deleted thread. Subscribers that fire during _notifySubscribers() see
|
|
17
|
-
* this inconsistent state and crash.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const createThreadState = (
|
|
21
|
-
threadId: string,
|
|
22
|
-
status: "regular" | "archived" = "regular",
|
|
23
|
-
): RemoteThreadState => {
|
|
24
|
-
const mappingId = createThreadMappingId(threadId);
|
|
25
|
-
return {
|
|
26
|
-
isLoading: false,
|
|
27
|
-
isLoadingMore: false,
|
|
28
|
-
cursor: undefined,
|
|
29
|
-
newThreadId: undefined,
|
|
30
|
-
threadIds: status === "regular" ? [threadId] : [],
|
|
31
|
-
archivedThreadIds: status === "archived" ? [threadId] : [],
|
|
32
|
-
threadIdMap: { [threadId]: mappingId },
|
|
33
|
-
threadData: {
|
|
34
|
-
[mappingId]: {
|
|
35
|
-
id: threadId,
|
|
36
|
-
remoteId: threadId,
|
|
37
|
-
externalId: undefined,
|
|
38
|
-
status,
|
|
39
|
-
title: undefined,
|
|
40
|
-
initializeTask: Promise.resolve({
|
|
41
|
-
remoteId: threadId,
|
|
42
|
-
externalId: undefined,
|
|
43
|
-
}),
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
describe("OptimisticState delete crash (#3346)", () => {
|
|
50
|
-
it("optimistic callback runs synchronously before execute completes", async () => {
|
|
51
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
52
|
-
const events: string[] = [];
|
|
53
|
-
|
|
54
|
-
state.subscribe(() => {
|
|
55
|
-
events.push("subscriber-notified");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const executeStarted = vi.fn();
|
|
59
|
-
const executeCompleted = vi.fn();
|
|
60
|
-
|
|
61
|
-
const promise = state.optimisticUpdate({
|
|
62
|
-
execute: async () => {
|
|
63
|
-
executeStarted();
|
|
64
|
-
// simulate async work like _ensureThreadIsNotMain
|
|
65
|
-
await Promise.resolve();
|
|
66
|
-
executeCompleted();
|
|
67
|
-
},
|
|
68
|
-
optimistic: (s) => {
|
|
69
|
-
events.push("optimistic-ran");
|
|
70
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// After calling optimisticUpdate but before awaiting:
|
|
75
|
-
// - optimistic callback has already run (synchronous)
|
|
76
|
-
// - execute has started but not completed (async)
|
|
77
|
-
expect(events).toEqual(["optimistic-ran", "subscriber-notified"]);
|
|
78
|
-
expect(executeStarted).toHaveBeenCalled();
|
|
79
|
-
expect(executeCompleted).not.toHaveBeenCalled();
|
|
80
|
-
|
|
81
|
-
// Thread data is already gone from the optimistic value
|
|
82
|
-
expect(getThreadData(state.value, "thread-1")).toBeUndefined();
|
|
83
|
-
|
|
84
|
-
await promise;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("BUG SCENARIO: subscriber sees deleted thread data while mainThreadId still references it", async () => {
|
|
88
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
89
|
-
|
|
90
|
-
// Simulate what happens in the real code:
|
|
91
|
-
// mainThreadId is external state that _ensureThreadIsNotMain would update
|
|
92
|
-
let mainThreadId = "thread-1";
|
|
93
|
-
let subscriberSawInconsistentState = false;
|
|
94
|
-
|
|
95
|
-
state.subscribe(() => {
|
|
96
|
-
// This fires synchronously during optimisticUpdate.
|
|
97
|
-
// In the real code, React components would re-render here and try to
|
|
98
|
-
// access the main thread's data.
|
|
99
|
-
const threadData = getThreadData(state.value, mainThreadId);
|
|
100
|
-
if (threadData === undefined && mainThreadId === "thread-1") {
|
|
101
|
-
// mainThreadId points to a deleted thread — this is the crash condition
|
|
102
|
-
subscriberSawInconsistentState = true;
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// OLD CODE: _ensureThreadIsNotMain inside execute
|
|
107
|
-
// The optimistic callback deletes thread data BEFORE execute can update mainThreadId
|
|
108
|
-
const promise = state.optimisticUpdate({
|
|
109
|
-
execute: async () => {
|
|
110
|
-
// In old code, _ensureThreadIsNotMain was here.
|
|
111
|
-
// It would switch mainThreadId, but this runs AFTER optimistic callback
|
|
112
|
-
await Promise.resolve();
|
|
113
|
-
mainThreadId = "thread-2"; // too late — subscriber already fired
|
|
114
|
-
},
|
|
115
|
-
optimistic: (s) => {
|
|
116
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// The subscriber saw inconsistent state — mainThreadId points to deleted thread
|
|
121
|
-
expect(subscriberSawInconsistentState).toBe(true);
|
|
122
|
-
|
|
123
|
-
await promise;
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("FIX: switching mainThreadId before optimisticUpdate prevents inconsistency", async () => {
|
|
127
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
128
|
-
|
|
129
|
-
let mainThreadId = "thread-1";
|
|
130
|
-
let subscriberSawInconsistentState = false;
|
|
131
|
-
|
|
132
|
-
state.subscribe(() => {
|
|
133
|
-
const threadData = getThreadData(state.value, mainThreadId);
|
|
134
|
-
if (threadData === undefined) {
|
|
135
|
-
subscriberSawInconsistentState = true;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// FIX: _ensureThreadIsNotMain runs BEFORE optimisticUpdate.
|
|
140
|
-
// switchToNewThread() both creates the new thread in state AND updates mainThreadId.
|
|
141
|
-
const newThreadId = "thread-2";
|
|
142
|
-
const mappingId = createThreadMappingId(newThreadId);
|
|
143
|
-
const currentState = state.value;
|
|
144
|
-
state.update({
|
|
145
|
-
...currentState,
|
|
146
|
-
newThreadId: newThreadId,
|
|
147
|
-
threadIdMap: {
|
|
148
|
-
...currentState.threadIdMap,
|
|
149
|
-
[newThreadId]: mappingId,
|
|
150
|
-
},
|
|
151
|
-
threadData: {
|
|
152
|
-
...currentState.threadData,
|
|
153
|
-
[mappingId]: {
|
|
154
|
-
status: "new" as const,
|
|
155
|
-
id: newThreadId,
|
|
156
|
-
remoteId: undefined,
|
|
157
|
-
externalId: undefined,
|
|
158
|
-
title: undefined,
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
mainThreadId = newThreadId;
|
|
163
|
-
|
|
164
|
-
// Reset flag — the state.update above triggered the subscriber
|
|
165
|
-
subscriberSawInconsistentState = false;
|
|
166
|
-
|
|
167
|
-
const promise = state.optimisticUpdate({
|
|
168
|
-
execute: async () => {
|
|
169
|
-
// _ensureThreadIsNotMain no longer here
|
|
170
|
-
return undefined;
|
|
171
|
-
},
|
|
172
|
-
optimistic: (s) => {
|
|
173
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// mainThreadId was already switched to thread-2 which exists in state
|
|
178
|
-
// — subscriber sees consistent state, no crash
|
|
179
|
-
expect(subscriberSawInconsistentState).toBe(false);
|
|
180
|
-
|
|
181
|
-
await promise;
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("archive does NOT remove threadData (no crash even without fix)", async () => {
|
|
185
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
186
|
-
|
|
187
|
-
let threadDataMissingDuringNotify = false;
|
|
188
|
-
|
|
189
|
-
state.subscribe(() => {
|
|
190
|
-
const threadData = getThreadData(state.value, "thread-1");
|
|
191
|
-
if (threadData === undefined) {
|
|
192
|
-
threadDataMissingDuringNotify = true;
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
await state.optimisticUpdate({
|
|
197
|
-
execute: async () => undefined,
|
|
198
|
-
optimistic: (s) => {
|
|
199
|
-
return updateStatusReducer(s, "thread-1", "archived");
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Archive keeps threadData — no SKIP_UPDATE, no crash
|
|
204
|
-
expect(threadDataMissingDuringNotify).toBe(false);
|
|
205
|
-
expect(getThreadData(state.value, "thread-1")).toBeDefined();
|
|
206
|
-
expect(getThreadData(state.value, "thread-1")?.status).toBe("archived");
|
|
207
|
-
});
|
|
208
|
-
});
|