@assistant-ui/store 0.0.0

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/AssistantContext.d.ts +22 -0
  4. package/dist/AssistantContext.d.ts.map +1 -0
  5. package/dist/AssistantContext.js +44 -0
  6. package/dist/AssistantContext.js.map +1 -0
  7. package/dist/DerivedScope.d.ts +18 -0
  8. package/dist/DerivedScope.d.ts.map +1 -0
  9. package/dist/DerivedScope.js +11 -0
  10. package/dist/DerivedScope.js.map +1 -0
  11. package/dist/ScopeRegistry.d.ts +41 -0
  12. package/dist/ScopeRegistry.d.ts.map +1 -0
  13. package/dist/ScopeRegistry.js +17 -0
  14. package/dist/ScopeRegistry.js.map +1 -0
  15. package/dist/asStore.d.ts +20 -0
  16. package/dist/asStore.d.ts.map +1 -0
  17. package/dist/asStore.js +23 -0
  18. package/dist/asStore.js.map +1 -0
  19. package/dist/index.d.ts +13 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +20 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/tapApi.d.ts +36 -0
  24. package/dist/tapApi.d.ts.map +1 -0
  25. package/dist/tapApi.js +52 -0
  26. package/dist/tapApi.js.map +1 -0
  27. package/dist/tapLookupResources.d.ts +44 -0
  28. package/dist/tapLookupResources.d.ts.map +1 -0
  29. package/dist/tapLookupResources.js +21 -0
  30. package/dist/tapLookupResources.js.map +1 -0
  31. package/dist/tapStoreList.d.ts +76 -0
  32. package/dist/tapStoreList.d.ts.map +1 -0
  33. package/dist/tapStoreList.js +46 -0
  34. package/dist/tapStoreList.js.map +1 -0
  35. package/dist/types.d.ts +86 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +1 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/useAssistantClient.d.ts +42 -0
  40. package/dist/useAssistantClient.d.ts.map +1 -0
  41. package/dist/useAssistantClient.js +153 -0
  42. package/dist/useAssistantClient.js.map +1 -0
  43. package/dist/useAssistantState.d.ts +18 -0
  44. package/dist/useAssistantState.d.ts.map +1 -0
  45. package/dist/useAssistantState.js +53 -0
  46. package/dist/useAssistantState.js.map +1 -0
  47. package/dist/utils/splitScopes.d.ts +24 -0
  48. package/dist/utils/splitScopes.d.ts.map +1 -0
  49. package/dist/utils/splitScopes.js +18 -0
  50. package/dist/utils/splitScopes.js.map +1 -0
  51. package/package.json +50 -0
  52. package/src/AssistantContext.tsx +64 -0
  53. package/src/DerivedScope.ts +21 -0
  54. package/src/ScopeRegistry.ts +58 -0
  55. package/src/asStore.ts +40 -0
  56. package/src/index.ts +13 -0
  57. package/src/tapApi.ts +91 -0
  58. package/src/tapLookupResources.ts +62 -0
  59. package/src/tapStoreList.ts +133 -0
  60. package/src/types.ts +120 -0
  61. package/src/useAssistantClient.tsx +250 -0
  62. package/src/useAssistantState.tsx +80 -0
  63. package/src/utils/splitScopes.ts +38 -0
