@assistant-ui/store 0.2.0 → 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 (110) hide show
  1. package/dist/AuiIf.d.ts +1 -1
  2. package/dist/AuiIf.d.ts.map +1 -1
  3. package/dist/Derived.d.ts +34 -0
  4. package/dist/Derived.d.ts.map +1 -0
  5. package/dist/Derived.js +24 -0
  6. package/dist/Derived.js.map +1 -0
  7. package/dist/attachTransformScopes.d.ts +11 -0
  8. package/dist/attachTransformScopes.d.ts.map +1 -0
  9. package/dist/attachTransformScopes.js +12 -0
  10. package/dist/attachTransformScopes.js.map +1 -0
  11. package/dist/index.d.ts +9 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +11 -4
  14. package/dist/index.js.map +1 -1
  15. package/dist/tapClientList.d.ts +28 -0
  16. package/dist/tapClientList.d.ts.map +1 -0
  17. package/dist/tapClientList.js +68 -0
  18. package/dist/tapClientList.js.map +1 -0
  19. package/dist/tapClientLookup.d.ts +15 -0
  20. package/dist/tapClientLookup.d.ts.map +1 -0
  21. package/dist/tapClientLookup.js +42 -0
  22. package/dist/tapClientLookup.js.map +1 -0
  23. package/dist/tapClientResource.d.ts +13 -0
  24. package/dist/tapClientResource.d.ts.map +1 -0
  25. package/dist/tapClientResource.js +114 -0
  26. package/dist/tapClientResource.js.map +1 -0
  27. package/dist/types/client.d.ts +115 -0
  28. package/dist/types/client.d.ts.map +1 -0
  29. package/dist/types/client.js +2 -0
  30. package/dist/types/client.js.map +1 -0
  31. package/dist/types/events.d.ts +33 -0
  32. package/dist/types/events.d.ts.map +1 -0
  33. package/dist/types/events.js +8 -0
  34. package/dist/types/events.js.map +1 -0
  35. package/dist/useAui.d.ts +5 -3
  36. package/dist/useAui.d.ts.map +1 -1
  37. package/dist/useAui.js +7 -2
  38. package/dist/useAui.js.map +1 -1
  39. package/dist/useAuiEvent.d.ts +1 -1
  40. package/dist/useAuiEvent.d.ts.map +1 -1
  41. package/dist/useAuiEvent.js +1 -1
  42. package/dist/useAuiEvent.js.map +1 -1
  43. package/dist/useAuiState.d.ts +2 -2
  44. package/dist/useAuiState.d.ts.map +1 -1
  45. package/dist/useAuiState.js +2 -2
  46. package/dist/useAuiState.js.map +1 -1
  47. package/dist/utils/BaseProxyHandler.d.ts +23 -0
  48. package/dist/utils/BaseProxyHandler.d.ts.map +1 -0
  49. package/dist/utils/BaseProxyHandler.js +46 -0
  50. package/dist/utils/BaseProxyHandler.js.map +1 -0
  51. package/dist/utils/NotificationManager.d.ts +11 -0
  52. package/dist/utils/NotificationManager.d.ts.map +1 -0
  53. package/dist/utils/NotificationManager.js +84 -0
  54. package/dist/utils/NotificationManager.js.map +1 -0
  55. package/dist/utils/proxied-assistant-state.d.ts +8 -0
  56. package/dist/utils/proxied-assistant-state.d.ts.map +1 -0
  57. package/dist/utils/proxied-assistant-state.js +34 -0
  58. package/dist/utils/proxied-assistant-state.js.map +1 -0
  59. package/dist/utils/react-assistant-context.d.ts +1 -1
  60. package/dist/utils/react-assistant-context.d.ts.map +1 -1
  61. package/dist/utils/react-assistant-context.js +2 -1
  62. package/dist/utils/react-assistant-context.js.map +1 -1
  63. package/dist/utils/splitClients.d.ts +10 -0
  64. package/dist/utils/splitClients.d.ts.map +1 -0
  65. package/dist/utils/splitClients.js +53 -0
  66. package/dist/utils/splitClients.js.map +1 -0
  67. package/dist/utils/tap-assistant-context.d.ts +19 -0
  68. package/dist/utils/tap-assistant-context.d.ts.map +1 -0
  69. package/dist/utils/tap-assistant-context.js +23 -0
  70. package/dist/utils/tap-assistant-context.js.map +1 -0
  71. package/dist/utils/tap-client-stack-context.d.ts +23 -0
  72. package/dist/utils/tap-client-stack-context.d.ts.map +1 -0
  73. package/dist/utils/tap-client-stack-context.js +28 -0
  74. package/dist/utils/tap-client-stack-context.js.map +1 -0
  75. package/dist/wrapperResource.d.ts +3 -0
  76. package/dist/wrapperResource.d.ts.map +1 -0
  77. package/dist/wrapperResource.js +11 -0
  78. package/dist/wrapperResource.js.map +1 -0
  79. package/package.json +5 -5
  80. package/src/AuiIf.ts +1 -1
  81. package/src/Derived.ts +46 -0
  82. package/src/__tests__/hooks.test.tsx +1 -1
  83. package/src/attachTransformScopes.ts +38 -0
  84. package/src/index.ts +37 -21
  85. package/src/tapClientList.ts +121 -0
  86. package/src/tapClientLookup.ts +79 -0
  87. package/src/tapClientResource.ts +187 -0
  88. package/src/types/client.ts +180 -0
  89. package/src/types/events.ts +77 -0
  90. package/src/useAui.ts +21 -19
  91. package/src/useAuiEvent.ts +2 -2
  92. package/src/useAuiState.ts +3 -3
  93. package/src/utils/BaseProxyHandler.ts +50 -0
  94. package/src/utils/NotificationManager.ts +114 -0
  95. package/src/utils/proxied-assistant-state.ts +53 -0
  96. package/src/utils/react-assistant-context.tsx +3 -7
  97. package/src/utils/splitClients.ts +80 -0
  98. package/src/utils/tap-assistant-context.ts +58 -0
  99. package/src/utils/tap-client-stack-context.ts +51 -0
  100. package/src/wrapperResource.ts +17 -0
  101. package/dist/scope-registry-forward.d.ts +0 -6
  102. package/dist/scope-registry-forward.d.ts.map +0 -1
  103. package/dist/scope-registry-forward.js +0 -2
  104. package/dist/scope-registry-forward.js.map +0 -1
  105. package/dist/scope-registry.d.ts +0 -17
  106. package/dist/scope-registry.d.ts.map +0 -1
  107. package/dist/scope-registry.js +0 -2
  108. package/dist/scope-registry.js.map +0 -1
  109. package/src/scope-registry-forward.ts +0 -6
  110. package/src/scope-registry.ts +0 -15
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { getClientState } from "../tapClientResource";
3
+ import type { AssistantClient, AssistantState } from "../types/client";
4
+ import { BaseProxyHandler, handleIntrospectionProp } from "./BaseProxyHandler";
5
+
6
+ export const PROXIED_ASSISTANT_STATE_SYMBOL = Symbol(
7
+ "assistant-ui.store.proxiedAssistantState",
8
+ );
9
+
10
+ const isIgnoredKey = (key: string | symbol): key is "on" | "subscribe" => {
11
+ return key === "on" || key === "subscribe" || typeof key === "symbol";
12
+ };
13
+
14
+ /**
15
+ * Proxied state that lazily accesses scope states
16
+ */
17
+ export const createProxiedAssistantState = (
18
+ client: AssistantClient,
19
+ ): AssistantState => {
20
+ class ProxiedAssistantStateProxyHandler
21
+ extends BaseProxyHandler
22
+ implements ProxyHandler<AssistantState>
23
+ {
24
+ get(_: unknown, prop: string | symbol) {
25
+ const introspection = handleIntrospectionProp(prop, "AssistantState");
26
+ if (introspection !== false) return introspection;
27
+ const scope = prop as keyof AssistantClient;
28
+ if (isIgnoredKey(scope)) return undefined;
29
+ return getClientState(client[scope]());
30
+ }
31
+
32
+ ownKeys(): ArrayLike<string | symbol> {
33
+ return Object.keys(client).filter((key) => !isIgnoredKey(key));
34
+ }
35
+
36
+ has(_: unknown, prop: string | symbol): boolean {
37
+ return !isIgnoredKey(prop) && prop in client;
38
+ }
39
+ }
40
+
41
+ return new Proxy<AssistantState>(
42
+ {} as AssistantState,
43
+ new ProxiedAssistantStateProxyHandler(),
44
+ );
45
+ };
46
+
47
+ export const getProxiedAssistantState = (
48
+ client: AssistantClient,
49
+ ): AssistantState => {
50
+ return (
51
+ client as unknown as { [PROXIED_ASSISTANT_STATE_SYMBOL]: AssistantState }
52
+ )[PROXIED_ASSISTANT_STATE_SYMBOL];
53
+ };
@@ -1,14 +1,10 @@
1
1
  import React, { createContext, useContext } from "react";
