@assistant-ui/store 0.1.6 → 0.2.1

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 (54) hide show
  1. package/README.md +9 -10
  2. package/dist/AuiIf.d.ts.map +1 -1
  3. package/dist/AuiIf.js.map +1 -1
  4. package/dist/attachTransformScopes.d.ts +11 -0
  5. package/dist/attachTransformScopes.d.ts.map +1 -0
  6. package/dist/attachTransformScopes.js +12 -0
  7. package/dist/attachTransformScopes.js.map +1 -0
  8. package/dist/index.d.ts +4 -4
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +2 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/tapClientList.d.ts +9 -5
  13. package/dist/tapClientList.d.ts.map +1 -1
  14. package/dist/tapClientList.js.map +1 -1
  15. package/dist/tapClientLookup.d.ts +7 -3
  16. package/dist/tapClientLookup.d.ts.map +1 -1
  17. package/dist/tapClientLookup.js +2 -2
  18. package/dist/tapClientLookup.js.map +1 -1
  19. package/dist/tapClientResource.d.ts +9 -24
  20. package/dist/tapClientResource.d.ts.map +1 -1
  21. package/dist/tapClientResource.js +11 -19
  22. package/dist/tapClientResource.js.map +1 -1
  23. package/dist/types/client.d.ts +23 -27
  24. package/dist/types/client.d.ts.map +1 -1
  25. package/dist/useAui.d.ts.map +1 -1
  26. package/dist/useAui.js +4 -4
  27. package/dist/useAui.js.map +1 -1
  28. package/dist/useAuiState.d.ts +1 -1
  29. package/dist/useAuiState.d.ts.map +1 -1
  30. package/dist/useAuiState.js +1 -1
  31. package/dist/useAuiState.js.map +1 -1
  32. package/dist/utils/proxied-assistant-state.d.ts.map +1 -1
  33. package/dist/utils/proxied-assistant-state.js.map +1 -1
  34. package/dist/utils/splitClients.d.ts.map +1 -1
  35. package/dist/utils/splitClients.js +25 -55
  36. package/dist/utils/splitClients.js.map +1 -1
  37. package/package.json +11 -4
  38. package/src/__tests__/hooks.test.tsx +126 -0
  39. package/src/attachTransformScopes.ts +38 -0
  40. package/src/index.ts +18 -9
  41. package/src/tapClientList.ts +13 -10
  42. package/src/tapClientLookup.ts +17 -14
  43. package/src/tapClientResource.ts +36 -31
  44. package/src/types/client.ts +41 -47
  45. package/src/{useAui.tsx → useAui.ts} +5 -6
  46. package/src/{useAuiState.tsx → useAuiState.ts} +2 -2
  47. package/src/utils/splitClients.ts +32 -82
  48. package/dist/attachDefaultPeers.d.ts +0 -56
  49. package/dist/attachDefaultPeers.d.ts.map +0 -1
  50. package/dist/attachDefaultPeers.js +0 -51
  51. package/dist/attachDefaultPeers.js.map +0 -1
  52. package/src/attachDefaultPeers.ts +0 -78
  53. /package/src/{AuiIf.tsx → AuiIf.ts} +0 -0
  54. /package/src/utils/{proxied-assistant-state.tsx → proxied-assistant-state.ts} +0 -0
@@ -4,9 +4,8 @@ import {
4
4
  tapRef,
5
5
  type ResourceElement,
6
6
  tapResource,
7
- tapInlineResource,
8
7
  } from "@assistant-ui/tap";
9
- import type { ClientMethods, ClientOutputOf } from "./types/client";
8
+ import type { ClientMethods } from "./types/client";
10
9
  import {
11
10
  tapClientStack,
12
11
  tapWithClientStack,
@@ -25,7 +24,7 @@ import { wrapperResource } from "./wrapperResource";
25
24
  const SYMBOL_GET_OUTPUT = Symbol("assistant-ui.store.getValue");
26
25
 
27
26
  type ClientInternal = {
28
- [SYMBOL_GET_OUTPUT]: ClientOutputOf<unknown, ClientMethods>;
27
+ [SYMBOL_GET_OUTPUT]: ClientMethods;
29
28
  };
30
29
 
31
30
  export const getClientState = (client: ClientMethods) => {
@@ -36,7 +35,7 @@ export const getClientState = (client: ClientMethods) => {
36
35
  "Ensure your Derived get() returns a client created with tapClientResource(), not a plain resource.",
37
36
  );
38
37
  }
39
- return output.state;
38
+ return (output as any).getState?.();
40
39
  };