package/dist/tapApi.js ADDED
@@ -0,0 +1,52 @@
1
+ // src/tapApi.ts
2
+ import { tapEffect, tapMemo, tapRef } from "@assistant-ui/tap";
3
+ var ReadonlyApiHandler = class {
4
+ constructor(getApi) {
5
+ this.getApi = getApi;
6
+ }
7
+ get(_, prop) {
8
+ return this.getApi()[prop];
9
+ }
10
+ ownKeys() {
11
+ return Object.keys(this.getApi());
12
+ }
13
+ has(_, prop) {
14
+ return prop in this.getApi();
15
+ }
16
+ getOwnPropertyDescriptor(_, prop) {
17
+ return Object.getOwnPropertyDescriptor(this.getApi(), prop);
18
+ }
19
+ set() {
20
+ return false;
21
+ }
22
+ defineProperty() {
23
+ return false;
24
+ }
25
+ deleteProperty() {
26
+ return false;
27
+ }
28
+ };
29
+ var tapApi = (api, options) => {
30
+ const ref = tapRef(api);
31
+ tapEffect(() => {
32
+ ref.current = api;
33
+ });
34
+ const apiProxy = tapMemo(
35
+ () => new Proxy({}, new ReadonlyApiHandler(() => ref.current)),
36
+ []
37
+ );
38
+ const key = options?.key;
39
+ const state = api.getState();
40
+ return tapMemo(
41
+ () => ({
42
+ key,
43
+ state,
44
+ api: apiProxy
45
+ }),
46
+ [state, key]
47
+ );
48
+ };
49
+ export {
50
+ tapApi
51
+ };
52
+ //# sourceMappingURL=tapApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tapApi.ts"],"sourcesContent":["import { tapEffect, tapMemo, tapRef } from \"@assistant-ui/tap\";\n\n/**\n * API object type\n */\nexport interface ApiObject {\n [key: string]: ((...args: any[]) => any) | ApiObject;\n}\n\n/**\n * Readonly API handler for creating stable proxies\n */\nclass ReadonlyApiHandler<TApi extends ApiObject> implements ProxyHandler<TApi> {\n constructor(private readonly getApi: () => TApi) {}\n\n get(_: unknown, prop: string | symbol) {\n return this.getApi()[prop as keyof TApi];\n }\n\n ownKeys(): ArrayLike<string | symbol> {\n return Object.keys(this.getApi() as object);\n }\n\n has(_: unknown, prop: string | symbol) {\n return prop in (this.getApi() as object);\n }\n\n getOwnPropertyDescriptor(_: unknown, prop: string | symbol) {\n return Object.getOwnPropertyDescriptor(this.getApi(), prop);\n }\n\n set() {\n return false;\n }\n defineProperty() {\n return false;\n }\n deleteProperty() {\n return false;\n }\n}\n\n/**\n * Wraps an API object to make it stable across renders while keeping getState reactive.\n * This is the recommended pattern for scope resources.\n *\n * @example\n * ```typescript\n * export const FooResource = resource(() => {\n * const [state, setState] = tapState({ bar: \"Hello\" });\n *\n * const updateBar = (newBar: string) => {\n * setState({ bar: newBar });\n * };\n *\n * return tapApi({\n * getState: () => state,\n * updateBar,\n * });\n * });\n * ```\n */\nexport const tapApi = <TApi extends ApiObject & { getState: () => any }>(\n api: TApi,\n options?: {\n key?: string | undefined;\n },\n) => {\n const ref = tapRef(api);\n tapEffect(() => {\n ref.current = api;\n });\n\n const apiProxy = tapMemo(\n () =>\n new Proxy<TApi>({} as TApi, new ReadonlyApiHandler(() => ref.current)),\n [],\n );\n\n const key = options?.key;\n const state = api.getState();\n\n return tapMemo(\n () => ({\n key,\n state,\n api: apiProxy,\n }),\n [state, key],\n );\n};\n"],"mappings":";AAAA,SAAS,WAAW,SAAS,cAAc;AAY3C,IAAM,qBAAN,MAA+E;AAAA,EAC7E,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,IAAI,GAAY,MAAuB;AACrC,WAAO,KAAK,OAAO,EAAE,IAAkB;AAAA,EACzC;AAAA,EAEA,UAAsC;AACpC,WAAO,OAAO,KAAK,KAAK,OAAO,CAAW;AAAA,EAC5C;AAAA,EAEA,IAAI,GAAY,MAAuB;AACrC,WAAO,QAAS,KAAK,OAAO;AAAA,EAC9B;AAAA,EAEA,yBAAyB,GAAY,MAAuB;AAC1D,WAAO,OAAO,yBAAyB,KAAK,OAAO,GAAG,IAAI;AAAA,EAC5D;AAAA,EAEA,MAAM;AACJ,WAAO;AAAA,EACT;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AACF;AAsBO,IAAM,SAAS,CACpB,KACA,YAGG;AACH,QAAM,MAAM,OAAO,GAAG;AACtB,YAAU,MAAM;AACd,QAAI,UAAU;AAAA,EAChB,CAAC;AAED,QAAM,WAAW;AAAA,IACf,MACE,IAAI,MAAY,CAAC,GAAW,IAAI,mBAAmB,MAAM,IAAI,OAAO,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AAEA,QAAM,MAAM,SAAS;AACrB,QAAM,QAAQ,IAAI,SAAS;AAE3B,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,IACA,CAAC,OAAO,GAAG;AAAA,EACb;AACF;","names":[]}
@@ -0,0 +1,44 @@
1
+ import { ResourceElement } from "@assistant-ui/tap";
2
+ import { ApiObject } from "./tapApi";
3
+ /**
4
+ * Creates a lookup-based resource collection for managing lists of items.
5
+ * Returns both the combined state array and an API function to lookup specific items.
6
+ *
7
+ * @param elements - Array of resource elements, each returning { key, state, api }
8
+ * @returns Object with { state: TState[], api: (lookup) => TApi }
9
+ *
10
+ * The api function accepts { index: number } or { key: string } for lookups.
11
+ * Consumers can wrap it to rename the key field (e.g., to "id" or "toolCallId").
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const foos = tapLookupResources(
16
+ * items.map((item) => FooItem({ id: item.id }, { key: item.id }))
17
+ * );
18
+ *
19
+ * // Access state array
20
+ * const allStates = foos.state;
21
+ *
22
+ * // Wrap to rename key field to "id"
23
+ * const wrappedApi = (lookup: { index: number } | { id: string }) => {
24
+ * if ("id" in lookup) {
25
+ * return foos.api({ key: lookup.id });
26
+ * } else {
27
+ * return foos.api(lookup);
28
+ * }
29
+ * };
30
+ * ```
31
+ */
32
+ export declare const tapLookupResources: <TState, TApi extends ApiObject>(elements: ResourceElement<{
33
+ key: string | undefined;
34
+ state: TState;
35
+ api: TApi;
36
+ }>[]) => {
37
+ state: TState[];
38
+ api: (lookup: {
39
+ index: number;
40
+ } | {
41
+ key: string;
42
+ }) => TApi;
43
+ };
44
+ //# sourceMappingURL=tapLookupResources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapLookupResources.d.ts","sourceRoot":"","sources":["../src/tapLookupResources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,EAAE,IAAI,SAAS,SAAS,EAC/D,UAAU,eAAe,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,IAAI,CAAC;CACX,CAAC,EAAE,KACH;IACD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAqB5D,CAAC"}
@@ -0,0 +1,21 @@
1
+ // src/tapLookupResources.ts
2
+ import { tapResources } from "@assistant-ui/tap";
3
+ var tapLookupResources = (elements) => {
4
+ const resources = tapResources(elements);
5
+ return {
6
+ state: resources.map((r) => r.state),
7
+ api: (lookup) => {
8
+ const value = "index" in lookup ? resources[lookup.index]?.api : resources.find((r) => r.key === lookup.key)?.api;
9
+ if (!value) {
10
+ throw new Error(
11
+ `tapLookupResources: Resource not found for lookup: ${JSON.stringify(lookup)}`
12
+ );
13
+ }
14
+ return value;
15
+ }
16
+ };
17
+ };
18
+ export {
19
+ tapLookupResources
20
+ };
21
+ //# sourceMappingURL=tapLookupResources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tapLookupResources.ts"],"sourcesContent":["import { ResourceElement, tapResources } from \"@assistant-ui/tap\";\nimport { ApiObject } from \"./tapApi\";\n\n/**\n * Creates a lookup-based resource collection for managing lists of items.\n * Returns both the combined state array and an API function to lookup specific items.\n *\n * @param elements - Array of resource elements, each returning { key, state, api }\n * @returns Object with { state: TState[], api: (lookup) => TApi }\n *\n * The api function accepts { index: number } or { key: string } for lookups.\n * Consumers can wrap it to rename the key field (e.g., to \"id\" or \"toolCallId\").\n *\n * @example\n * ```typescript\n * const foos = tapLookupResources(\n * items.map((item) => FooItem({ id: item.id }, { key: item.id }))\n * );\n *\n * // Access state array\n * const allStates = foos.state;\n *\n * // Wrap to rename key field to \"id\"\n * const wrappedApi = (lookup: { index: number } | { id: string }) => {\n * if (\"id\" in lookup) {\n * return foos.api({ key: lookup.id });\n * } else {\n * return foos.api(lookup);\n * }\n * };\n * ```\n */\nexport const tapLookupResources = <TState, TApi extends ApiObject>(\n elements: ResourceElement<{\n key: string | undefined;\n state: TState;\n api: TApi;\n }>[],\n): {\n state: TState[];\n api: (lookup: { index: number } | { key: string }) => TApi;\n} => {\n const resources = tapResources(elements);\n\n return {\n state: resources.map((r) => r.state),\n api: (lookup: { index: number } | { key: string }) => {\n const value =\n \"index\" in lookup\n ? resources[lookup.index]?.api\n : resources.find((r) => r.key === lookup.key)?.api;\n\n if (!value) {\n throw new Error(\n `tapLookupResources: Resource not found for lookup: ${JSON.stringify(lookup)}`,\n );\n }\n\n return value;\n },\n };\n};\n"],"mappings":";AAAA,SAA0B,oBAAoB;AAgCvC,IAAM,qBAAqB,CAChC,aAQG;AACH,QAAM,YAAY,aAAa,QAAQ;AAEvC,SAAO;AAAA,IACL,OAAO,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,IACnC,KAAK,CAAC,WAAgD;AACpD,YAAM,QACJ,WAAW,SACP,UAAU,OAAO,KAAK,GAAG,MACzB,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,OAAO,GAAG,GAAG;AAEnD,UAAI,CAAC,OAAO;AACV,cAAM,IAAI;AAAA,UACR,sDAAsD,KAAK,UAAU,MAAM,CAAC;AAAA,QAC9E;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,76 @@
1
+ import type { ContravariantResource } from "@assistant-ui/tap";
2
+ import { ApiObject } from "./tapApi";
3
+ /**
4
+ * Resource props that will be passed to each item resource
5
+ */
6
+ export type TapStoreListResourceProps<TProps> = {
7
+ initialValue: TProps;
8
+ remove: () => void;
9
+ };
10
+ /**
11
+ * Configuration for tapStoreList hook
12
+ */
13
+ export type TapStoreListConfig<TProps, TState, TApi extends ApiObject> = {
14
+ /**
15
+ * Initial values for the list items
16
+ */
17
+ initialValues: TProps[];
18
+ /**
19
+ * Resource function that creates an element for each item
20
+ * Should return a ResourceElement with { key, state, api }
21
+ *
22
+ * The resource will receive { initialValue, remove } as props.
23
+ */
24
+ resource: ContravariantResource<{
25
+ key: string | undefined;
26
+ state: TState;
27
+ api: TApi;
28
+ }, TapStoreListResourceProps<TProps>>;
29
+ /**
30
+ * Optional ID generator function for new items
31
+ * If not provided, items must include an ID when added
32
+ */
33
+ idGenerator?: () => string;
34
+ };
35
+ /**
36
+ * Creates a stateful list with add functionality, rendering each item via the provided resource.
37
+ * Returns state array, api lookup function, and add method.
38
+ *
39
+ * @param config - Configuration object with initialValues, resource, and optional idGenerator
40
+ * @returns Object with { state: TState[], api: (lookup) => TApi, add: (id?) => void }
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const todoList = tapStoreList({
45
+ * initialValues: [
46
+ * { id: "1", text: "First todo" },
47
+ * { id: "2", text: "Second todo" }
48
+ * ],
49
+ * resource: (props) => TodoItemResource(props, { key: props.id }),
50
+ * idGenerator: () => `todo-${Date.now()}`
51
+ * });
52
+ *
53
+ * // Access state array
54
+ * const allTodos = todoList.state;
55
+ *
56
+ * // Lookup specific item
57
+ * const firstTodo = todoList.api({ index: 0 });
58
+ * const specificTodo = todoList.api({ key: "1" });
59
+ *
60
+ * // Add new item
61
+ * todoList.add(); // Uses idGenerator
62
+ * todoList.add("custom-id"); // Uses provided id
63
+ * ```
64
+ */
65
+ export declare const tapStoreList: <TProps extends {
66
+ id: string;
67
+ }, TState, TApi extends ApiObject>(config: TapStoreListConfig<TProps, TState, TApi>) => {
68
+ state: TState[];
69
+ api: (lookup: {
70
+ index: number;
71
+ } | {
72
+ id: string;
73
+ }) => TApi;
74
+ add: (id?: string) => void;
75
+ };
76
+ //# sourceMappingURL=tapStoreList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapStoreList.d.ts","sourceRoot":"","sources":["../src/tapStoreList.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC;;GAEG;AACH,MAAM,MAAM,yBAAyB,CAAC,MAAM,IAAI;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAS,SAAS,IAAI;IACvE;;OAEG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAMxB;;;;;OAKG;IACH,QAAQ,EAAE,qBAAqB,CAC7B;QACE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,IAAI,CAAC;KACX,EACD,yBAAyB,CAAC,MAAM,CAAC,CAClC,CAAC;IACF;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAC7B,MAAM,EACN,IAAI,SAAS,SAAS,EAEtB,QAAQ,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,KAC/C;IACD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1D,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CA8C5B,CAAC"}
@@ -0,0 +1,46 @@
1
+ // src/tapStoreList.ts
2
+ import { tapState } from "@assistant-ui/tap";
3
+ import { tapLookupResources } from "./tapLookupResources.js";
4
+ var tapStoreList = (config) => {
5
+ const { initialValues, resource: Resource, idGenerator } = config;
6
+ const [items, setItems] = tapState(initialValues);
7
+ const lookup = tapLookupResources(
8
+ items.map(
9
+ (item) => Resource(
10
+ {
11
+ initialValue: item,
12
+ remove: () => {
13
+ setItems(items.filter((i) => i !== item));
14
+ }
15
+ },
16
+ {
17
+ key: item.id
18
+ }
19
+ )
20
+ )
21
+ );
22
+ const add = (id) => {
23
+ const newId = id ?? idGenerator?.();
24
+ if (!newId) {
25
+ throw new Error(
26
+ "tapStoreList: Either provide an id to add() or configure an idGenerator"
27
+ );
28
+ }
29
+ const newItem = { id: newId };
30
+ setItems([...items, newItem]);
31
+ };
32
+ return {
33
+ state: lookup.state,
34
+ api: (query) => {
35
+ if ("index" in query) {
36
+ return lookup.api({ index: query.index });
37
+ }
38
+ return lookup.api({ key: query.id });
39
+ },
40
+ add
41
+ };
42
+ };
43
+ export {
44
+ tapStoreList
45
+ };
46
+ //# sourceMappingURL=tapStoreList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tapStoreList.ts"],"sourcesContent":["import { tapState } from \"@assistant-ui/tap\";\nimport type { ContravariantResource } from \"@assistant-ui/tap\";\nimport { tapLookupResources } from \"./tapLookupResources\";\nimport { ApiObject } from \"./tapApi\";\n\n/**\n * Resource props that will be passed to each item resource\n */\nexport type TapStoreListResourceProps<TProps> = {\n initialValue: TProps;\n remove: () => void;\n};\n\n/**\n * Configuration for tapStoreList hook\n */\nexport type TapStoreListConfig<TProps, TState, TApi extends ApiObject> = {\n /**\n * Initial values for the list items\n */\n initialValues: TProps[];\n\n // TODO we can't use Resource type here because of contravariance\n // I think we need a special type in tap that correctly handles the contravariance\n // or change the behavior of the Resource type\n\n /**\n * Resource function that creates an element for each item\n * Should return a ResourceElement with { key, state, api }\n *\n * The resource will receive { initialValue, remove } as props.\n */\n resource: ContravariantResource<\n {\n key: string | undefined;\n state: TState;\n api: TApi;\n },\n TapStoreListResourceProps<TProps>\n >;\n /**\n * Optional ID generator function for new items\n * If not provided, items must include an ID when added\n */\n idGenerator?: () => string;\n};\n\n/**\n * Creates a stateful list with add functionality, rendering each item via the provided resource.\n * Returns state array, api lookup function, and add method.\n *\n * @param config - Configuration object with initialValues, resource, and optional idGenerator\n * @returns Object with { state: TState[], api: (lookup) => TApi, add: (id?) => void }\n *\n * @example\n * ```typescript\n * const todoList = tapStoreList({\n * initialValues: [\n * { id: \"1\", text: \"First todo\" },\n * { id: \"2\", text: \"Second todo\" }\n * ],\n * resource: (props) => TodoItemResource(props, { key: props.id }),\n * idGenerator: () => `todo-${Date.now()}`\n * });\n *\n * // Access state array\n * const allTodos = todoList.state;\n *\n * // Lookup specific item\n * const firstTodo = todoList.api({ index: 0 });\n * const specificTodo = todoList.api({ key: \"1\" });\n *\n * // Add new item\n * todoList.add(); // Uses idGenerator\n * todoList.add(\"custom-id\"); // Uses provided id\n * ```\n */\nexport const tapStoreList = <\n TProps extends { id: string },\n TState,\n TApi extends ApiObject,\n>(\n config: TapStoreListConfig<TProps, TState, TApi>,\n): {\n state: TState[];\n api: (lookup: { index: number } | { id: string }) => TApi;\n add: (id?: string) => void;\n} => {\n const { initialValues, resource: Resource, idGenerator } = config;\n\n const [items, setItems] = tapState<TProps[]>(initialValues);\n\n const lookup = tapLookupResources(\n items.map((item) =>\n Resource(\n {\n initialValue: item,\n remove: () => {\n setItems(items.filter((i) => i !== item));\n },\n },\n {\n key: item.id,\n },\n ),\n ),\n );\n\n const add = (id?: string) => {\n const newId = id ?? idGenerator?.();\n if (!newId) {\n throw new Error(\n \"tapStoreList: Either provide an id to add() or configure an idGenerator\",\n );\n }\n\n // Create a new item with the generated/provided id\n // This assumes TProps has an 'id' field - users will need to ensure their props type supports this\n const newItem = { id: newId } as TProps;\n setItems([...items, newItem]);\n };\n\n return {\n state: lookup.state,\n api: (query: { index: number } | { id: string }) => {\n if (\"index\" in query) {\n return lookup.api({ index: query.index });\n }\n return lookup.api({ key: query.id });\n },\n add,\n };\n};\n"],"mappings":";AAAA,SAAS,gBAAgB;AAEzB,SAAS,0BAA0B;AA2E5B,IAAM,eAAe,CAK1B,WAKG;AACH,QAAM,EAAE,eAAe,UAAU,UAAU,YAAY,IAAI;AAE3D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB,aAAa;AAE1D,QAAM,SAAS;AAAA,IACb,MAAM;AAAA,MAAI,CAAC,SACT;AAAA,QACE;AAAA,UACE,cAAc;AAAA,UACd,QAAQ,MAAM;AACZ,qBAAS,MAAM,OAAO,CAAC,MAAM,MAAM,IAAI,CAAC;AAAA,UAC1C;AAAA,QACF;AAAA,QACA;AAAA,UACE,KAAK,KAAK;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,CAAC,OAAgB;AAC3B,UAAM,QAAQ,MAAM,cAAc;AAClC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAIA,UAAM,UAAU,EAAE,IAAI,MAAM;AAC5B,aAAS,CAAC,GAAG,OAAO,OAAO,CAAC;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,KAAK,CAAC,UAA8C;AAClD,UAAI,WAAW,OAAO;AACpB,eAAO,OAAO,IAAI,EAAE,OAAO,MAAM,MAAM,CAAC;AAAA,MAC1C;AACA,aAAO,OAAO,IAAI,EAAE,KAAK,MAAM,GAAG,CAAC;AAAA,IACrC;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,86 @@
1
+ import type { ResourceElement } from "@assistant-ui/tap";
2
+ /**
3
+ * Module augmentation interface for assistant-ui store type extensions.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * declare module "@assistant-ui/store" {
8
+ * interface AssistantScopeRegistry {
9
+ * foo: {
10
+ * value: { getState: () => { bar: string }; updateBar: (bar: string) => void };
11
+ * source: "root";
12
+ * query: Record<string, never>;
13
+ * };
14
+ * }
15
+ * }
16
+ * ```
17
+ */
18
+ export interface AssistantScopeRegistry {
19
+ }
20
+ export type AssistantScopes = keyof AssistantScopeRegistry extends never ? Record<"ERROR: No scopes were defined", ScopeDefinition> : {
21
+ [K in keyof AssistantScopeRegistry]: AssistantScopeRegistry[K];
22
+ };
23
+ /**
24
+ * Helper type to extract the value type from a scope definition
25
+ */
26
+ export type ScopeValue<T extends ScopeDefinition> = T["value"];
27
+ /**
28
+ * Helper type to extract the source type from a scope definition
29
+ */
30
+ export type ScopeSource<T extends ScopeDefinition> = T["source"];
31
+ /**
32
+ * Helper type to extract the query type from a scope definition
33
+ */
34
+ export type ScopeQuery<T extends ScopeDefinition> = T["query"];
35
+ /**
36
+ * Type for a scope field - a function that returns the current API value,
37
+ * with source and query metadata attached
38
+ */
39
+ export type ScopeField<T extends ScopeDefinition> = (() => ScopeValue<T>) & ({
40
+ source: ScopeSource<T>;
41
+ query: ScopeQuery<T>;
42
+ } | {
43
+ source: null;
44
+ query: null;
45
+ });
46
+ /**
47
+ * Props passed to a derived scope resource element
48
+ */
49
+ export type DerivedScopeProps<T extends ScopeDefinition> = {
50
+ get: (parent: AssistantClient) => ScopeValue<T>;
51
+ source: ScopeSource<T>;
52
+ query: ScopeQuery<T>;
53
+ };
54
+ /**
55
+ * Input type for scope definitions - ResourceElement that returns the API value
56
+ * Can optionally include source/query metadata via DerivedScope
57
+ */
58
+ export type ScopeInput<T extends ScopeDefinition> = ResourceElement<{
59
+ api: ScopeValue<T>;
60
+ }>;
61
+ /**
62
+ * Map of scope names to their input definitions
63
+ */
64
+ export type ScopesInput = {
65
+ [K in keyof AssistantScopes]?: ScopeInput<AssistantScopes[K]>;
66
+ };
67
+ /**
68
+ * Unsubscribe function type
69
+ */
70
+ export type Unsubscribe = () => void;
71
+ /**
72
+ * State type extracted from all scopes
73
+ */
74
+ export type AssistantState = {
75
+ [K in keyof AssistantScopes]: ReturnType<AssistantScopes[K]["value"]["getState"]>;
76
+ };
77
+ /**
78
+ * The assistant client type with all registered scopes
79
+ */
80
+ export type AssistantClient = {
81
+ [K in keyof AssistantScopes]: ScopeField<AssistantScopes[K]>;
82
+ } & {
83
+ subscribe(listener: () => void): Unsubscribe;
84
+ flushSync(): void;
85
+ };
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAmBzD;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,sBAAsB;CAAG;AAE1C,MAAM,MAAM,eAAe,GAAG,MAAM,sBAAsB,SAAS,KAAK,GACpE,MAAM,CAAC,+BAA+B,EAAE,eAAe,CAAC,GACxD;KAAG,CAAC,IAAI,MAAM,sBAAsB,GAAG,sBAAsB,CAAC,CAAC,CAAC;CAAE,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;AAE/D;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,GACvE,CACI;IACE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CACtB,GACD;IACE,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,IAAI,CAAC;CACb,CACJ,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,eAAe,IAAI;IACzD,GAAG,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,eAAe,CAAC;IAClE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CACpB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;KACvB,CAAC,IAAI,MAAM,eAAe,CAAC,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAC9D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;KAC1B,CAAC,IAAI,MAAM,eAAe,GAAG,UAAU,CACtC,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CACxC;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;KAC3B,CAAC,IAAI,MAAM,eAAe,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAC7D,GAAG;IACF,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,WAAW,CAAC;IAC7C,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,42 @@
1
+ import type { AssistantClient, AssistantScopes, ScopesInput, ScopeField } from "./types";
2
+ /**
3
+ * Hook to mount and access root scopes
4
+ */
5
+ export declare const useRootScopes: (rootScopes: ScopesInput) => {
6
+ scopes: {};
7
+ subscribe?: never;
8
+ flushSync?: never;
9
+ } | {
10
+ scopes: { [K in "ERROR: No scopes were defined"]: ScopeField<AssistantScopes[K]>; };
11
+ subscribe: (callback: () => void) => () => void;
12
+ flushSync: () => void;
13
+ };
14
+ /**
15
+ * Hook to mount and access derived scopes
16
+ */
17
+ export declare const useDerivedScopes: (derivedScopes: ScopesInput, parentClient: AssistantClient) => {
18
+ "ERROR: No scopes were defined"?: ScopeField<import("./types").ScopeDefinition<any, any, any>>;
19
+ };
20
+ /**
21
+ * Hook to access or extend the AssistantClient
22
+ *
23
+ * @example Without config - returns the client from context:
24
+ * ```typescript
25
+ * const client = useAssistantClient();
26
+ * const fooState = client.foo.getState();
27
+ * ```
28
+ *
29
+ * @example With config - creates a new client with additional scopes:
30
+ * ```typescript
31
+ * const client = useAssistantClient({
32
+ * message: DerivedScope({
33
+ * source: "thread",
34
+ * query: { type: "index", index: 0 },
35
+ * get: () => messageApi,
36
+ * }),
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function useAssistantClient(): AssistantClient;
41
+ export declare function useAssistantClient(scopes: ScopesInput): AssistantClient;
42
+ //# sourceMappingURL=useAssistantClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssistantClient.d.ts","sourceRoot":"","sources":["../src/useAssistantClient.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,WAAW,EACX,UAAU,EAGX,MAAM,SAAS,CAAC;AA6FjB;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,WAAW;;;;;YA1B1C,GACF,CAAC,mCAAuB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAC3D;0BACqB,MAAM,IAAI;;CAyBrC,CAAC;AAqEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,eAAe,WAAW,EAC1B,cAAc,eAAe;;CAK9B,CAAC;AAyBF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAAC;AACtD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC"}
@@ -0,0 +1,153 @@
1
+ // src/useAssistantClient.tsx
2
+ import { useMemo } from "react";
3
+ import { useResource } from "@assistant-ui/tap/react";
4
+ import {
5
+ resource,
6
+ tapMemo,
7
+ tapResource,
8
+ tapResources,
9
+ tapEffectEvent
10
+ } from "@assistant-ui/tap";
11
+ import { asStore } from "./asStore.js";
12
+ import { useAssistantContextValue } from "./AssistantContext.js";
13
+ import { splitScopes } from "./utils/splitScopes.js";
14
+ var RootScopeResource = resource(
15
+ ({
16
+ scopeName,
17
+ element
18
+ }) => {
19
+ const store = tapResource(asStore(element));
20
+ return tapMemo(() => {
21
+ const scopeFunction = (() => store.getState().api);
22
+ scopeFunction.source = "root";
23
+ scopeFunction.query = {};
24
+ return [
25
+ scopeName,
26
+ {
27
+ scopeFunction,
28
+ subscribe: store.subscribe,
29
+ flushSync: store.flushSync
30
+ }
31
+ ];
32
+ }, [scopeName, store]);
33
+ }
34
+ );
35
+ var RootScopesResource = resource((scopes) => {
36
+ const resultEntries = tapResources(
37
+ Object.entries(scopes).map(
38
+ ([scopeName, element]) => RootScopeResource(
39
+ {
40
+ scopeName,
41
+ element
42
+ },
43
+ { key: scopeName }
44
+ )
45
+ )
46
+ );
47
+ return tapMemo(() => {
48
+ if (resultEntries.length === 0) {
49
+ return {
50
+ scopes: {}
51
+ };
52
+ }
53
+ return {
54
+ scopes: Object.fromEntries(
55
+ resultEntries.map(([scopeName, { scopeFunction }]) => [
56
+ scopeName,
57
+ scopeFunction
58
+ ])
59
+ ),
60
+ subscribe: (callback) => {
61
+ const unsubscribes = resultEntries.map(([, { subscribe }]) => {
62
+ return subscribe(() => {
63
+ console.log("Callback called for");
64
+ callback();
65
+ });
66
+ });
67
+ return () => {
68
+ unsubscribes.forEach((unsubscribe) => unsubscribe());
69
+ };
70
+ },
71
+ flushSync: () => {
72
+ resultEntries.forEach(([, { flushSync }]) => {
73
+ flushSync();
74
+ });
75
+ }
76
+ };
77
+ }, [...resultEntries]);
78
+ });
79
+ var useRootScopes = (rootScopes) => {
80
+ return useResource(RootScopesResource(rootScopes));
81
+ };
82
+ var DerivedScopeResource = resource(
83
+ ({
84
+ scopeName,
85
+ element,
86
+ parentClient
87
+ }) => {
88
+ const get = tapEffectEvent(element.props.get);
89
+ const source = element.props.source;
90
+ const query = element.props.query;
91
+ return tapMemo(() => {
92
+ const scopeFunction = (() => get(parentClient));
93
+ scopeFunction.source = source;
94
+ scopeFunction.query = query;
95
+ return [scopeName, scopeFunction];
96
+ }, [scopeName, get, source, JSON.stringify(query), parentClient]);
97
+ }
98
+ );
99
+ var DerivedScopesResource = resource(
100
+ ({
101
+ scopes,
102
+ parentClient
103
+ }) => {
104
+ const resultEntries = tapResources(
105
+ Object.entries(scopes).map(
106
+ ([scopeName, element]) => DerivedScopeResource(
107
+ {
108
+ scopeName,
109
+ element,
110
+ parentClient
111
+ },
112
+ { key: scopeName }
113
+ )
114
+ )
115
+ );
116
+ return tapMemo(() => {
117
+ return Object.fromEntries(resultEntries);
118
+ }, [...resultEntries]);
119
+ }
120
+ );
121
+ var useDerivedScopes = (derivedScopes, parentClient) => {
122
+ return useResource(
123
+ DerivedScopesResource({ scopes: derivedScopes, parentClient })
124
+ );
125
+ };
126
+ var useExtendedAssistantClientImpl = (scopes) => {
127
+ const baseClient = useAssistantContextValue();
128
+ const { rootScopes, derivedScopes } = splitScopes(scopes);
129
+ const rootFields = useRootScopes(rootScopes);
130
+ const derivedFields = useDerivedScopes(derivedScopes, baseClient);
131
+ return useMemo(() => {
132
+ return {
133
+ ...baseClient,
134
+ ...rootFields.scopes,
135
+ ...derivedFields,
136
+ subscribe: rootFields.subscribe ?? baseClient.subscribe,
137
+ flushSync: rootFields.flushSync ?? baseClient.flushSync
138
+ };
139
+ }, [baseClient, rootFields, derivedFields]);
140
+ };
141
+ function useAssistantClient(scopes) {
142
+ if (scopes) {
143
+ return useExtendedAssistantClientImpl(scopes);
144
+ } else {
145
+ return useAssistantContextValue();
146
+ }
147
+ }
148
+ export {
149
+ useAssistantClient,
150
+ useDerivedScopes,
151
+ useRootScopes
152
+ };
153
+ //# sourceMappingURL=useAssistantClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/useAssistantClient.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useResource } from \"@assistant-ui/tap/react\";\nimport {\n resource,\n tapMemo,\n tapResource,\n tapResources,\n tapEffectEvent,\n ResourceElement,\n} from \"@assistant-ui/tap\";\nimport type {\n AssistantClient,\n AssistantScopes,\n ScopesInput,\n ScopeField,\n ScopeInput,\n DerivedScopeProps,\n} from \"./types\";\nimport { asStore } from \"./asStore\";\nimport { useAssistantContextValue } from \"./AssistantContext\";\nimport { splitScopes } from \"./utils/splitScopes\";\n\n/**\n * Resource for a single root scope\n * Returns a tuple of [scopeName, {scopeFunction, subscribe, flushSync}]\n */\nconst RootScopeResource = resource(\n <K extends keyof AssistantScopes>({\n scopeName,\n element,\n }: {\n scopeName: K;\n element: ScopeInput<AssistantScopes[K]>;\n }) => {\n const store = tapResource(asStore(element));\n\n return tapMemo(() => {\n const scopeFunction = (() => store.getState().api) as ScopeField<\n AssistantScopes[K]\n >;\n scopeFunction.source = \"root\";\n scopeFunction.query = {} as AssistantScopes[K][\"query\"];\n\n return [\n scopeName,\n {\n scopeFunction,\n subscribe: store.subscribe,\n flushSync: store.flushSync,\n },\n ] as const;\n }, [scopeName, store]);\n },\n);\n\n/**\n * Resource for all root scopes\n * Mounts each root scope and returns an object mapping scope names to their stores\n */\nconst RootScopesResource = resource((scopes: ScopesInput) => {\n const resultEntries = tapResources(\n Object.entries(scopes).map(([scopeName, element]) =>\n RootScopeResource(\n {\n scopeName: scopeName as keyof AssistantScopes,\n element: element as ScopeInput<\n AssistantScopes[keyof AssistantScopes]\n >,\n },\n { key: scopeName },\n ),\n ),\n );\n\n return tapMemo(() => {\n if (resultEntries.length === 0) {\n return {\n scopes: {},\n };\n }\n\n return {\n scopes: Object.fromEntries(\n resultEntries.map(([scopeName, { scopeFunction }]) => [\n scopeName,\n scopeFunction,\n ]),\n ) as {\n [K in keyof typeof scopes]: ScopeField<AssistantScopes[K]>;\n },\n subscribe: (callback: () => void) => {\n const unsubscribes = resultEntries.map(([, { subscribe }]) => {\n return subscribe(() => {\n console.log(\"Callback called for\");\n callback();\n });\n });\n return () => {\n unsubscribes.forEach((unsubscribe) => unsubscribe());\n };\n },\n flushSync: () => {\n resultEntries.forEach(([, { flushSync }]) => {\n flushSync();\n });\n },\n };\n }, [...resultEntries]);\n});\n\n/**\n * Hook to mount and access root scopes\n */\nexport const useRootScopes = (rootScopes: ScopesInput) => {\n return useResource(RootScopesResource(rootScopes));\n};\n\n/**\n * Resource for a single derived scope\n * Returns a tuple of [scopeName, scopeFunction] where scopeFunction has source and query\n */\nconst DerivedScopeResource = resource(\n <K extends keyof AssistantScopes>({\n scopeName,\n element,\n parentClient,\n }: {\n scopeName: K;\n element: ResourceElement<\n AssistantScopes[K],\n DerivedScopeProps<AssistantScopes[K]>\n >;\n parentClient: AssistantClient;\n }) => {\n const get = tapEffectEvent(element.props.get);\n const source = element.props.source;\n const query = element.props.query;\n return tapMemo(() => {\n const scopeFunction = (() => get(parentClient)) as ScopeField<\n AssistantScopes[K]\n >;\n scopeFunction.source = source;\n scopeFunction.query = query;\n\n return [scopeName, scopeFunction] as const;\n }, [scopeName, get, source, JSON.stringify(query), parentClient]);\n },\n);\n\n/**\n * Resource for all derived scopes\n * Builds stable scope functions with source and query metadata\n */\nconst DerivedScopesResource = resource(\n ({\n scopes,\n parentClient,\n }: {\n scopes: ScopesInput;\n parentClient: AssistantClient;\n }) => {\n const resultEntries = tapResources(\n Object.entries(scopes).map(([scopeName, element]) =>\n DerivedScopeResource(\n {\n scopeName: scopeName as keyof AssistantScopes,\n element: element as ScopeInput<\n AssistantScopes[keyof AssistantScopes]\n >,\n parentClient,\n },\n { key: scopeName },\n ),\n ),\n );\n\n return tapMemo(() => {\n return Object.fromEntries(resultEntries) as {\n [K in keyof typeof scopes]: ScopeField<AssistantScopes[K]>;\n };\n }, [...resultEntries]);\n },\n);\n\n/**\n * Hook to mount and access derived scopes\n */\nexport const useDerivedScopes = (\n derivedScopes: ScopesInput,\n parentClient: AssistantClient,\n) => {\n return useResource(\n DerivedScopesResource({ scopes: derivedScopes, parentClient }),\n );\n};\n\nconst useExtendedAssistantClientImpl = (\n scopes: ScopesInput,\n): AssistantClient => {\n const baseClient = useAssistantContextValue();\n const { rootScopes, derivedScopes } = splitScopes(scopes);\n\n // Mount the scopes to keep them alive\n const rootFields = useRootScopes(rootScopes);\n const derivedFields = useDerivedScopes(derivedScopes, baseClient);\n\n return useMemo(() => {\n // Merge base client with extended client\n // If baseClient is the default proxy, spreading it will be a no-op\n return {\n ...baseClient,\n ...rootFields.scopes,\n ...derivedFields,\n subscribe: rootFields.subscribe ?? baseClient.subscribe,\n flushSync: rootFields.flushSync ?? baseClient.flushSync,\n } as AssistantClient;\n }, [baseClient, rootFields, derivedFields]);\n};\n\n/**\n * Hook to access or extend the AssistantClient\n *\n * @example Without config - returns the client from context:\n * ```typescript\n * const client = useAssistantClient();\n * const fooState = client.foo.getState();\n * ```\n *\n * @example With config - creates a new client with additional scopes:\n * ```typescript\n * const client = useAssistantClient({\n * message: DerivedScope({\n * source: \"thread\",\n * query: { type: \"index\", index: 0 },\n * get: () => messageApi,\n * }),\n * });\n * ```\n */\nexport function useAssistantClient(): AssistantClient;\nexport function useAssistantClient(scopes: ScopesInput): AssistantClient;\nexport function useAssistantClient(scopes?: ScopesInput): AssistantClient {\n if (scopes) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useExtendedAssistantClientImpl(scopes);\n } else {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useAssistantContextValue();\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,18 @@
1
+ import type { AssistantState } from "./types";
2
+ /**
3
+ * Hook to access a slice of the assistant state with automatic subscription
4
+ *
5
+ * @param selector - Function to select a slice of the state
6
+ * @returns The selected state slice
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const client = useAssistantClient({
11
+ * foo: RootScope({ ... }),
12
+ * });
13
+ *
14
+ * const bar = useAssistantState((state) => state.foo.bar);
15
+ * ```
16
+ */
17
+ export declare const useAssistantState: <T>(selector: (state: AssistantState) => T) => T;
18
+ //# sourceMappingURL=useAssistantState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssistantState.d.ts","sourceRoot":"","sources":["../src/useAssistantState.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,SAAS,CAAC;AAsC/D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,UAAU,CAAC,KAAK,EAAE,cAAc,KAAK,CAAC,KACrC,CAuBF,CAAC"}