@assistant-ui/react 0.11.48 → 0.11.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/client/AssistantClient.d.ts.map +1 -1
  2. package/dist/client/AssistantClient.js +1 -2
  3. package/dist/client/AssistantClient.js.map +1 -1
  4. package/dist/client/ModelContextClient.d.ts +1 -1
  5. package/dist/client/ThreadMessageClient.d.ts.map +1 -1
  6. package/dist/client/ThreadMessageClient.js +8 -9
  7. package/dist/client/ThreadMessageClient.js.map +1 -1
  8. package/dist/client/util-hooks/tapLookupResources.d.ts +2 -2
  9. package/dist/client/util-hooks/tapLookupResources.d.ts.map +1 -1
  10. package/dist/client/util-hooks/tapLookupResources.js +13 -4
  11. package/dist/client/util-hooks/tapLookupResources.js.map +1 -1
  12. package/dist/context/providers/MessageProvider.d.ts.map +1 -1
  13. package/dist/context/providers/MessageProvider.js +1 -2
  14. package/dist/context/providers/MessageProvider.js.map +1 -1
  15. package/dist/context/providers/TextMessagePartProvider.d.ts.map +1 -1
  16. package/dist/context/providers/TextMessagePartProvider.js +1 -2
  17. package/dist/context/providers/TextMessagePartProvider.js.map +1 -1
  18. package/dist/context/react/AssistantApiContext.d.ts +1 -2
  19. package/dist/context/react/AssistantApiContext.d.ts.map +1 -1
  20. package/dist/context/react/AssistantApiContext.js +1 -12
  21. package/dist/context/react/AssistantApiContext.js.map +1 -1
  22. package/dist/legacy-runtime/client/ComposerRuntimeClient.d.ts.map +1 -1
  23. package/dist/legacy-runtime/client/ComposerRuntimeClient.js +4 -6
  24. package/dist/legacy-runtime/client/ComposerRuntimeClient.js.map +1 -1
  25. package/dist/legacy-runtime/client/EventManagerRuntimeClient.d.ts +1 -1
  26. package/dist/legacy-runtime/client/MessageRuntimeClient.d.ts.map +1 -1
  27. package/dist/legacy-runtime/client/MessageRuntimeClient.js +8 -6
  28. package/dist/legacy-runtime/client/MessageRuntimeClient.js.map +1 -1
  29. package/dist/legacy-runtime/client/ThreadListRuntimeClient.d.ts.map +1 -1
  30. package/dist/legacy-runtime/client/ThreadListRuntimeClient.js +4 -3
  31. package/dist/legacy-runtime/client/ThreadListRuntimeClient.js.map +1 -1
  32. package/dist/legacy-runtime/client/ThreadRuntimeClient.d.ts.map +1 -1
  33. package/dist/legacy-runtime/client/ThreadRuntimeClient.js +4 -6
  34. package/dist/legacy-runtime/client/ThreadRuntimeClient.js.map +1 -1
  35. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +1 -1
  36. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  37. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts +1 -4
  38. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts.map +1 -1
  39. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js +34 -12
  40. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js.map +1 -1
  41. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  42. package/dist/primitives/composer/ComposerInput.js +4 -2
  43. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  44. package/dist/primitives/thread/ThreadViewport.d.ts +36 -0
  45. package/dist/primitives/thread/ThreadViewport.d.ts.map +1 -1
  46. package/dist/primitives/thread/ThreadViewport.js +21 -12
  47. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  48. package/dist/primitives/thread/ThreadViewportSlack.d.ts.map +1 -1
  49. package/dist/primitives/thread/ThreadViewportSlack.js +4 -1
  50. package/dist/primitives/thread/ThreadViewportSlack.js.map +1 -1
  51. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts +20 -2
  52. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  53. package/dist/primitives/thread/useThreadViewportAutoScroll.js +21 -2
  54. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  55. package/dist/tests/setup.js +7 -7
  56. package/dist/tests/setup.js.map +1 -1
  57. package/dist/utils/tap-store/derived-scopes.d.ts +3 -10
  58. package/dist/utils/tap-store/derived-scopes.d.ts.map +1 -1
  59. package/dist/utils/tap-store/derived-scopes.js +14 -20
  60. package/dist/utils/tap-store/derived-scopes.js.map +1 -1
  61. package/dist/utils/tap-store/index.d.ts +1 -1
  62. package/dist/utils/tap-store/index.d.ts.map +1 -1
  63. package/dist/utils/tap-store/index.js.map +1 -1
  64. package/dist/utils/tap-store/store.d.ts +1 -7
  65. package/dist/utils/tap-store/store.d.ts.map +1 -1
  66. package/dist/utils/tap-store/store.js +2 -2
  67. package/dist/utils/tap-store/store.js.map +1 -1
  68. package/dist/utils/tap-store/tap-api.d.ts.map +1 -1
  69. package/dist/utils/tap-store/tap-api.js +13 -7
  70. package/dist/utils/tap-store/tap-api.js.map +1 -1
  71. package/package.json +5 -5
  72. package/src/client/AssistantClient.ts +0 -1
  73. package/src/client/ThreadMessageClient.tsx +10 -9
  74. package/src/client/util-hooks/tapLookupResources.ts +26 -11
  75. package/src/context/providers/MessageProvider.tsx +0 -1
  76. package/src/context/providers/TextMessagePartProvider.tsx +0 -1
  77. package/src/context/react/AssistantApiContext.tsx +1 -18
  78. package/src/legacy-runtime/client/ComposerRuntimeClient.ts +4 -6
  79. package/src/legacy-runtime/client/MessageRuntimeClient.ts +10 -6
  80. package/src/legacy-runtime/client/ThreadListRuntimeClient.ts +4 -3
  81. package/src/legacy-runtime/client/ThreadRuntimeClient.ts +4 -6
  82. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.tsx +1 -1
  83. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +40 -17
  84. package/src/primitives/composer/ComposerInput.tsx +4 -2
  85. package/src/primitives/thread/ThreadViewport.tsx +49 -18
  86. package/src/primitives/thread/ThreadViewportSlack.tsx +4 -1
  87. package/src/primitives/thread/useThreadViewportAutoScroll.tsx +48 -2
  88. package/src/utils/tap-store/derived-scopes.ts +17 -28
  89. package/src/utils/tap-store/index.ts +1 -2
  90. package/src/utils/tap-store/store.ts +2 -7
  91. package/src/utils/tap-store/tap-api.ts +12 -7