41
40
 
42
41
  // Global cache for function templates by field name
@@ -64,7 +63,7 @@ function getOrCreateProxyFn(prop: string | symbol) {
64
63
  );
65
64
  }
66
65
 
67
- const method = output.methods[prop];
66
+ const method = output[prop];
68
67
  if (!method)
69
68
  throw new Error(`Method "${String(prop)}" is not implemented.`);
70
69
  if (typeof method !== "function")
@@ -85,7 +84,7 @@ class ClientProxyHandler
85
84
 
86
85
  constructor(
87
86
  private readonly outputRef: {
88
- current: ClientOutputOf<unknown, ClientMethods>;
87
+ current: ClientMethods;
89
88
  },
90
89
  private readonly index: number,
91
90
  ) {
@@ -97,7 +96,7 @@ class ClientProxyHandler
97
96
  if (prop === SYMBOL_CLIENT_INDEX) return this.index;
98
97
  const introspection = handleIntrospectionProp(prop, "ClientProxy");
99
98
  if (introspection !== false) return introspection;
100
- const value = this.outputRef.current.methods[prop];
99
+ const value = this.outputRef.current[prop];
101
100
  if (typeof value === "function") {
102
101
  if (this.cachedReceiver !== receiver) {
103
102
  this.boundFns = new Map();
@@ -114,43 +113,34 @@ class ClientProxyHandler
114
113
  }
115
114
 
116
115
  ownKeys(): ArrayLike<string | symbol> {
117
- return Object.keys(this.outputRef.current.methods);
116
+ return Object.keys(this.outputRef.current);
118
117
  }
119
118
 
120
119
  has(_: unknown, prop: string | symbol) {
121
120
  if (prop === SYMBOL_GET_OUTPUT) return true;
122
121
  if (prop === SYMBOL_CLIENT_INDEX) return true;
123
- return prop in this.outputRef.current.methods;
122
+ return prop in this.outputRef.current;
124
123
  }
125
124
  }
126
125
 
127
126
  /**
128
127
  * Resource that wraps a plain resource element to create a stable client proxy.
129
128
  *
130
- * Takes a ResourceElement that returns { state, methods } and
129
+ * Takes a ResourceElement that returns methods (with optional getState()) and
131
130
  * wraps it to produce a stable client proxy. This adds the client to the
132
131
  * client stack, enabling event scoping.
133
132
  *
134
- * Use this for 1:1 client mappings where you want event scoping to work correctly.
135
- *
136
- * @example
137
- * ```typescript
138
- * const MessageResource = resource(({ messageId }: { messageId: string }) => {
139
- * return tapInlineResource(
140
- * tapClientResource(InnerMessageResource({ messageId }))
141
- * );
142
- * });
143
- * ```
133
+ * @internal
144
134
  */
145
135
  export const ClientResource = wrapperResource(
146
- <TState, TMethods extends ClientMethods>(
147
- element: ResourceElement<ClientOutputOf<TState, TMethods>>,
148
- ): ClientOutputOf<TState, TMethods> & {
136
+ <TMethods extends ClientMethods>(
137
+ element: ResourceElement<TMethods>,
138
+ ): {
139
+ methods: TMethods;
140
+ state: unknown;
149
141
  key: string | number | undefined;
150
142
  } => {
151
- const valueRef = tapRef(
152
- null as unknown as ClientOutputOf<TState, TMethods>,
153
- );
143
+ const valueRef = tapRef(null as unknown as TMethods);
154
144
 
155
145
  const index = tapClientStack().length;
156
146
  const methods = tapMemo(
@@ -171,12 +161,27 @@ export const ClientResource = wrapperResource(
171
161
  valueRef.current = value;
172
162
  });
173
163
 
174
- return { methods, state: value.state, key: element.key };
164
+ const state = (value as any).getState?.();
165
+ return { methods, state, key: element.key };
175
166
  },
176
167
  );
177
168
 
178
- export const tapClientResource = <TState, TMethods extends ClientMethods>(
179
- element: ResourceElement<ClientOutputOf<TState, TMethods>>,
180
- ) => {
181
- return tapInlineResource(ClientResource(element));
169
+ type InferClientState<TMethods> = TMethods extends {
170
+ getState: () => infer S;
171
+ }
172
+ ? S
173
+ : undefined;
174
+
175
+ export const tapClientResource = <TMethods extends ClientMethods>(
176
+ element: ResourceElement<TMethods>,
177
+ ): {
178
+ state: InferClientState<TMethods>;
179
+ methods: TMethods;
180
+ key: string | number | undefined;
181
+ } => {
182
+ return tapResource(ClientResource(element)) as {
183
+ state: InferClientState<TMethods>;
184
+ methods: TMethods;
185
+ key: string | number | undefined;
186
+ };
182
187
  };
@@ -9,7 +9,7 @@ import type {
9
9
  * Base type for methods that can be called on a client.
10
10
  */
11
11
  export interface ClientMethods {
12
- [key: string | symbol]: ((...args: any[]) => any) | ClientMethods;
12
+ [key: string | symbol]: (...args: any[]) => any;
13
13
  }
14
14
 
15
15
  type ClientMetaType = { source: ClientNames; query: Record<string, unknown> };
@@ -23,12 +23,10 @@ type ClientMetaType = { source: ClientNames; query: Record<string, unknown> };
23
23
  * @internal
24
24
  */
25
25
  export type ClientSchema<
26
- TState = unknown,
27
26
  TMethods extends ClientMethods = ClientMethods,
28
27
  TMeta extends ClientMetaType = never,
29
28
  TEvents extends Record<string, unknown> = never,
30
29
  > = {
31
- state: TState;
32
30
  methods: TMethods;
33
31
  meta?: TMeta;
34
32
  events?: TEvents;
@@ -40,16 +38,20 @@ export type ClientSchema<
40
38
  * @example
41
39
  * ```typescript
42
40
  * declare module "@assistant-ui/store" {
43
- * interface ClientRegistry {
41
+ * interface ScopeRegistry {
44
42
  * // Simple client (meta and events are optional)
45
43
  * foo: {
46
- * state: { bar: string };
47
- * methods: { updateBar: (bar: string) => void };
44
+ * methods: {
45
+ * getState: () => { bar: string };
46
+ * updateBar: (bar: string) => void;
47
+ * };
48
48
  * };
49
49
  * // Full client with meta and events
50
50
  * bar: {
51
- * state: { id: string };
52
- * methods: { update: () => void };
51
+ * methods: {
52
+ * getState: () => { id: string };
53
+ * update: () => void;
54
+ * };
53
55
  * meta: { source: "fooList"; query: { index: number } };
54
56
  * events: {
55
57
  * "bar.updated": { id: string };
@@ -59,7 +61,7 @@ export type ClientSchema<
59
61
  * }
60
62
  * ```
61
63
  */
62
- export interface ClientRegistry {}
64
+ export interface ScopeRegistry {}
63
65
 
64
66
  type ClientEventsType<K extends ClientNames> = Record<
65
67
  `${K}.${string}`,
@@ -67,63 +69,51 @@ type ClientEventsType<K extends ClientNames> = Record<
67
69
  >;
68
70
 
69
71
  type ClientError<E extends string> = {
70
- state: E;
71
72
  methods: Record<E, () => E>;
72
73
  meta: { source: ClientNames; query: Record<E, E> };
73
74
  events: Record<`${E}.`, E>;
74
75
  };
75
76
 
76
- type ValidateClient<K extends keyof ClientRegistry> =
77
- ClientRegistry[K] extends { methods: ClientMethods }
78
- ? "meta" extends keyof ClientRegistry[K]
79
- ? ClientRegistry[K]["meta"] extends ClientMetaType
80
- ? "events" extends keyof ClientRegistry[K]
81
- ? ClientRegistry[K]["events"] extends ClientEventsType<K>
82
- ? ClientRegistry[K]
83
- : ClientError<`ERROR: ${K & string} has invalid events type`>
84
- : ClientRegistry[K]
85
- : ClientError<`ERROR: ${K & string} has invalid meta type`>
86
- : "events" extends keyof ClientRegistry[K]
87
- ? ClientRegistry[K]["events"] extends ClientEventsType<K>
88
- ? ClientRegistry[K]
77
+ type ValidateClient<K extends keyof ScopeRegistry> = ScopeRegistry[K] extends {
78
+ methods: ClientMethods;
79
+ }
80
+ ? "meta" extends keyof ScopeRegistry[K]
81
+ ? ScopeRegistry[K]["meta"] extends ClientMetaType
82
+ ? "events" extends keyof ScopeRegistry[K]
83
+ ? ScopeRegistry[K]["events"] extends ClientEventsType<K>
84
+ ? ScopeRegistry[K]
89
85
  : ClientError<`ERROR: ${K & string} has invalid events type`>
90
- : ClientRegistry[K]
91
- : ClientError<`ERROR: ${K & string} has invalid methods type`>;
92
-
93
- type ClientSchemas = keyof ClientRegistry extends never
86
+ : ScopeRegistry[K]
87
+ : ClientError<`ERROR: ${K & string} has invalid meta type`>
88
+ : "events" extends keyof ScopeRegistry[K]
89
+ ? ScopeRegistry[K]["events"] extends ClientEventsType<K>
90
+ ? ScopeRegistry[K]
91
+ : ClientError<`ERROR: ${K & string} has invalid events type`>
92
+ : ScopeRegistry[K]
93
+ : ClientError<`ERROR: ${K & string} has invalid methods type`>;
94
+
95
+ type ClientSchemas = keyof ScopeRegistry extends never
94
96
  ? {
95
97
  "ERROR: No clients were defined": ClientError<"ERROR: No clients were defined">;
96
98
  }
97
- : { [K in keyof ClientRegistry]: ValidateClient<K> };
99
+ : { [K in keyof ScopeRegistry]: ValidateClient<K> };
98
100
 
99
101
  /**
100
- * Output type that client resources return with state and methods.
102
+ * Output type that client resources return (just methods).
101
103
  *
102
104
  * @example
103
105
  * ```typescript
104
106
  * const FooResource = resource((): ClientResourceOutput<"foo"> => {
105
107
  * const [state, setState] = tapState({ bar: "hello" });
106
108
  * return {
107
- * state,
108
- * methods: {
109
- * updateBar: (b) => setState({ bar: b })
110
- * }
109
+ * getState: () => state,
110
+ * updateBar: (b) => setState({ bar: b }),
111
111
  * };
112
112
  * });
113
113
  * ```
114
114
  */
115
- export type ClientOutput<K extends ClientNames> = ClientOutputOf<
116
- ClientSchemas[K]["state"],
117
- ClientSchemas[K]["methods"] & ClientMethods
118
- >;
119
-
120
- /**
121
- * Generic version of ClientResourceOutput for library code.
122
- */
123
- export type ClientOutputOf<TState, TMethods extends ClientMethods> = {
124
- state: TState;
125
- methods: TMethods;
126
- };
115
+ export type ClientOutput<K extends ClientNames> = ClientSchemas[K]["methods"] &
116
+ ClientMethods;
127
117
 
128
118
  export type ClientNames = keyof ClientSchemas extends infer U ? U : never;
129
119
 
@@ -154,10 +144,14 @@ export type ClientElement<K extends ClientNames> = ResourceElement<
154
144
  export type Unsubscribe = () => void;
155
145
 
156
146
  /**
157
- * State type extracted from all clients.
147
+ * State type extracted from all clients via their getState() methods.
158
148
  */
159
149
  export type AssistantState = {
160
- [K in ClientNames]: ClientSchemas[K]["state"];
150
+ [K in ClientNames]: ClientSchemas[K]["methods"] extends {
151
+ getState: () => infer S;
152
+ }
153
+ ? S
154
+ : never;
161
155
  };
162
156
 
163
157
  /**
@@ -6,12 +6,11 @@ import {
6
6
  tapMemo,
7
7
  tapResources,
8
8
  tapEffectEvent,
9
- tapInlineResource,
10
9
  tapEffect,
11
10
  tapRef,
12
11
  tapResource,
13
12
  withKey,
14
- tapSubscribableResource,
13
+ tapResourceRoot,
15
14
  } from "@assistant-ui/tap";
16
15
  import type {
17
16
  AssistantClient,
@@ -46,7 +45,7 @@ import {
46
45
  createProxiedAssistantState,
47
46
  } from "./utils/proxied-assistant-state";
48
47
 
49
- const tapShallowMemoArray = <T,>(array: readonly T[]) => {
48
+ const tapShallowMemoArray = <T>(array: readonly T[]) => {
50
49
  // biome-ignore lint/correctness/useExhaustiveDependencies: shallow memo
51
50
  return tapMemo(() => array, array);
52
51
  };
@@ -81,7 +80,7 @@ const RootClientAccessorResource = resource(
81
80
  clientRef: { parent: AssistantClient; current: AssistantClient | null };
82
81
  name: K;
83
82
  }): AssistantClientAccessor<K> => {
84
- const store = tapSubscribableResource(
83
+ const store = tapResourceRoot(
85
84
  RootClientResource({ element, emit: notifications.emit, clientRef }),
86
85
  );
87
86
 
@@ -129,7 +128,7 @@ const RootClientsAccessorsResource = resource(
129
128
  clients: RootClients;
130
129
  clientRef: { parent: AssistantClient; current: AssistantClient | null };
131
130
  }) => {
132
- const notifications = tapInlineResource(NotificationManager());
131
+ const notifications = tapResource(NotificationManager());
133
132
 
134
133
  tapEffect(
135
134
  () => clientRef.parent.subscribe(notifications.notifySubscribers),
@@ -318,7 +317,7 @@ export const AssistantClientResource = resource(
318
317
  : NoOpRootClientsAccessorsResource(),
319
318
  );
320
319
 
321
- const derivedFields = tapInlineResource(
320
+ const derivedFields = tapResource(
322
321
  DerivedClientsAccessorsResource({ clients: derivedClients, clientRef }),
323
322
  );
324
323
 
@@ -15,10 +15,10 @@ import { getProxiedAssistantState } from "./utils/proxied-assistant-state";
15
15
  * foo: RootScope({ ... }),
16
16
  * });
17
17
  *
18
- * const bar = useAuiState((state) => state.foo.bar);
18
+ * const bar = useAuiState((s) => s.foo.bar);
19
19
  * ```
20
20
  */
21
- export const useAuiState = <T,>(selector: (state: AssistantState) => T): T => {
21
+ export const useAuiState = <T>(selector: (state: AssistantState) => T): T => {
22
22
  const aui = useAui();
23
23
  const proxiedState = getProxiedAssistantState(aui);
24
24
 
@@ -4,7 +4,7 @@ import type {
4
4
  ClientElement,
5
5
  ClientNames,
6
6
  } from "../types/client";
7
- import { getDefaultPeers } from "../attachDefaultPeers";
7
+ import { getTransformScopes } from "../attachTransformScopes";
8
8
  import type { useAui } from "../useAui";
9
9
  import { tapMemo } from "@assistant-ui/tap";
10
10
 
@@ -16,99 +16,49 @@ export type DerivedClients = Partial<
16
16
  >;
17
17
 
18
18
  /**
19
- * Splits a clients object into root clients and derived clients.
20
- *
21
- * @param clients - The clients input object to split
22
- * @returns An object with { rootClients, derivedClients }
23
- *
24
- * @example
25
- * ```typescript
26
- * const clients = {
27
- * foo: RootClient({ ... }),
28
- * bar: Derived({ ... }),
29
- * };
30
- *
31
- * const { rootClients, derivedClients } = splitClients(clients);
32
- * // rootClients = { foo: ... }
33
- * // derivedClients = { bar: ... }
34
- * ```
19
+ * Splits a clients object into root clients and derived clients,
20
+ * applying transformScopes from root client elements.
35
21
  */
36
22
  function splitClients(clients: useAui.Props, baseClient: AssistantClient) {
23
+ // 1. Collect transforms from root elements and run them iteratively
24
+ let scopes = { ...clients } as Record<
25
+ string,
26
+ ClientElement<ClientNames> | DerivedElement<ClientNames>
27
+ >;
28
+ const visited = new Set<(...args: any[]) => any>();
29
+
30
+ let changed = true;
31
+ while (changed) {
32
+ changed = false;
33
+ for (const clientElement of Object.values(scopes)) {
34
+ if (clientElement.type === (Derived as unknown)) continue;
35
+ if (visited.has(clientElement.type)) continue;
36
+ visited.add(clientElement.type);
37
+
38
+ const transform = getTransformScopes(clientElement.type);
39
+ if (transform) {
40
+ scopes = transform(scopes, baseClient) as typeof scopes;
41
+ changed = true;
42
+ break; // restart iteration since scopes may have new root elements
43
+ }
44
+ }
45
+ }
46
+
47
+ // 2. Split result into root/derived
37
48
  const rootClients: RootClients = {};
38
49
  const derivedClients: DerivedClients = {};
39
50
 
40
- for (const [key, clientElement] of Object.entries(clients) as [
41
- keyof useAui.Props,
42
- NonNullable<useAui.Props[keyof useAui.Props]>,
51
+ for (const [key, clientElement] of Object.entries(scopes) as [
52
+ ClientNames,
53
+ ClientElement<ClientNames> | DerivedElement<ClientNames>,
43
54
  ][]) {
44
- if (clientElement.type === Derived) {
55
+ if (clientElement.type === (Derived as unknown)) {
45
56
  derivedClients[key] = clientElement as DerivedElement<ClientNames>;
46
57
  } else {
47
58
  rootClients[key] = clientElement as ClientElement<ClientNames>;
48
59
  }
49
60
  }
50
61
 
51
- // Recursively gather all default peers, flattening nested ones
52
- const gatherDefaultPeers = (
53
- clientElement: ClientElement<ClientNames>,
54
- visited = new Set<ClientElement<ClientNames>>(),
55
- ): Array<
56
- [ClientNames, ClientElement<ClientNames> | DerivedElement<ClientNames>]
57
- > => {
58
- // Prevent infinite loops
59
- if (visited.has(clientElement)) return [];
60
- visited.add(clientElement);
61
-
62
- const defaultPeers = getDefaultPeers(clientElement.type);
63
- if (!defaultPeers) return [];
64
-
65
- const result: Array<
66
- [ClientNames, ClientElement<ClientNames> | DerivedElement<ClientNames>]
67
- > = [];
68
-
69
- for (const [key, peerElement] of Object.entries(defaultPeers) as [
70
- ClientNames,
71
- ClientElement<ClientNames> | DerivedElement<ClientNames>,
72
- ][]) {
73
- result.push([key, peerElement]);
74
-
75
- // If this peer is a root client with its own default peers, recursively gather them
76
- if (peerElement.type !== Derived<ClientNames>) {
77
- const nestedPeers = gatherDefaultPeers(
78
- peerElement as ClientElement<ClientNames>,
79
- visited,
80
- );
81
- result.push(...nestedPeers);
82
- }
83
- }
84
-
85
- return result;
86
- };
87
-
88
- // Apply flattened default peers for each root client
89
- for (const [_clientKey, clientElement] of Object.entries(rootClients) as [
90
- ClientNames,
91
- ClientElement<ClientNames>,
92
- ][]) {
93
- const allPeers = gatherDefaultPeers(clientElement);
94
-
95
- for (const [key, peerElement] of allPeers) {
96
- // Skip if already exists (first wins)
97
- if (
98
- key in rootClients ||
99
- key in derivedClients ||
100
- baseClient[key].source !== null
101
- )
102
- continue;
103
-
104
- if (peerElement.type === Derived<ClientNames>) {
105
- derivedClients[key] = peerElement as DerivedElement<ClientNames>;
106
- } else {
107
- rootClients[key] = peerElement as ClientElement<ClientNames>;
108
- }
109
- }
110
- }
111
-
112
62
  return { rootClients, derivedClients };
113
63
  }
114
64
 
@@ -1,56 +0,0 @@
1
- import type { ResourceElement } from "@assistant-ui/tap";
2
- import type { ClientElement, ClientNames } from "./types/client.js";
3
- import type { DerivedElement } from "./Derived.js";
4
- /**
5
- * Symbol used to store default peer clients on a resource.
6
- */
7
- declare const DEFAULT_PEERS: unique symbol;
8
- /**
9
- * Type for resources that have default peers attached.
10
- */
11
- export type ResourceWithDefaultPeers = {
12
- [DEFAULT_PEERS]?: DefaultPeers;
13
- };
14
- /**
15
- * Default peers configuration - can be either root clients or derived clients.
16
- */
17
- export type DefaultPeers = {
18
- [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;
19
- };
20
- /**
21
- * Attaches default peer clients to a resource.
22
- *
23
- * Default peers are only applied if the scope doesn't exist:
24
- * - Not defined in parent context
25
- * - Not provided by user
26
- * - Not already defined by a previous resource's default peers
27
- *
28
- * First definition wins - no overriding is permitted.
29
- *
30
- * @param resource - The resource to attach default peers to
31
- * @param peers - The default peer clients to attach
32
- * @throws Error if a peer key already exists in the resource's default peers
33
- *
34
- * @example
35
- * ```typescript
36
- * const ThreadListClient = resource(({ ... }) => { ... });
37
- *
38
- * attachDefaultPeers(ThreadListClient, {
39
- * // Derived default peers
40
- * thread: Derived({ source: "threads", query: { type: "main" }, get: ... }),
41
- * threadListItem: Derived({ ... }),
42
- * composer: Derived({ getMeta: ..., get: ... }),
43
- *
44
- * // Root default peers
45
- * tools: Tools({}),
46
- * modelContext: ModelContext({}),
47
- * });
48
- * ```
49
- */
50
- export declare function attachDefaultPeers<T extends (...args: any[]) => ResourceElement<any>>(resource: T, peers: DefaultPeers): void;
51
- /**
52
- * Gets the default peers attached to a resource, if any.
53
- */
54
- export declare function getDefaultPeers<T extends (...args: any[]) => ResourceElement<any>>(resource: T): DefaultPeers | undefined;
55
- export {};
56
- //# sourceMappingURL=attachDefaultPeers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attachDefaultPeers.d.ts","sourceRoot":"","sources":["../src/attachDefaultPeers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,0BAAuB;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAkB;AAEhD;;GAEG;AACH,QAAA,MAAM,aAAa,eAAuC,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,CAAC,aAAa,CAAC,CAAC,EAAE,YAAY,CAAC;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;KACxB,CAAC,IAAI,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;CAC1D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,eAAe,CAAC,GAAG,CAAC,EAClD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAaxC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,eAAe,CAAC,GAAG,CAAC,EAClD,QAAQ,EAAE,CAAC,GAAG,YAAY,GAAG,SAAS,CAEvC"}
@@ -1,51 +0,0 @@
1
- /**
2
- * Symbol used to store default peer clients on a resource.
3
- */
4
- const DEFAULT_PEERS = Symbol("assistant-ui.default-peers");
5
- /**
6
- * Attaches default peer clients to a resource.
7
- *
8
- * Default peers are only applied if the scope doesn't exist:
9
- * - Not defined in parent context
10
- * - Not provided by user
11
- * - Not already defined by a previous resource's default peers
12
- *
13
- * First definition wins - no overriding is permitted.
14
- *
15
- * @param resource - The resource to attach default peers to
16
- * @param peers - The default peer clients to attach
17
- * @throws Error if a peer key already exists in the resource's default peers
18
- *
19
- * @example
20
- * ```typescript
21
- * const ThreadListClient = resource(({ ... }) => { ... });
22
- *
23
- * attachDefaultPeers(ThreadListClient, {
24
- * // Derived default peers
25
- * thread: Derived({ source: "threads", query: { type: "main" }, get: ... }),
26
- * threadListItem: Derived({ ... }),
27
- * composer: Derived({ getMeta: ..., get: ... }),
28
- *
29
- * // Root default peers
30
- * tools: Tools({}),
31
- * modelContext: ModelContext({}),
32
- * });
33
- * ```
34
- */
35
- export function attachDefaultPeers(resource, peers) {
36
- const resourceWithPeers = resource;
37
- const existing = resourceWithPeers[DEFAULT_PEERS] ?? {};
38
- for (const key of Object.keys(peers)) {
39
- if (key in existing) {
40
- throw new Error(`Default peer "${key}" is already attached to this resource`);
41
- }
42
- }
43
- resourceWithPeers[DEFAULT_PEERS] = { ...existing, ...peers };
44
- }
45
- /**
46
- * Gets the default peers attached to a resource, if any.
47
- */
48
- export function getDefaultPeers(resource) {
49
- return resource[DEFAULT_PEERS];
50
- }
51
- //# sourceMappingURL=attachDefaultPeers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attachDefaultPeers.js","sourceRoot":"","sources":["../src/attachDefaultPeers.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AAgB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,kBAAkB,CAEhC,QAAW,EAAE,KAAmB;IAChC,MAAM,iBAAiB,GAAG,QAAwC,CAAC;IACnE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IAExD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,iBAAiB,GAAG,wCAAwC,CAC7D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,iBAAiB,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAE7B,QAAW;IACX,OAAQ,QAAyC,CAAC,aAAa,CAAC,CAAC;AACnE,CAAC"}