@assistant-ui/store 0.0.2 → 0.0.4
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/README.md +59 -262
- package/dist/AssistantIf.d.ts +4 -6
- package/dist/AssistantIf.d.ts.map +1 -1
- package/dist/AssistantIf.js +1 -4
- package/dist/AssistantIf.js.map +1 -1
- package/dist/Derived.d.ts +34 -0
- package/dist/Derived.d.ts.map +1 -0
- package/dist/Derived.js +11 -0
- package/dist/Derived.js.map +1 -0
- package/dist/attachDefaultPeers.d.ts +56 -0
- package/dist/attachDefaultPeers.d.ts.map +1 -0
- package/dist/attachDefaultPeers.js +22 -0
- package/dist/attachDefaultPeers.js.map +1 -0
- package/dist/index.d.ts +10 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -13
- package/dist/index.js.map +1 -1
- package/dist/tapClientList.d.ts +24 -0
- package/dist/tapClientList.d.ts.map +1 -0
- package/dist/tapClientList.js +72 -0
- package/dist/tapClientList.js.map +1 -0
- package/dist/tapClientLookup.d.ts +11 -0
- package/dist/tapClientLookup.d.ts.map +1 -0
- package/dist/tapClientLookup.js +42 -0
- package/dist/tapClientLookup.js.map +1 -0
- package/dist/tapClientResource.d.ts +24 -0
- package/dist/tapClientResource.d.ts.map +1 -0
- package/dist/tapClientResource.js +100 -0
- package/dist/tapClientResource.js.map +1 -0
- package/dist/types/client.d.ts +117 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/client.js +1 -0
- package/dist/types/events.d.ts +33 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +12 -0
- package/dist/types/events.js.map +1 -0
- package/dist/useAssistantClient.d.ts +13 -46
- package/dist/useAssistantClient.d.ts.map +1 -1
- package/dist/useAssistantClient.js +177 -137
- package/dist/useAssistantClient.js.map +1 -1
- package/dist/useAssistantEvent.d.ts +2 -2
- package/dist/useAssistantEvent.d.ts.map +1 -1
- package/dist/useAssistantEvent.js +3 -6
- package/dist/useAssistantEvent.js.map +1 -1
- package/dist/useAssistantState.d.ts +2 -2
- package/dist/useAssistantState.d.ts.map +1 -1
- package/dist/useAssistantState.js +7 -36
- package/dist/useAssistantState.js.map +1 -1
- package/dist/utils/BaseProxyHandler.d.ts +23 -0
- package/dist/utils/BaseProxyHandler.d.ts.map +1 -0
- package/dist/utils/BaseProxyHandler.js +41 -0
- package/dist/utils/BaseProxyHandler.js.map +1 -0
- package/dist/utils/NotificationManager.d.ts +11 -0
- package/dist/utils/NotificationManager.d.ts.map +1 -0
- package/dist/utils/NotificationManager.js +81 -0
- package/dist/utils/NotificationManager.js.map +1 -0
- package/dist/utils/StoreResource.d.ts +14 -0
- package/dist/utils/StoreResource.d.ts.map +1 -0
- package/dist/utils/StoreResource.js +23 -0
- package/dist/utils/StoreResource.js.map +1 -0
- package/dist/utils/proxied-assistant-state.d.ts +8 -0
- package/dist/utils/proxied-assistant-state.d.ts.map +1 -0
- package/dist/utils/proxied-assistant-state.js +41 -0
- package/dist/utils/proxied-assistant-state.js.map +1 -0
- package/dist/{AssistantContext.d.ts → utils/react-assistant-context.d.ts} +6 -6
- package/dist/utils/react-assistant-context.d.ts.map +1 -0
- package/dist/utils/react-assistant-context.js +73 -0
- package/dist/utils/react-assistant-context.js.map +1 -0
- package/dist/utils/splitClients.d.ts +28 -0
- package/dist/utils/splitClients.d.ts.map +1 -0
- package/dist/utils/splitClients.js +37 -0
- package/dist/utils/splitClients.js.map +1 -0
- package/dist/utils/tap-assistant-context.d.ts +19 -0
- package/dist/utils/tap-assistant-context.d.ts.map +1 -0
- package/dist/utils/tap-assistant-context.js +37 -0
- package/dist/utils/tap-assistant-context.js.map +1 -0
- package/dist/utils/tap-client-stack-context.d.ts +23 -0
- package/dist/utils/tap-client-stack-context.d.ts.map +1 -0
- package/dist/utils/tap-client-stack-context.js +30 -0
- package/dist/utils/tap-client-stack-context.js.map +1 -0
- package/package.json +3 -3
- package/src/AssistantIf.tsx +3 -11
- package/src/Derived.ts +46 -0
- package/src/attachDefaultPeers.ts +78 -0
- package/src/index.ts +19 -22
- package/src/tapClientList.ts +105 -0
- package/src/tapClientLookup.ts +56 -0
- package/src/tapClientResource.ts +152 -0
- package/src/types/client.ts +186 -0
- package/src/types/events.ts +77 -0
- package/src/useAssistantClient.tsx +252 -234
- package/src/useAssistantEvent.ts +6 -9
- package/src/useAssistantState.tsx +10 -48
- package/src/utils/BaseProxyHandler.ts +50 -0
- package/src/utils/NotificationManager.ts +110 -0
- package/src/utils/StoreResource.ts +36 -0
- package/src/utils/proxied-assistant-state.tsx +53 -0
- package/src/utils/react-assistant-context.tsx +107 -0
- package/src/utils/splitClients.ts +85 -0
- package/src/utils/tap-assistant-context.ts +59 -0
- package/src/utils/tap-client-stack-context.ts +51 -0
- package/dist/AssistantContext.d.ts.map +0 -1
- package/dist/AssistantContext.js +0 -45
- package/dist/AssistantContext.js.map +0 -1
- package/dist/DerivedScope.d.ts +0 -20
- package/dist/DerivedScope.d.ts.map +0 -1
- package/dist/DerivedScope.js +0 -11
- package/dist/DerivedScope.js.map +0 -1
- package/dist/EventContext.d.ts +0 -61
- package/dist/EventContext.d.ts.map +0 -1
- package/dist/EventContext.js +0 -62
- package/dist/EventContext.js.map +0 -1
- package/dist/ScopeRegistry.d.ts +0 -41
- package/dist/ScopeRegistry.d.ts.map +0 -1
- package/dist/ScopeRegistry.js +0 -17
- package/dist/ScopeRegistry.js.map +0 -1
- package/dist/StoreContext.d.ts +0 -9
- package/dist/StoreContext.d.ts.map +0 -1
- package/dist/StoreContext.js +0 -20
- package/dist/StoreContext.js.map +0 -1
- package/dist/asStore.d.ts +0 -20
- package/dist/asStore.d.ts.map +0 -1
- package/dist/asStore.js +0 -23
- package/dist/asStore.js.map +0 -1
- package/dist/tapApi.d.ts +0 -36
- package/dist/tapApi.d.ts.map +0 -1
- package/dist/tapApi.js +0 -52
- package/dist/tapApi.js.map +0 -1
- package/dist/tapLookupResources.d.ts +0 -44
- package/dist/tapLookupResources.d.ts.map +0 -1
- package/dist/tapLookupResources.js +0 -21
- package/dist/tapLookupResources.js.map +0 -1
- package/dist/tapStoreList.d.ts +0 -76
- package/dist/tapStoreList.d.ts.map +0 -1
- package/dist/tapStoreList.js +0 -46
- package/dist/tapStoreList.js.map +0 -1
- package/dist/types.d.ts +0 -84
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
- package/dist/utils/splitScopes.d.ts +0 -24
- package/dist/utils/splitScopes.d.ts.map +0 -1
- package/dist/utils/splitScopes.js +0 -18
- package/dist/utils/splitScopes.js.map +0 -1
- package/src/AssistantContext.tsx +0 -64
- package/src/DerivedScope.ts +0 -23
- package/src/EventContext.ts +0 -187
- package/src/ScopeRegistry.ts +0 -58
- package/src/StoreContext.ts +0 -28
- package/src/asStore.ts +0 -40
- package/src/tapApi.ts +0 -91
- package/src/tapLookupResources.ts +0 -62
- package/src/tapStoreList.ts +0 -133
- package/src/types.ts +0 -119
- package/src/utils/splitScopes.ts +0 -38
- /package/dist/{types.js.map → types/client.js.map} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AssistantClientAccessor,
|
|
3
|
+
ClientEvents,
|
|
4
|
+
ClientNames,
|
|
5
|
+
} from "./client";
|
|
6
|
+
|
|
7
|
+
// --- Event Map Construction ---
|
|
8
|
+
type UnionToIntersection<U> = (
|
|
9
|
+
U extends unknown
|
|
10
|
+
? (x: U) => void
|
|
11
|
+
: never
|
|
12
|
+
) extends (x: infer I) => void
|
|
13
|
+
? I
|
|
14
|
+
: never;
|
|
15
|
+
|
|
16
|
+
type ClientEventMap = UnionToIntersection<
|
|
17
|
+
{ [K in ClientNames]: ClientEvents<K> }[ClientNames]
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
// --- Core Types ---
|
|
21
|
+
|
|
22
|
+
type WildcardPayload = {
|
|
23
|
+
[K in keyof ClientEventMap]: { event: K; payload: ClientEventMap[K] };
|
|
24
|
+
}[keyof ClientEventMap];
|
|
25
|
+
|
|
26
|
+
export type AssistantEventPayload = ClientEventMap & { "*": WildcardPayload };
|
|
27
|
+
|
|
28
|
+
export type AssistantEventName = keyof AssistantEventPayload;
|
|
29
|
+
|
|
30
|
+
type EventSource<T extends AssistantEventName> =
|
|
31
|
+
T extends `${infer Source}.${string}` ? Source : never;
|
|
32
|
+
|
|
33
|
+
// --- Scoping ---
|
|
34
|
+
|
|
35
|
+
type ParentOf<K extends ClientNames> =
|
|
36
|
+
AssistantClientAccessor<K> extends { source: infer S }
|
|
37
|
+
? S extends ClientNames
|
|
38
|
+
? S
|
|
39
|
+
: never
|
|
40
|
+
: never;
|
|
41
|
+
|
|
42
|
+
type AncestorsOf<
|
|
43
|
+
K extends ClientNames,
|
|
44
|
+
Seen extends ClientNames = never,
|
|
45
|
+
> = K extends Seen
|
|
46
|
+
? never
|
|
47
|
+
: ParentOf<K> extends never
|
|
48
|
+
? never
|
|
49
|
+
: ParentOf<K> | AncestorsOf<ParentOf<K>, Seen | K>;
|
|
50
|
+
|
|
51
|
+
/** Valid scopes: `"*"` | event source | ancestors of event source */
|
|
52
|
+
export type AssistantEventScope<TEvent extends AssistantEventName> =
|
|
53
|
+
| "*"
|
|
54
|
+
| EventSource<TEvent>
|
|
55
|
+
| (EventSource<TEvent> extends ClientNames
|
|
56
|
+
? AncestorsOf<EventSource<TEvent>>
|
|
57
|
+
: never);
|
|
58
|
+
|
|
59
|
+
// --- Selection & Callbacks ---
|
|
60
|
+
|
|
61
|
+
export type AssistantEventSelector<TEvent extends AssistantEventName> =
|
|
62
|
+
| TEvent
|
|
63
|
+
| { scope: AssistantEventScope<TEvent>; event: TEvent };
|
|
64
|
+
|
|
65
|
+
export const normalizeEventSelector = <TEvent extends AssistantEventName>(
|
|
66
|
+
selector: AssistantEventSelector<TEvent>,
|
|
67
|
+
) => {
|
|
68
|
+
if (typeof selector === "string") {
|
|
69
|
+
const source = selector.split(".")[0] as AssistantEventScope<TEvent>;
|
|
70
|
+
return { scope: source, event: selector };
|
|
71
|
+
}
|
|
72
|
+
return { scope: selector.scope, event: selector.event };
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type AssistantEventCallback<TEvent extends AssistantEventName> = (
|
|
76
|
+
payload: AssistantEventPayload[TEvent],
|
|
77
|
+
) => void;
|
|
@@ -1,303 +1,321 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
2
3
|
import { useResource } from "@assistant-ui/tap/react";
|
|
3
4
|
import {
|
|
4
5
|
resource,
|
|
5
6
|
tapMemo,
|
|
6
|
-
tapResource,
|
|
7
7
|
tapResources,
|
|
8
8
|
tapEffectEvent,
|
|
9
9
|
tapInlineResource,
|
|
10
|
-
|
|
10
|
+
tapEffect,
|
|
11
|
+
tapRef,
|
|
12
|
+
tapResource,
|
|
11
13
|
} from "@assistant-ui/tap";
|
|
12
14
|
import type {
|
|
13
15
|
AssistantClient,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from "./
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
|
|
16
|
+
AssistantClientAccessor,
|
|
17
|
+
ClientNames,
|
|
18
|
+
ClientElement,
|
|
19
|
+
ClientMeta,
|
|
20
|
+
} from "./types/client";
|
|
21
|
+
import { Derived, DerivedElement } from "./Derived";
|
|
22
|
+
import { StoreResource } from "./utils/StoreResource";
|
|
23
|
+
import {
|
|
24
|
+
useAssistantContextValue,
|
|
25
|
+
DefaultAssistantClient,
|
|
26
|
+
createRootAssistantClient,
|
|
27
|
+
} from "./utils/react-assistant-context";
|
|
28
|
+
import {
|
|
29
|
+
DerivedClients,
|
|
30
|
+
RootClients,
|
|
31
|
+
splitClients,
|
|
32
|
+
} from "./utils/splitClients";
|
|
23
33
|
import {
|
|
24
|
-
EventManager,
|
|
25
34
|
normalizeEventSelector,
|
|
26
|
-
type
|
|
35
|
+
type AssistantEventName,
|
|
27
36
|
type AssistantEventCallback,
|
|
28
37
|
type AssistantEventSelector,
|
|
29
|
-
} from "./
|
|
30
|
-
import {
|
|
38
|
+
} from "./types/events";
|
|
39
|
+
import { NotificationManager } from "./utils/NotificationManager";
|
|
40
|
+
import { withAssistantTapContextProvider } from "./utils/tap-assistant-context";
|
|
41
|
+
import { tapClientResource } from "./tapClientResource";
|
|
42
|
+
import { getClientIndex } from "./utils/tap-client-stack-context";
|
|
43
|
+
import {
|
|
44
|
+
PROXIED_ASSISTANT_STATE_SYMBOL,
|
|
45
|
+
createProxiedAssistantState,
|
|
46
|
+
} from "./utils/proxied-assistant-state";
|
|
31
47
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* This ensures the context is re-established on every re-render.
|
|
35
|
-
*/
|
|
36
|
-
const RootScopeStoreResource = resource(
|
|
37
|
-
<K extends keyof AssistantScopes>({
|
|
48
|
+
const RootClientResource = resource(
|
|
49
|
+
<K extends ClientNames>({
|
|
38
50
|
element,
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
emit,
|
|
52
|
+
clientRef,
|
|
41
53
|
}: {
|
|
42
|
-
element:
|
|
43
|
-
|
|
44
|
-
parent: AssistantClient;
|
|
54
|
+
element: ClientElement<K>;
|
|
55
|
+
emit: NotificationManager["emit"];
|
|
56
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
45
57
|
}) => {
|
|
46
|
-
|
|
47
|
-
|
|
58
|
+
const { methods, state } = withAssistantTapContextProvider(
|
|
59
|
+
{ clientRef, emit },
|
|
60
|
+
() => tapClientResource(element),
|
|
48
61
|
);
|
|
62
|
+
return tapMemo(() => ({ methods }), [state]);
|
|
49
63
|
},
|
|
50
64
|
);
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* Returns a tuple of [scopeName, {scopeFunction, subscribe, flushSync}]
|
|
55
|
-
*/
|
|
56
|
-
const RootScopeResource = resource(
|
|
57
|
-
<K extends keyof AssistantScopes>({
|
|
58
|
-
scopeName,
|
|
66
|
+
const RootClientAccessorResource = resource(
|
|
67
|
+
<K extends ClientNames>({
|
|
59
68
|
element,
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
notifications,
|
|
70
|
+
clientRef,
|
|
62
71
|
}: {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
element: ClientElement<K>;
|
|
73
|
+
notifications: NotificationManager;
|
|
74
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
75
|
+
}): AssistantClientAccessor<K> => {
|
|
76
|
+
const store = tapInlineResource(
|
|
77
|
+
StoreResource(
|
|
78
|
+
RootClientResource({ element, emit: notifications.emit, clientRef }),
|
|
79
|
+
),
|
|
70
80
|
);
|
|
71
81
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
>;
|
|
76
|
-
scopeFunction.source = "root";
|
|
77
|
-
scopeFunction.query = {};
|
|
82
|
+
tapEffect(() => {
|
|
83
|
+
return store.subscribe(notifications.notifySubscribers);
|
|
84
|
+
}, [store, notifications]);
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
] as const;
|
|
87
|
-
}, [scopeName, store]);
|
|
86
|
+
return tapMemo(() => {
|
|
87
|
+
const clientFunction = () => store.getState().methods;
|
|
88
|
+
clientFunction.source = "root" as const;
|
|
89
|
+
clientFunction.query = {};
|
|
90
|
+
return clientFunction;
|
|
91
|
+
}, [store]);
|
|
88
92
|
},
|
|
89
93
|
);
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const events = tapInlineResource(EventManager());
|
|
95
|
+
const NoOpRootClientsAccessorsResource = resource(() => {
|
|
96
|
+
return tapMemo(
|
|
97
|
+
() => ({ clients: {}, subscribe: undefined, on: undefined }),
|
|
98
|
+
[],
|
|
99
|
+
);
|
|
100
|
+
});
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
),
|
|
102
|
+
const RootClientsAccessorsResource = resource(
|
|
103
|
+
({
|
|
104
|
+
clients: inputClients,
|
|
105
|
+
clientRef,
|
|
106
|
+
}: {
|
|
107
|
+
clients: RootClients;
|
|
108
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
109
|
+
}) => {
|
|
110
|
+
const notifications = tapInlineResource(NotificationManager());
|
|
111
|
+
|
|
112
|
+
tapEffect(
|
|
113
|
+
() => clientRef.parent.subscribe(notifications.notifySubscribers),
|
|
114
|
+
[clientRef, notifications],
|
|
113
115
|
);
|
|
114
116
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
const results = tapResources(
|
|
118
|
+
inputClients,
|
|
119
|
+
(element) =>
|
|
120
|
+
RootClientAccessorResource({
|
|
121
|
+
element: element!,
|
|
122
|
+
notifications,
|
|
123
|
+
clientRef,
|
|
124
|
+
}),
|
|
125
|
+
[notifications, clientRef],
|
|
126
|
+
);
|
|
122
127
|
|
|
123
128
|
return tapMemo(() => {
|
|
124
|
-
if (resultEntries.length === 0) {
|
|
125
|
-
return {
|
|
126
|
-
scopes: {},
|
|
127
|
-
on,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
129
|
return {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
130
|
+
clients: results,
|
|
131
|
+
subscribe: notifications.subscribe,
|
|
132
|
+
on: function <TEvent extends AssistantEventName>(
|
|
133
|
+
this: AssistantClient,
|
|
134
|
+
selector: AssistantEventSelector<TEvent>,
|
|
135
|
+
callback: AssistantEventCallback<TEvent>,
|
|
136
|
+
) {
|
|
137
|
+
if (!this) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
"const { on } = useAssistantClient() is not supported. Use aui.on() instead.",
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { scope, event } = normalizeEventSelector(selector);
|
|
144
|
+
|
|
145
|
+
if (scope !== "*") {
|
|
146
|
+
const source = this[scope as ClientNames].source;
|
|
147
|
+
if (source === null) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Scope "${scope}" is not available. Use { scope: "*", event: "${event}" } to listen globally.`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const localUnsub = notifications.on(event, (payload, clientStack) => {
|
|
155
|
+
if (scope === "*") {
|
|
156
|
+
callback(payload);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const scopeClient = this[scope as ClientNames]();
|
|
161
|
+
const index = getClientIndex(scopeClient);
|
|
162
|
+
if (scopeClient === clientStack[index]) {
|
|
163
|
+
callback(payload);
|
|
164
|
+
}
|
|
146
165
|
});
|
|
166
|
+
if (
|
|
167
|
+
scope !== "*" &&
|
|
168
|
+
clientRef.parent[scope as ClientNames].source === null
|
|
169
|
+
)
|
|
170
|
+
return localUnsub;
|
|
171
|
+
|
|
172
|
+
const parentUnsub = clientRef.parent.on(selector, callback);
|
|
173
|
+
|
|
147
174
|
return () => {
|
|
148
|
-
|
|
175
|
+
localUnsub();
|
|
176
|
+
parentUnsub();
|
|
149
177
|
};
|
|
150
178
|
},
|
|
151
|
-
flushSync: () => {
|
|
152
|
-
resultEntries.forEach(([, { flushSync }]) => {
|
|
153
|
-
flushSync();
|
|
154
|
-
});
|
|
155
|
-
},
|
|
156
|
-
on,
|
|
157
179
|
};
|
|
158
|
-
}, [
|
|
180
|
+
}, [results, notifications, clientRef]);
|
|
159
181
|
},
|
|
160
182
|
);
|
|
161
183
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
export const useRootScopes = (
|
|
166
|
-
rootScopes: ScopesInput,
|
|
167
|
-
parent: AssistantClient,
|
|
168
|
-
) => {
|
|
169
|
-
return useResource(RootScopesResource({ scopes: rootScopes, parent }));
|
|
184
|
+
type MetaMemo<K extends ClientNames> = {
|
|
185
|
+
meta?: ClientMeta<K>;
|
|
186
|
+
dep?: unknown;
|
|
170
187
|
};
|
|
171
188
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
189
|
+
const getMeta = <K extends ClientNames>(
|
|
190
|
+
props: Derived.Props<K>,
|
|
191
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null },
|
|
192
|
+
memo: MetaMemo<K>,
|
|
193
|
+
): ClientMeta<K> => {
|
|
194
|
+
if ("source" in props && "query" in props) return props;
|
|
195
|
+
if (memo.dep === props) return memo.meta!;
|
|
196
|
+
const meta = props.getMeta(clientRef.current!);
|
|
197
|
+
memo.meta = meta;
|
|
198
|
+
memo.dep = props;
|
|
199
|
+
return meta;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const DerivedClientAccessorResource = resource(
|
|
203
|
+
<K extends ClientNames>({
|
|
179
204
|
element,
|
|
180
|
-
|
|
205
|
+
clientRef,
|
|
181
206
|
}: {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
AssistantScopes[K],
|
|
185
|
-
DerivedScopeProps<AssistantScopes[K]>
|
|
186
|
-
>;
|
|
187
|
-
parentClient: AssistantClient;
|
|
207
|
+
element: DerivedElement<K>;
|
|
208
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
188
209
|
}) => {
|
|
189
|
-
const get = tapEffectEvent(element.props
|
|
190
|
-
const source = element.props.source;
|
|
191
|
-
const query = element.props.query;
|
|
192
|
-
return tapMemo(() => {
|
|
193
|
-
const scopeFunction = (() => get(parentClient)) as ScopeField<
|
|
194
|
-
AssistantScopes[K]
|
|
195
|
-
>;
|
|
196
|
-
scopeFunction.source = source;
|
|
197
|
-
scopeFunction.query = query;
|
|
210
|
+
const get = tapEffectEvent(() => element.props);
|
|
198
211
|
|
|
199
|
-
|
|
200
|
-
|
|
212
|
+
return tapMemo(() => {
|
|
213
|
+
const clientFunction = () => get().get(clientRef.current!);
|
|
214
|
+
const metaMemo = {};
|
|
215
|
+
Object.defineProperties(clientFunction, {
|
|
216
|
+
source: {
|
|
217
|
+
get: () => getMeta(get(), clientRef, metaMemo).source,
|
|
218
|
+
},
|
|
219
|
+
query: {
|
|
220
|
+
get: () => getMeta(get(), clientRef, metaMemo).query,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
return clientFunction;
|
|
224
|
+
}, [clientRef]);
|
|
201
225
|
},
|
|
202
226
|
);
|
|
203
227
|
|
|
204
|
-
|
|
205
|
-
* Resource for all derived scopes
|
|
206
|
-
* Builds stable scope functions with source and query metadata
|
|
207
|
-
*/
|
|
208
|
-
const DerivedScopesResource = resource(
|
|
228
|
+
const DerivedClientsAccessorsResource = resource(
|
|
209
229
|
({
|
|
210
|
-
|
|
211
|
-
|
|
230
|
+
clients,
|
|
231
|
+
clientRef,
|
|
212
232
|
}: {
|
|
213
|
-
|
|
214
|
-
|
|
233
|
+
clients: DerivedClients;
|
|
234
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
215
235
|
}) => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
parentClient,
|
|
225
|
-
},
|
|
226
|
-
{ key: scopeName },
|
|
227
|
-
),
|
|
228
|
-
),
|
|
236
|
+
return tapResources(
|
|
237
|
+
clients,
|
|
238
|
+
(element) =>
|
|
239
|
+
DerivedClientAccessorResource({
|
|
240
|
+
element: element!,
|
|
241
|
+
clientRef,
|
|
242
|
+
}),
|
|
243
|
+
[clientRef],
|
|
229
244
|
);
|
|
230
|
-
|
|
231
|
-
return tapMemo(() => {
|
|
232
|
-
return Object.fromEntries(resultEntries) as {
|
|
233
|
-
[K in keyof typeof scopes]: ScopeField<AssistantScopes[K]>;
|
|
234
|
-
};
|
|
235
|
-
}, [...resultEntries]);
|
|
236
245
|
},
|
|
237
246
|
);
|
|
238
247
|
|
|
239
248
|
/**
|
|
240
|
-
*
|
|
249
|
+
* Resource that creates an extended AssistantClient.
|
|
241
250
|
*/
|
|
242
|
-
export const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
251
|
+
export const AssistantClientResource = resource(
|
|
252
|
+
({
|
|
253
|
+
baseClient,
|
|
254
|
+
clients,
|
|
255
|
+
}: {
|
|
256
|
+
baseClient: AssistantClient;
|
|
257
|
+
clients: useAssistantClient.Props;
|
|
258
|
+
}): AssistantClient => {
|
|
259
|
+
const { rootClients, derivedClients } = splitClients(clients, baseClient);
|
|
250
260
|
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const { rootScopes, derivedScopes } = splitScopes(scopes);
|
|
261
|
+
const clientRef = tapRef({
|
|
262
|
+
parent: baseClient,
|
|
263
|
+
current: null as AssistantClient | null,
|
|
264
|
+
}).current;
|
|
256
265
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
266
|
+
const rootFields = tapResource(
|
|
267
|
+
Object.keys(rootClients).length > 0
|
|
268
|
+
? RootClientsAccessorsResource({ clients: rootClients, clientRef })
|
|
269
|
+
: NoOpRootClientsAccessorsResource(),
|
|
270
|
+
);
|
|
260
271
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
const derivedFields = tapInlineResource(
|
|
273
|
+
DerivedClientsAccessorsResource({ clients: derivedClients, clientRef }),
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const client = tapMemo(() => {
|
|
277
|
+
// Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message
|
|
278
|
+
const proto =
|
|
279
|
+
baseClient === DefaultAssistantClient
|
|
280
|
+
? createRootAssistantClient()
|
|
281
|
+
: baseClient;
|
|
282
|
+
const client = Object.create(proto) as AssistantClient;
|
|
283
|
+
Object.assign(client, rootFields.clients, derivedFields, {
|
|
284
|
+
subscribe: rootFields.subscribe ?? baseClient.subscribe,
|
|
285
|
+
on: rootFields.on ?? baseClient.on,
|
|
286
|
+
[PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),
|
|
287
|
+
});
|
|
288
|
+
return client;
|
|
289
|
+
}, [baseClient, rootFields, derivedFields]);
|
|
290
|
+
|
|
291
|
+
if (clientRef.current === null) {
|
|
292
|
+
clientRef.current = client;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
tapEffect(() => {
|
|
296
|
+
clientRef.current = client;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return client;
|
|
300
|
+
},
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
export namespace useAssistantClient {
|
|
304
|
+
export type Props = {
|
|
305
|
+
[K in ClientNames]?: ClientElement<K> | DerivedElement<K>;
|
|
306
|
+
};
|
|
307
|
+
}
|
|
274
308
|
|
|
275
|
-
/**
|
|
276
|
-
* Hook to access or extend the AssistantClient
|
|
277
|
-
*
|
|
278
|
-
* @example Without config - returns the client from context:
|
|
279
|
-
* ```typescript
|
|
280
|
-
* const client = useAssistantClient();
|
|
281
|
-
* const fooState = client.foo.getState();
|
|
282
|
-
* ```
|
|
283
|
-
*
|
|
284
|
-
* @example With config - creates a new client with additional scopes:
|
|
285
|
-
* ```typescript
|
|
286
|
-
* const client = useAssistantClient({
|
|
287
|
-
* message: DerivedScope({
|
|
288
|
-
* source: "thread",
|
|
289
|
-
* query: { type: "index", index: 0 },
|
|
290
|
-
* get: () => messageApi,
|
|
291
|
-
* }),
|
|
292
|
-
* });
|
|
293
|
-
* ```
|
|
294
|
-
*/
|
|
295
309
|
export function useAssistantClient(): AssistantClient;
|
|
296
|
-
export function useAssistantClient(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
310
|
+
export function useAssistantClient(
|
|
311
|
+
clients: useAssistantClient.Props,
|
|
312
|
+
): AssistantClient;
|
|
313
|
+
export function useAssistantClient(
|
|
314
|
+
clients?: useAssistantClient.Props,
|
|
315
|
+
): AssistantClient {
|
|
316
|
+
const baseClient = useAssistantContextValue();
|
|
317
|
+
if (clients) {
|
|
318
|
+
return useResource(AssistantClientResource({ baseClient, clients }));
|
|
302
319
|
}
|
|
320
|
+
return baseClient;
|
|
303
321
|
}
|
package/src/useAssistantEvent.ts
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { useEffect, useEffectEvent } from "react";
|
|
2
2
|
import { useAssistantClient } from "./useAssistantClient";
|
|
3
3
|
import type {
|
|
4
|
-
|
|
4
|
+
AssistantEventName,
|
|
5
5
|
AssistantEventCallback,
|
|
6
6
|
AssistantEventSelector,
|
|
7
|
-
} from "./
|
|
8
|
-
import { normalizeEventSelector } from "./
|
|
7
|
+
} from "./types/events";
|
|
8
|
+
import { normalizeEventSelector } from "./types/events";
|
|
9
9
|
|
|
10
|
-
export const useAssistantEvent = <TEvent extends
|
|
10
|
+
export const useAssistantEvent = <TEvent extends AssistantEventName>(
|
|
11
11
|
selector: AssistantEventSelector<TEvent>,
|
|
12
12
|
callback: AssistantEventCallback<TEvent>,
|
|
13
13
|
) => {
|
|
14
|
-
const
|
|
14
|
+
const aui = useAssistantClient();
|
|
15
15
|
const callbackRef = useEffectEvent(callback);
|
|
16
16
|
|
|
17
17
|
const { scope, event } = normalizeEventSelector(selector);
|
|
18
|
-
useEffect(
|
|
19
|
-
() => client.on({ scope, event }, callbackRef),
|
|
20
|
-
[client, scope, event],
|
|
21
|
-
);
|
|
18
|
+
useEffect(() => aui.on({ scope, event }, callbackRef), [aui, scope, event]);
|
|
22
19
|
};
|