@assistant-ui/store 0.0.1 → 0.0.3
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 +10 -0
- package/dist/AssistantIf.d.ts.map +1 -0
- package/dist/AssistantIf.js +13 -0
- package/dist/AssistantIf.js.map +1 -0
- 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 +11 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -16
- 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 -41
- package/dist/useAssistantClient.d.ts.map +1 -1
- package/dist/useAssistantClient.js +185 -130
- 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 +5 -6
- package/src/AssistantIf.tsx +17 -0
- package/src/Derived.ts +46 -0
- package/src/attachDefaultPeers.ts +78 -0
- package/src/index.ts +31 -25
- 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 +259 -217
- 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 -18
- 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 -65
- 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 -88
- 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 -21
- package/src/EventContext.ts +0 -184
- 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 -129
- 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,279 +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
|
-
* Returns a tuple of [scopeName, {scopeFunction, subscribe, flushSync}]
|
|
35
|
-
*/
|
|
36
|
-
const RootScopeResource = resource(
|
|
37
|
-
<K extends keyof AssistantScopes>({
|
|
38
|
-
scopeName,
|
|
48
|
+
const RootClientResource = resource(
|
|
49
|
+
<K extends ClientNames>({
|
|
39
50
|
element,
|
|
51
|
+
emit,
|
|
52
|
+
clientRef,
|
|
40
53
|
}: {
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
element: ClientElement<K>;
|
|
55
|
+
emit: NotificationManager["emit"];
|
|
56
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
43
57
|
}) => {
|
|
44
|
-
const
|
|
58
|
+
const { methods, state } = withAssistantTapContextProvider(
|
|
59
|
+
{ clientRef, emit },
|
|
60
|
+
() => tapClientResource(element),
|
|
61
|
+
);
|
|
62
|
+
return tapMemo(() => ({ methods }), [state]);
|
|
63
|
+
},
|
|
64
|
+
);
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
const RootClientAccessorResource = resource(
|
|
67
|
+
<K extends ClientNames>({
|
|
68
|
+
element,
|
|
69
|
+
notifications,
|
|
70
|
+
clientRef,
|
|
71
|
+
}: {
|
|
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
|
+
),
|
|
80
|
+
);
|
|
52
81
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
82
|
+
tapEffect(() => {
|
|
83
|
+
return store.subscribe(notifications.notifySubscribers);
|
|
84
|
+
}, [store, notifications]);
|
|
85
|
+
|
|
86
|
+
return tapMemo(() => {
|
|
87
|
+
const clientFunction = () => store.getState().methods;
|
|
88
|
+
clientFunction.source = "root" as const;
|
|
89
|
+
clientFunction.query = {};
|
|
90
|
+
return clientFunction;
|
|
91
|
+
}, [store]);
|
|
62
92
|
},
|
|
63
93
|
);
|
|
64
94
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const events = tapInlineResource(EventManager());
|
|
95
|
+
const NoOpRootClientsAccessorsResource = resource(() => {
|
|
96
|
+
return tapMemo(
|
|
97
|
+
() => ({ clients: {}, subscribe: undefined, on: undefined }),
|
|
98
|
+
[],
|
|
99
|
+
);
|
|
100
|
+
});
|
|
72
101
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
),
|
|
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],
|
|
87
115
|
);
|
|
88
116
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
const results = tapResources(
|
|
118
|
+
inputClients,
|
|
119
|
+
(element) =>
|
|
120
|
+
RootClientAccessorResource({
|
|
121
|
+
element: element!,
|
|
122
|
+
notifications,
|
|
123
|
+
clientRef,
|
|
124
|
+
}),
|
|
125
|
+
[notifications, clientRef],
|
|
126
|
+
);
|
|
96
127
|
|
|
97
128
|
return tapMemo(() => {
|
|
98
|
-
if (resultEntries.length === 0) {
|
|
99
|
-
return {
|
|
100
|
-
scopes: {},
|
|
101
|
-
on,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
129
|
return {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
+
}
|
|
120
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
|
+
|
|
121
174
|
return () => {
|
|
122
|
-
|
|
175
|
+
localUnsub();
|
|
176
|
+
parentUnsub();
|
|
123
177
|
};
|
|
124
178
|
},
|
|
125
|
-
flushSync: () => {
|
|
126
|
-
resultEntries.forEach(([, { flushSync }]) => {
|
|
127
|
-
flushSync();
|
|
128
|
-
});
|
|
129
|
-
},
|
|
130
|
-
on,
|
|
131
179
|
};
|
|
132
|
-
}, [
|
|
180
|
+
}, [results, notifications, clientRef]);
|
|
133
181
|
},
|
|
134
182
|
);
|
|
135
183
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
export const useRootScopes = (
|
|
140
|
-
rootScopes: ScopesInput,
|
|
141
|
-
parent: AssistantClient,
|
|
142
|
-
) => {
|
|
143
|
-
return useResource(RootScopesResource({ scopes: rootScopes, parent }));
|
|
184
|
+
type MetaMemo<K extends ClientNames> = {
|
|
185
|
+
meta?: ClientMeta<K>;
|
|
186
|
+
dep?: unknown;
|
|
144
187
|
};
|
|
145
188
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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>({
|
|
153
204
|
element,
|
|
154
|
-
|
|
205
|
+
clientRef,
|
|
155
206
|
}: {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
AssistantScopes[K],
|
|
159
|
-
DerivedScopeProps<AssistantScopes[K]>
|
|
160
|
-
>;
|
|
161
|
-
parentClient: AssistantClient;
|
|
207
|
+
element: DerivedElement<K>;
|
|
208
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
162
209
|
}) => {
|
|
163
|
-
const get = tapEffectEvent(element.props
|
|
164
|
-
const source = element.props.source;
|
|
165
|
-
const query = element.props.query;
|
|
166
|
-
return tapMemo(() => {
|
|
167
|
-
const scopeFunction = (() => get(parentClient)) as ScopeField<
|
|
168
|
-
AssistantScopes[K]
|
|
169
|
-
>;
|
|
170
|
-
scopeFunction.source = source;
|
|
171
|
-
scopeFunction.query = query;
|
|
210
|
+
const get = tapEffectEvent(() => element.props);
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
|
|
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]);
|
|
175
225
|
},
|
|
176
226
|
);
|
|
177
227
|
|
|
178
|
-
|
|
179
|
-
* Resource for all derived scopes
|
|
180
|
-
* Builds stable scope functions with source and query metadata
|
|
181
|
-
*/
|
|
182
|
-
const DerivedScopesResource = resource(
|
|
228
|
+
const DerivedClientsAccessorsResource = resource(
|
|
183
229
|
({
|
|
184
|
-
|
|
185
|
-
|
|
230
|
+
clients,
|
|
231
|
+
clientRef,
|
|
186
232
|
}: {
|
|
187
|
-
|
|
188
|
-
|
|
233
|
+
clients: DerivedClients;
|
|
234
|
+
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
189
235
|
}) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
parentClient,
|
|
199
|
-
},
|
|
200
|
-
{ key: scopeName },
|
|
201
|
-
),
|
|
202
|
-
),
|
|
236
|
+
return tapResources(
|
|
237
|
+
clients,
|
|
238
|
+
(element) =>
|
|
239
|
+
DerivedClientAccessorResource({
|
|
240
|
+
element: element!,
|
|
241
|
+
clientRef,
|
|
242
|
+
}),
|
|
243
|
+
[clientRef],
|
|
203
244
|
);
|
|
204
|
-
|
|
205
|
-
return tapMemo(() => {
|
|
206
|
-
return Object.fromEntries(resultEntries) as {
|
|
207
|
-
[K in keyof typeof scopes]: ScopeField<AssistantScopes[K]>;
|
|
208
|
-
};
|
|
209
|
-
}, [...resultEntries]);
|
|
210
245
|
},
|
|
211
246
|
);
|
|
212
247
|
|
|
213
248
|
/**
|
|
214
|
-
*
|
|
249
|
+
* Resource that creates an extended AssistantClient.
|
|
215
250
|
*/
|
|
216
|
-
export const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
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);
|
|
224
260
|
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const { rootScopes, derivedScopes } = splitScopes(scopes);
|
|
261
|
+
const clientRef = tapRef({
|
|
262
|
+
parent: baseClient,
|
|
263
|
+
current: null as AssistantClient | null,
|
|
264
|
+
}).current;
|
|
230
265
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
266
|
+
const rootFields = tapResource(
|
|
267
|
+
Object.keys(rootClients).length > 0
|
|
268
|
+
? RootClientsAccessorsResource({ clients: rootClients, clientRef })
|
|
269
|
+
: NoOpRootClientsAccessorsResource(),
|
|
270
|
+
);
|
|
234
271
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
+
}
|
|
248
308
|
|
|
249
|
-
/**
|
|
250
|
-
* Hook to access or extend the AssistantClient
|
|
251
|
-
*
|
|
252
|
-
* @example Without config - returns the client from context:
|
|
253
|
-
* ```typescript
|
|
254
|
-
* const client = useAssistantClient();
|
|
255
|
-
* const fooState = client.foo.getState();
|
|
256
|
-
* ```
|
|
257
|
-
*
|
|
258
|
-
* @example With config - creates a new client with additional scopes:
|
|
259
|
-
* ```typescript
|
|
260
|
-
* const client = useAssistantClient({
|
|
261
|
-
* message: DerivedScope({
|
|
262
|
-
* source: "thread",
|
|
263
|
-
* query: { type: "index", index: 0 },
|
|
264
|
-
* get: () => messageApi,
|
|
265
|
-
* }),
|
|
266
|
-
* });
|
|
267
|
-
* ```
|
|
268
|
-
*/
|
|
269
309
|
export function useAssistantClient(): AssistantClient;
|
|
270
|
-
export function useAssistantClient(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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 }));
|
|
278
319
|
}
|
|
320
|
+
return baseClient;
|
|
279
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
|
};
|