@@ -39,8 +39,7 @@ type UseToolInvocationsParams = {
39
39
 
40
40
  export type ToolExecutionStatus =
41
41
  | { type: "executing" }
42
- | { type: "interrupt"; payload: { type: "human"; payload: unknown } }
43
- | { type: "cancelled"; reason: string };
42
+ | { type: "interrupt"; payload: { type: "human"; payload: unknown } };
44
43
 
45
44
  export function useToolInvocations({
46
45
  state,
@@ -71,6 +70,9 @@ export function useToolInvocations({
71
70
  >(new Map());
72
71
 
73
72
  const acRef = useRef<AbortController>(new AbortController());
73
+ const executingCountRef = useRef(0);
74
+ const settledResolversRef = useRef<Array<() => void>>([]);
75
+
74
76
  const [controller] = useState(() => {
75
77
  const [stream, controller] = createAssistantStreamController();
76
78
  const transform = unstable_toolResultStream(
@@ -96,6 +98,28 @@ export function useToolInvocations({
96
98
  }));
97
99
  });
98
100
  },
101
+ {
102
+ onExecutionStart: (toolCallId: string) => {
103
+ executingCountRef.current++;
104
+ setToolStatuses((prev) => ({
105
+ ...prev,
106
+ [toolCallId]: { type: "executing" },
107
+ }));
108
+ },
109
+ onExecutionEnd: (toolCallId: string) => {
110
+ executingCountRef.current--;
111
+ setToolStatuses((prev) => {
112
+ const next = { ...prev };
113
+ delete next[toolCallId];
114
+ return next;
115
+ });
116
+ // Resolve any waiting abort promises when all tools have settled
117
+ if (executingCountRef.current === 0) {
118
+ settledResolversRef.current.forEach((resolve) => resolve());
119
+ settledResolversRef.current = [];
120
+ }
121
+ },
122
+ },
99
123
  );
100
124
  stream
101
125
  .pipeThrough(transform)
@@ -116,13 +140,6 @@ export function useToolInvocations({
116
140
  isError: chunk.isError,
117
141
  ...(chunk.artifact && { artifact: chunk.artifact }),
118
142
  });
119
-
120
- // Clear status when result is set
121
- setToolStatuses((prev) => {
122
- const next = { ...prev };
123
- delete next[chunk.meta.toolCallId];
124
- return next;
125
- });
126
143
  }
127
144
  },
128
145
  }),