2
- import type {
3
- AssistantClient,
4
- AssistantClientAccessor,
5
- } from "@assistant-ui/core/store";
2
+ import type { AssistantClient, AssistantClientAccessor } from "../types/client";
6
3
  import {
7
4
  createProxiedAssistantState,
8
5
  PROXIED_ASSISTANT_STATE_SYMBOL,
9
- BaseProxyHandler,
10
- handleIntrospectionProp,
11
- } from "@assistant-ui/core/store/internal";
6
+ } from "./proxied-assistant-state";
7
+ import { BaseProxyHandler, handleIntrospectionProp } from "./BaseProxyHandler";
12
8
 
13
9
  const NO_OP_SUBSCRIBE = () => () => {};
14
10
 
@@ -0,0 +1,80 @@
1
+ import { Derived, DerivedElement } from "../Derived";
2
+ import type {
3
+ AssistantClient,
4
+ ClientElement,
5
+ ClientNames,
6
+ } from "../types/client";
7
+ import { getTransformScopes } from "../attachTransformScopes";
8
+ import type { useAui } from "../useAui";
9
+ import { tapMemo } from "@assistant-ui/tap";
10
+
11
+ export type RootClients = Partial<
12
+ Record<ClientNames, ClientElement<ClientNames>>
13
+ >;
14
+ export type DerivedClients = Partial<
15
+ Record<ClientNames, DerivedElement<ClientNames>>
16
+ >;
17
+
18
+ /**
19
+ * Splits a clients object into root clients and derived clients,
20
+ * applying transformScopes from root client elements.
21
+ */
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
48
+ const rootClients: RootClients = {};
49
+ const derivedClients: DerivedClients = {};
50
+
51
+ for (const [key, clientElement] of Object.entries(scopes) as [
52
+ ClientNames,
53
+ ClientElement<ClientNames> | DerivedElement<ClientNames>,
54
+ ][]) {
55
+ if (clientElement.type === (Derived as unknown)) {
56
+ derivedClients[key] = clientElement as DerivedElement<ClientNames>;
57
+ } else {
58
+ rootClients[key] = clientElement as ClientElement<ClientNames>;
59
+ }
60
+ }
61
+
62
+ return { rootClients, derivedClients };
63
+ }
64
+
65
+ const tapShallowMemoObject = <T extends object>(object: T) => {
66
+ // biome-ignore lint/correctness/useExhaustiveDependencies: shallow memo
67
+ return tapMemo(() => object, [...Object.entries(object).flat()]);
68
+ };
69
+
70
+ export const tapSplitClients = (
71
+ clients: useAui.Props,
72
+ baseClient: AssistantClient,
73
+ ) => {
74
+ const { rootClients, derivedClients } = splitClients(clients, baseClient);
75
+
76
+ return {
77
+ rootClients: tapShallowMemoObject(rootClients),
78
+ derivedClients: tapShallowMemoObject(derivedClients),
79
+ };
80
+ };
@@ -0,0 +1,58 @@
1
+ import {
2
+ createResourceContext,
3
+ tap,
4
+ withContextProvider,
5
+ tapEffectEvent,
6
+ } from "@assistant-ui/tap";
7
+ import type {
8
+ AssistantEventName,
9
+ AssistantEventPayload,
10
+ } from "../types/events";
11
+ import type { AssistantClient } from "../types/client";
12
+ import { tapClientStack, type ClientStack } from "./tap-client-stack-context";
13
+
14
+ type EmitFn = <TEvent extends Exclude<AssistantEventName, "*">>(
15
+ event: TEvent,
16
+ payload: AssistantEventPayload[TEvent],
17
+ clientStack: ClientStack,
18
+ ) => void;
19
+
20
+ export type AssistantTapContextValue = {
21
+ clientRef: { parent: AssistantClient; current: AssistantClient | null };
22
+ emit: EmitFn;
23
+ };
24
+
25
+ const AssistantTapContext =
26
+ createResourceContext<AssistantTapContextValue | null>(null);
27
+
28
+ export const withAssistantTapContextProvider = <TResult>(
29
+ value: AssistantTapContextValue,
30
+ fn: () => TResult,
31
+ ) => {
32
+ return withContextProvider(AssistantTapContext, value, fn);
33
+ };
34
+
35
+ const tapAssistantTapContext = () => {
36
+ const ctx = tap(AssistantTapContext);
37
+ if (!ctx) throw new Error("AssistantTapContext is not available");
38
+
39
+ return ctx;
40
+ };
41
+
42
+ export const tapAssistantClientRef = () => {
43
+ return tapAssistantTapContext().clientRef;
44
+ };
45
+
46
+ export const tapAssistantEmit = () => {
47
+ const { emit } = tapAssistantTapContext();
48
+ const clientStack = tapClientStack();
49
+
50
+ return tapEffectEvent(
51
+ <TEvent extends Exclude<AssistantEventName, "*">>(
52
+ event: TEvent,
53
+ payload: AssistantEventPayload[TEvent],
54
+ ) => {
55
+ emit(event, payload, clientStack);
56
+ },
57
+ );
58
+ };
@@ -0,0 +1,51 @@
1
+ import {
2
+ createResourceContext,
3
+ tap,
4
+ withContextProvider,
5
+ tapMemo,
6
+ } from "@assistant-ui/tap";
7
+ import type { ClientMethods } from "../types/client";
8
+
9
+ /**
10
+ * Symbol used to get the client index from a ClientProxy.
11
+ */
12
+ export const SYMBOL_CLIENT_INDEX = Symbol("assistant-ui.store.clientIndex");
13
+
14
+ /**
15
+ * Get the index of a client (its position in the client stack when created).
16
+ */
17
+ export const getClientIndex = (client: ClientMethods): number => {
18
+ return (client as unknown as { [SYMBOL_CLIENT_INDEX]: number })[
19
+ SYMBOL_CLIENT_INDEX
20
+ ];
21
+ };
22
+
23
+ /**
24
+ * The client stack - an array of clients representing the current hierarchy.
25
+ */
26
+ export type ClientStack = readonly ClientMethods[];
27
+
28
+ const ClientStackContext = createResourceContext<ClientStack>([]);
29
+
30
+ /**
31
+ * Get the current client stack inside a tap resource.
32
+ */
33
+ export const tapClientStack = (): ClientStack => {
34
+ return tap(ClientStackContext);
35
+ };
36
+
37
+ /**
38
+ * Execute a callback with a client pushed onto the stack.
39
+ * The stack is duplicated, not mutated.
40
+ */
41
+ export const tapWithClientStack = <T>(
42
+ client: ClientMethods,
43
+ callback: () => T,
44
+ ): T => {
45
+ const currentStack = tapClientStack();
46
+ const newStack = tapMemo(
47
+ () => [...currentStack, client],
48
+ [currentStack, client],
49
+ );
50
+ return withContextProvider(ClientStackContext, newStack, callback);
51
+ };
@@ -0,0 +1,17 @@
1
+ import {
2
+ type ResourceElement,
3
+ Resource,
4
+ resource,
5
+ withKey,
6
+ } from "@assistant-ui/tap";
7
+
8
+ export const wrapperResource = <R, P>(
9
+ fn: (props: ResourceElement<P>) => R,
10
+ ): Resource<R, ResourceElement<P>> => {
11
+ const res = resource(fn);
12
+ return (props: ResourceElement<P>) => {
13
+ const el = res(props);
14
+ if (props.key === undefined) return el;
15
+ return withKey(props.key, el);
16
+ };
17
+ };
@@ -1,6 +0,0 @@
1
- import type { ScopeRegistry as StoreScopeRegistry } from "./scope-registry.js";
2
- declare module "@assistant-ui/core/store" {
3
- interface ScopeRegistry extends StoreScopeRegistry {
4
- }
5
- }
6
- //# sourceMappingURL=scope-registry-forward.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-registry-forward.d.ts","sourceRoot":"","sources":["../src/scope-registry-forward.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,4BAAyB;AAG5E,OAAO,QAAQ,0BAA0B,CAAC;IACxC,UAAU,aAAc,SAAQ,kBAAkB;KAAG;CACtD"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=scope-registry-forward.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-registry-forward.js","sourceRoot":"","sources":["../src/scope-registry-forward.ts"],"names":[],"mappings":""}
@@ -1,17 +0,0 @@
1
- /**
2
- * Module augmentation interface for assistant-ui store type extensions.
3
- *
4
- * Users augment this interface to register custom scopes:
5
- * ```typescript
6
- * declare module "@assistant-ui/store" {
7
- * interface ScopeRegistry {
8
- * myScope: { methods: { getState: () => MyState } };
9
- * }
10
- * }
11
- * ```
12
- *
13
- * Augmentations are automatically forwarded to `@assistant-ui/core/store`.
14
- */
15
- export interface ScopeRegistry {
16
- }
17
- //# sourceMappingURL=scope-registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-registry.d.ts","sourceRoot":"","sources":["../src/scope-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;CAAG"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=scope-registry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scope-registry.js","sourceRoot":"","sources":["../src/scope-registry.ts"],"names":[],"mappings":""}
@@ -1,6 +0,0 @@
1
- import type { ScopeRegistry as StoreScopeRegistry } from "./scope-registry";
2
-
3
- // Forward user augmentations on @assistant-ui/store to @assistant-ui/core/store
4
- declare module "@assistant-ui/core/store" {
5
- interface ScopeRegistry extends StoreScopeRegistry {}
6
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * Module augmentation interface for assistant-ui store type extensions.
3
- *
4
- * Users augment this interface to register custom scopes:
5
- * ```typescript
6
- * declare module "@assistant-ui/store" {
7
- * interface ScopeRegistry {
8
- * myScope: { methods: { getState: () => MyState } };
9
- * }
10
- * }
11
- * ```
12
- *
13
- * Augmentations are automatically forwarded to `@assistant-ui/core/store`.
14
- */
15
- export interface ScopeRegistry {}