@@ -234,20 +251,27 @@ export function useToolInvocations({
234
251
  }
235
252
  }, [state, controller, onResult]);
236
253
 
237
- const abort = () => {
254
+ const abort = (): Promise<void> => {
238
255
  humanInputRef.current.forEach(({ reject }) => {
239
256
  reject(new Error("Tool execution aborted"));
240
257
  });
241
258
  humanInputRef.current.clear();
242
- setToolStatuses({});
243
259
 
244
260
  acRef.current.abort();
245
261
  acRef.current = new AbortController();
262
+
263
+ // Return a promise that resolves when all executing tools have settled
264
+ if (executingCountRef.current === 0) {
265
+ return Promise.resolve();
266
+ }
267
+ return new Promise<void>((resolve) => {
268
+ settledResolversRef.current.push(resolve);
269
+ });
246
270
  };
247
271
 
248
272
  return {
249
273
  reset: () => {
250
- abort();
274
+ void abort();
251
275
  isInitialState.current = true;
252
276
  },
253
277
  abort,
@@ -255,11 +279,10 @@ export function useToolInvocations({
255
279
  const handlers = humanInputRef.current.get(toolCallId);
256
280
  if (handlers) {
257
281
  humanInputRef.current.delete(toolCallId);
258
- setToolStatuses((prev) => {
259
- const next = { ...prev };
260
- delete next[toolCallId];
261
- return next;
262
- });
282
+ setToolStatuses((prev) => ({
283
+ ...prev,
284
+ [toolCallId]: { type: "executing" },
285
+ }));
263
286
  handlers.resolve(payload);
264
287
  } else {
265
288
  throw new Error(
@@ -17,6 +17,7 @@ import TextareaAutosize, {
17
17
  import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown";
18
18
  import { useOnScrollToBottom } from "../../utils/hooks/useOnScrollToBottom";
19
19
  import { useAssistantState, useAssistantApi } from "../../context";
20
+ import { flushSync } from "@assistant-ui/tap";
20
21
 
21
22
  export namespace ComposerPrimitiveInput {
22
23
  export type Element = HTMLTextAreaElement;
@@ -207,8 +208,9 @@ export const ComposerPrimitiveInput = forwardRef<
207
208
  disabled={isDisabled}
208
209
  onChange={composeEventHandlers(onChange, (e) => {
209
210
  if (!api.composer().getState().isEditing) return;
210
- api.composer().setText(e.target.value);
211
- api.flushSync();
211
+ flushSync(() => {
212
+ api.composer().setText(e.target.value);
213
+ });
212
214
  })}
213
215
  onKeyDown={composeEventHandlers(onKeyDown, handleKeyPress)}
214
216
  onPaste={composeEventHandlers(onPaste, handlePaste)}
@@ -30,36 +30,67 @@ export namespace ThreadPrimitiveViewport {
30
30
  * - "top": New user messages anchor at the top of the viewport for a focused reading experience.
31
31
  */
32
32
  turnAnchor?: "top" | "bottom" | undefined;
33
+
34
+ /**
35
+ * Whether to scroll to bottom when a new run starts.
36
+ *
37
+ * Defaults to true.
38
+ */
39
+ scrollToBottomOnRunStart?: boolean | undefined;
40
+
41
+ /**
42
+ * Whether to scroll to bottom when thread history is first loaded.
43
+ *
44
+ * Defaults to true.
45
+ */
46
+ scrollToBottomOnInitialize?: boolean | undefined;
47
+
48
+ /**
49
+ * Whether to scroll to bottom when switching to a different thread.
50
+ *
51
+ * Defaults to true.
52
+ */
53
+ scrollToBottomOnThreadSwitch?: boolean | undefined;
33
54
  };
34
55
  }
35
56
 
36
57
  const useViewportSizeRef = () => {
37
58
  const register = useThreadViewport((s) => s.registerViewport);
38
- const getHeight = useCallback(
39
- (el: HTMLElement) =>
40
- el.clientHeight - parseFloat(getComputedStyle(el).paddingTop),
41
- [],
42
- );
43
-
59
+ const getHeight = useCallback((el: HTMLElement) => el.clientHeight, []);
44
60
  return useSizeHandle(register, getHeight);
45
61
  };
46
62
 
47
63
  const ThreadPrimitiveViewportScrollable = forwardRef<
48
64
  ThreadPrimitiveViewport.Element,
49
65
  ThreadPrimitiveViewport.Props
50
- >(({ autoScroll, children, ...rest }, forwardedRef) => {
51
- const autoScrollRef = useThreadViewportAutoScroll<HTMLDivElement>({
52
- autoScroll,
53
- });
54
- const viewportSizeRef = useViewportSizeRef();
55
- const ref = useComposedRefs(forwardedRef, autoScrollRef, viewportSizeRef);
66
+ >(
67
+ (
68
+ {
69
+ autoScroll,
70
+ scrollToBottomOnRunStart,
71
+ scrollToBottomOnInitialize,
72
+ scrollToBottomOnThreadSwitch,
73
+ children,
74
+ ...rest
75
+ },
76
+ forwardedRef,
77
+ ) => {
78
+ const autoScrollRef = useThreadViewportAutoScroll<HTMLDivElement>({
79
+ autoScroll,
80
+ scrollToBottomOnRunStart,
81
+ scrollToBottomOnInitialize,
82
+ scrollToBottomOnThreadSwitch,
83
+ });
84
+ const viewportSizeRef = useViewportSizeRef();
85
+ const ref = useComposedRefs(forwardedRef, autoScrollRef, viewportSizeRef);
56
86
 
57
- return (
58
- <Primitive.div {...rest} ref={ref}>
59
- {children}
60
- </Primitive.div>
61
- );
62
- });
87
+ return (
88
+ <Primitive.div {...rest} ref={ref}>
89
+ {children}
90
+ </Primitive.div>
91
+ );
92
+ },
93
+ );
63
94
 
64
95
  ThreadPrimitiveViewportScrollable.displayName =
65
96
  "ThreadPrimitive.ViewportScrollable";
@@ -57,7 +57,10 @@ export const ThreadPrimitiveViewportSlack: FC<ThreadViewportSlackProps> = ({
57
57
  fillClampThreshold = "10em",
58
58
  fillClampOffset = "6em",
59
59
  }) => {
60
- const isLast = useAssistantState(({ message }) => message.isLast);
60
+ const isLast = useAssistantState(
61
+ // only add slack if the message is the last message and we already have at least 3 messages
62
+ ({ message }) => message.isLast && message.index >= 2,
63
+ );
61
64
  const threadViewportStore = useThreadViewportStore({ optional: true });
62
65
  const isNested = useContext(SlackNestingContext);
63
66
 
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useComposedRefs } from "@radix-ui/react-compose-refs";
4
- import { RefCallback, useCallback, useRef } from "react";
4
+ import { useCallback, useRef, type RefCallback } from "react";
5
5
  import { useAssistantEvent } from "../../context";
6
6
  import { useOnResizeContent } from "../../utils/hooks/useOnResizeContent";
7
7
  import { useOnScrollToBottom } from "../../utils/hooks/useOnScrollToBottom";
@@ -18,11 +18,35 @@ export namespace useThreadViewportAutoScroll {
18
18
  * Default false if `turnAnchor` is "top", otherwise defaults to true.
19
19
  */
20
20
  autoScroll?: boolean | undefined;
21
+
22
+ /**
23
+ * Whether to scroll to bottom when a new run starts.
24
+ *
25
+ * Defaults to true.
26
+ */
27
+ scrollToBottomOnRunStart?: boolean | undefined;
28
+
29
+ /**
30
+ * Whether to scroll to bottom when thread history is first loaded.
31
+ *
32
+ * Defaults to true.
33
+ */
34
+ scrollToBottomOnInitialize?: boolean | undefined;
35
+
36
+ /**
37
+ * Whether to scroll to bottom when switching to a different thread.
38
+ *
39
+ * Defaults to true.
40
+ */
41
+ scrollToBottomOnThreadSwitch?: boolean | undefined;
21
42
  };
22
43
  }
23
44
 
24
45
  export const useThreadViewportAutoScroll = <TElement extends HTMLElement>({
25
46
  autoScroll,
47
+ scrollToBottomOnRunStart = true,
48
+ scrollToBottomOnInitialize = true,
49
+ scrollToBottomOnThreadSwitch = true,
26
50
  }: useThreadViewportAutoScroll.Options): RefCallback<TElement> => {
27
51
  const divRef = useRef<TElement>(null);
28
52
 
@@ -62,7 +86,10 @@ export const useThreadViewportAutoScroll = <TElement extends HTMLElement>({
62
86
  scrollingToBottomBehaviorRef.current = null;
63
87
  }
64
88
 
65
- if (newIsAtBottom !== isAtBottom) {
89
+ const shouldUpdate =
90
+ newIsAtBottom || scrollingToBottomBehaviorRef.current === null;
91
+
92
+ if (shouldUpdate && newIsAtBottom !== isAtBottom) {
66
93
  writableStore(threadViewportStore).setState({
67
94
  isAtBottom: newIsAtBottom,
68
95
  });
@@ -96,12 +123,31 @@ export const useThreadViewportAutoScroll = <TElement extends HTMLElement>({
96
123
 
97
124
  // autoscroll on run start
98
125
  useAssistantEvent("thread.run-start", () => {
126
+ if (!scrollToBottomOnRunStart) return;
99
127
  scrollingToBottomBehaviorRef.current = "auto";
100
128
  requestAnimationFrame(() => {
101
129
  scrollToBottom("auto");
102
130
  });
103
131
  });
104
132
 
133
+ // scroll to bottom instantly when thread history is first loaded
134
+ useAssistantEvent("thread.initialize", () => {
135
+ if (!scrollToBottomOnInitialize) return;
136
+ scrollingToBottomBehaviorRef.current = "instant";
137
+ requestAnimationFrame(() => {
138
+ scrollToBottom("instant");
139
+ });
140
+ });
141
+
142
+ // scroll to bottom instantly when switching threads
143
+ useAssistantEvent("thread-list-item.switched-to", () => {
144
+ if (!scrollToBottomOnThreadSwitch) return;
145
+ scrollingToBottomBehaviorRef.current = "instant";
146
+ requestAnimationFrame(() => {
147
+ scrollToBottom("instant");
148
+ });
149
+ });
150
+
105
151
  const autoScrollRef = useComposedRefs<TElement>(resizeRef, scrollRef, divRef);
106
152
  return autoScrollRef as RefCallback<TElement>;
107
153
  };
@@ -40,7 +40,7 @@ type AssistantApiFieldNames = {
40
40
  /**
41
41
  * Configuration for a derived scope field - infers types from the actual values provided
42
42
  */
43
- export type DerivedScopeConfig<TSource extends string | null, TQuery, TApi> = {
43
+ export type DerivedConfig<TSource extends string | null, TQuery, TApi> = {
44
44
  source: TSource;
45
45
  query: TQuery;
46
46
  get: () => TApi;
@@ -59,18 +59,12 @@ export type OnCallbackFn = <TEvent extends AssistantEvent>(
59
59
  */
60
60
  export type SubscribeCallbackFn = (listener: () => void) => Unsubscribe;
61
61
 
62
- /**
63
- * Type for the special `flushSync` callback function
64
- */
65
- export type FlushSyncCallbackFn = () => void;
66
-
67
62
  /**
68
63
  * Type for special non-field functions in AssistantApi
69
64
  */
70
65
  export type SpecialCallbacks = {
71
66
  on?: OnCallbackFn;
72
67
  subscribe?: SubscribeCallbackFn;
73
- flushSync?: FlushSyncCallbackFn;
74
68
  };
75
69
 
76
70
  /**
@@ -98,7 +92,7 @@ export type DerivedScopesInput = {
98
92
  */
99
93
  export const DerivedScope = resource(
100
94
  <TSource extends string | null, TQuery, TApi>(
101
- config: DerivedScopeConfig<TSource, TQuery, TApi>,
95
+ config: DerivedConfig<TSource, TQuery, TApi>,
102
96
  ): AssistantApiField<
103
97
  TApi,
104
98
  {
@@ -144,32 +138,28 @@ const ScopeFieldWithNameResource = resource(
144
138
  */
145
139
  export const DerivedScopes = resource(
146
140
  (scopes: DerivedScopesInput): Partial<AssistantApi> => {
147
- const { on, subscribe, flushSync, ...scopeFields } = scopes;
148
- const callbacksRef = tapRef({ on, subscribe, flushSync });
141
+ const { on, subscribe, ...scopeFields } = scopes;
142
+ const callbacksRef = tapRef({ on, subscribe });
149
143
  tapEffect(() => {
150
- callbacksRef.current = { on, subscribe, flushSync };
144
+ callbacksRef.current = { on, subscribe };
151
145
  });
152
146
 
153
147
  const results = tapResources(
154
- Object.entries(scopeFields).map(([fieldName, scopeElement]) =>
155
- ScopeFieldWithNameResource(
156
- {
157
- fieldName,
158
- scopeElement: scopeElement as ReturnType<typeof DerivedScope>,
159
- },
160
- { key: fieldName },
161
- ),
162
- ),
148
+ scopeFields as Record<string, ReturnType<typeof DerivedScope>>,
149
+ (scopeElement, fieldName) =>
150
+ ScopeFieldWithNameResource({
151
+ fieldName,
152
+ scopeElement,
153
+ }),
154
+ [],
163
155
  );
164
156
 
165
157
  return tapMemo(() => {
166
- const result = Object.fromEntries(results) as Partial<AssistantApi>;
158
+ const result = Object.fromEntries(
159
+ Object.values(results),
160
+ ) as Partial<AssistantApi>;
167
161
 
168
- const {
169
- on: onCb,
170
- subscribe: subCb,
171
- flushSync: flushCb,
172
- } = callbacksRef.current;
162
+ const { on: onCb, subscribe: subCb } = callbacksRef.current;
173
163
 
174
164
  if (onCb) {
175
165
  result.on = <TEvent extends AssistantEvent>(
@@ -178,9 +168,8 @@ export const DerivedScopes = resource(
178
168
  ) => onCb(selector, callback);
179
169
  }
180
170
  if (subCb) result.subscribe = (listener) => subCb(listener);
181
- if (flushCb) result.flushSync = () => flushCb();
182
171
 
183
172
  return result;
184
- }, [...results]);
173
+ }, [results]);
185
174
  },
186
175
  );
@@ -2,10 +2,9 @@ export { type Store, asStore } from "./store";
2
2
  export { tapApi, type ApiObject } from "./tap-api";
3
3
  export {
4
4
  DerivedScope,
5
- type DerivedScopeConfig,
5
+ type DerivedConfig,
6
6
  type OnCallbackFn,
7
7
  type SubscribeCallbackFn,
8
- type FlushSyncCallbackFn,
9
8
  type SpecialCallbacks,
10
9
  type DerivedScopesInput,
11
10
  } from "./derived-scopes";
@@ -17,22 +17,17 @@ export interface Store<TState> {
17
17
  * Subscribe to the store.
18
18
  */
19
19
  subscribe(listener: () => void): Unsubscribe;
20
-
21
- /**
22
- * Synchronously flush all the updates to the store.
23
- */
24
- flushSync(): void;
25
20
  }
26
21
 
27
22
  export const asStore = resource(
28
23
  <TState, TProps>(element: ResourceElement<TState, TProps>): Store<TState> => {
29
24
  const resource = tapMemo(
30
- () => createResource(element, true),
25
+ () => createResource(element, { mount: false }),
31
26
  [element.type],
32
27
  );
33
28
 
34
29
  tapEffect(() => {
35
- resource.updateInput(element.props);
30
+ resource.render(element);
36
31
  });
37
32
 
38
33
  return resource;
@@ -5,33 +5,39 @@ export interface ApiObject {
5
5
  }
6
6
 
7
7
  class ReadonlyApiHandler<TApi extends ApiObject> implements ProxyHandler<TApi> {
8
- constructor(private readonly getApi: () => TApi) {}
8
+ constructor(private readonly ref: tapRef.RefObject<TApi>) {}
9
9
 
10
10
  get(_: unknown, prop: string | symbol) {
11
- return this.getApi()[prop as keyof TApi];
11
+ return this.ref.current[prop as keyof TApi];
12
12
  }
13
13
 
14
14
  ownKeys(): ArrayLike<string | symbol> {
15
- return Object.keys(this.getApi() as object);
15
+ return Object.keys(this.ref.current as object);
16
16
  }
17
17
 
18
18
  has(_: unknown, prop: string | symbol) {
19
- return prop in (this.getApi() as object);
19
+ return prop in (this.ref.current as object);
20
20
  }
21
21
 
22
22
  getOwnPropertyDescriptor(_: unknown, prop: string | symbol) {
23
- return Object.getOwnPropertyDescriptor(this.getApi(), prop);
23
+ return Object.getOwnPropertyDescriptor(this.ref.current, prop);
24
24
  }
25
25
 
26
26
  set() {
27
27
  return false;
28
28
  }
29
+ setPrototypeOf() {
30
+ return false;
31
+ }
29
32
  defineProperty() {
30
33
  return false;
31
34
  }
32
35
  deleteProperty() {
33
36
  return false;
34
37
  }
38
+ preventExtensions(): boolean {
39
+ return false;
40
+ }
35
41
  }
36
42
 
37
43
  export const tapApi = <TApi extends ApiObject & { getState: () => any }>(
@@ -46,8 +52,7 @@ export const tapApi = <TApi extends ApiObject & { getState: () => any }>(
46
52
  });
47
53
 
48
54
  const apiProxy = tapMemo(
49
- () =>
50
- new Proxy<TApi>({} as TApi, new ReadonlyApiHandler(() => ref.current)),
55
+ () => new Proxy<TApi>({} as TApi, new ReadonlyApiHandler(ref)),
51
56
  [],
52
57
  );
53
58