@assistant-ui/store 0.0.1 → 0.0.2

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.
@@ -0,0 +1,12 @@
1
+ import type { FC, PropsWithChildren } from "react";
2
+ import type { AssistantState } from "./types";
3
+ type UseAssistantIfProps = {
4
+ condition: AssistantIf.Condition;
5
+ };
6
+ export declare namespace AssistantIf {
7
+ type Props = PropsWithChildren<UseAssistantIfProps>;
8
+ type Condition = (state: AssistantState) => boolean;
9
+ }
10
+ export declare const AssistantIf: FC<AssistantIf.Props>;
11
+ export {};
12
+ //# sourceMappingURL=AssistantIf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantIf.d.ts","sourceRoot":"","sources":["../src/AssistantIf.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC;CAClC,CAAC;AAMF,yBAAiB,WAAW,CAAC;IAC3B,KAAY,KAAK,GAAG,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IAC3D,KAAY,SAAS,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC;CAC5D;AAED,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAG7C,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+
3
+ // src/AssistantIf.tsx
4
+ import { useAssistantState } from "./useAssistantState.js";
5
+ var useAssistantIf = (props) => {
6
+ return useAssistantState(props.condition);
7
+ };
8
+ var AssistantIf = ({ children, condition }) => {
9
+ const result = useAssistantIf({ condition });
10
+ return result ? children : null;
11
+ };
12
+ AssistantIf.displayName = "AssistantIf";
13
+ export {
14
+ AssistantIf
15
+ };
16
+ //# sourceMappingURL=AssistantIf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/AssistantIf.tsx"],"sourcesContent":["\"use client\";\n\nimport type { FC, PropsWithChildren } from \"react\";\nimport { useAssistantState } from \"./useAssistantState\";\nimport type { AssistantState } from \"./types\";\n\ntype UseAssistantIfProps = {\n condition: AssistantIf.Condition;\n};\n\nconst useAssistantIf = (props: UseAssistantIfProps) => {\n return useAssistantState(props.condition);\n};\n\nexport namespace AssistantIf {\n export type Props = PropsWithChildren<UseAssistantIfProps>;\n export type Condition = (state: AssistantState) => boolean;\n}\n\nexport const AssistantIf: FC<AssistantIf.Props> = ({ children, condition }) => {\n const result = useAssistantIf({ condition });\n return result ? children : null;\n};\n\nAssistantIf.displayName = \"AssistantIf\";\n"],"mappings":";;;AAGA,SAAS,yBAAyB;AAOlC,IAAM,iBAAiB,CAAC,UAA+B;AACrD,SAAO,kBAAkB,MAAM,SAAS;AAC1C;AAOO,IAAM,cAAqC,CAAC,EAAE,UAAU,UAAU,MAAM;AAC7E,QAAM,SAAS,eAAe,EAAE,UAAU,CAAC;AAC3C,SAAO,SAAS,WAAW;AAC7B;AAEA,YAAY,cAAc;","names":[]}
@@ -1,18 +1,20 @@
1
- import type { ScopeDefinition, ScopeValue, DerivedScopeProps } from "./types";
1
+ import type { ScopeDefinition, DerivedScopeProps } from "./types";
2
2
  /**
3
3
  * Creates a derived scope field that memoizes based on source and query.
4
4
  * The get callback always calls the most recent version (useEffectEvent pattern).
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * const MessageScope = DerivedScope<MessageScopeDefinition>({
9
- * source: "thread",
10
- * query: { type: "index", index: 0 },
11
- * get: () => messageApi,
8
+ * const client = useAssistantClient({
9
+ * message: DerivedScope({
10
+ * source: "thread",
11
+ * query: { index: 0 },
12
+ * get: (client) => client.thread().message({ index: 0 }),
13
+ * }),
12
14
  * });
13
15
  * ```
14
16
  */
15
17
  export declare const DerivedScope: <T extends ScopeDefinition>(props: DerivedScopeProps<T>, options?: {
16
18
  key?: string | number;
17
- } | undefined) => import("@assistant-ui/tap").ResourceElement<ScopeValue<T>, DerivedScopeProps<T>>;
19
+ } | undefined) => import("@assistant-ui/tap").ResourceElement<null, DerivedScopeProps<T>>;
18
20
  //# sourceMappingURL=DerivedScope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DerivedScope.d.ts","sourceRoot":"","sources":["../src/DerivedScope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GACtB,CAAC,SAAS,eAAe;;kGAG3B,CAAC"}
1
+ {"version":3,"file":"DerivedScope.d.ts","sourceRoot":"","sources":["../src/DerivedScope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,GACtB,CAAC,SAAS,eAAe;;yFAG3B,CAAC"}
@@ -1,8 +1,8 @@
1
1
  // src/DerivedScope.ts
2
2
  import { resource } from "@assistant-ui/tap";
3
3
  var DerivedScope = resource(
4
- (config) => {
5
- return config;
4
+ (_config) => {
5
+ return null;
6
6
  }
7
7
  );
8
8
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/DerivedScope.ts"],"sourcesContent":["import { resource } from \"@assistant-ui/tap\";\nimport type { ScopeDefinition, ScopeValue, DerivedScopeProps } from \"./types\";\n\n/**\n * Creates a derived scope field that memoizes based on source and query.\n * The get callback always calls the most recent version (useEffectEvent pattern).\n *\n * @example\n * ```typescript\n * const MessageScope = DerivedScope<MessageScopeDefinition>({\n * source: \"thread\",\n * query: { type: \"index\", index: 0 },\n * get: () => messageApi,\n * });\n * ```\n */\nexport const DerivedScope = resource(\n <T extends ScopeDefinition>(config: DerivedScopeProps<T>): ScopeValue<T> => {\n return config;\n },\n);\n"],"mappings":";AAAA,SAAS,gBAAgB;AAgBlB,IAAM,eAAe;AAAA,EAC1B,CAA4B,WAAgD;AAC1E,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/DerivedScope.ts"],"sourcesContent":["import { resource } from \"@assistant-ui/tap\";\nimport type { ScopeDefinition, DerivedScopeProps } from \"./types\";\n\n/**\n * Creates a derived scope field that memoizes based on source and query.\n * The get callback always calls the most recent version (useEffectEvent pattern).\n *\n * @example\n * ```typescript\n * const client = useAssistantClient({\n * message: DerivedScope({\n * source: \"thread\",\n * query: { index: 0 },\n * get: (client) => client.thread().message({ index: 0 }),\n * }),\n * });\n * ```\n */\nexport const DerivedScope = resource(\n <T extends ScopeDefinition>(_config: DerivedScopeProps<T>): null => {\n return null;\n },\n);\n"],"mappings":";AAAA,SAAS,gBAAgB;AAkBlB,IAAM,eAAe;AAAA,EAC1B,CAA4B,YAAwC;AAClE,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,19 +1,4 @@
1
- import type { Unsubscribe } from "./types";
2
- /**
3
- * Module augmentation interface for custom events.
4
- *
5
- * @example
6
- * ```typescript
7
- * declare module "@assistant-ui/store" {
8
- * interface AssistantEventRegistry {
9
- * "thread.run-start": { threadId: string };
10
- * "custom.my-event": { data: string };
11
- * }
12
- * }
13
- * ```
14
- */
15
- export interface AssistantEventRegistry {
16
- }
1
+ import type { AssistantScopes, Unsubscribe } from "./types";
17
2
  /**
18
3
  * Module augmentation interface for event scope configuration.
19
4
  * Maps event sources to their parent scopes.
@@ -30,13 +15,23 @@ export interface AssistantEventRegistry {
30
15
  */
31
16
  export interface AssistantEventScopeConfig {
32
17
  }
33
- export type AssistantEventMap = AssistantEventRegistry & {
34
- "*": {
35
- [K in Exclude<keyof AssistantEventRegistry, "*">]: {
36
- event: K;
37
- payload: AssistantEventRegistry[K];
38
- };
39
- }[Exclude<keyof AssistantEventRegistry, "*">];
18
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
19
+ /**
20
+ * Event map derived from scope event definitions
21
+ */
22
+ export type ScopeEventMap = UnionToIntersection<{
23
+ [K in keyof AssistantScopes]: AssistantScopes[K] extends {
24
+ events: infer E;
25
+ } ? E extends Record<string, unknown> ? E : never : never;
26
+ }[keyof AssistantScopes]>;
27
+ type WildcardPayload = {
28
+ [K in keyof ScopeEventMap]: {
29
+ event: K;
30
+ payload: ScopeEventMap[K];
31
+ };
32
+ }[keyof ScopeEventMap];
33
+ export type AssistantEventMap = ScopeEventMap & {
34
+ "*": WildcardPayload;
40
35
  };
41
36
  export type AssistantEvent = keyof AssistantEventMap;
42
37
  export type EventSource<T extends AssistantEvent = AssistantEvent> = T extends `${infer Source}.${string}` ? Source : never;
@@ -62,4 +57,5 @@ export declare const EventManager: () => import("@assistant-ui/tap").ResourceEle
62
57
  on: <TEvent extends AssistantEvent>(event: TEvent, callback: AssistantEventCallback<TEvent>) => () => void;
63
58
  emit: <TEvent extends Exclude<AssistantEvent, "*">>(event: TEvent, payload: AssistantEventMap[TEvent]) => void;
64
59
  }, undefined>;
60
+ export {};
65
61
  //# sourceMappingURL=EventContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EventContext.d.ts","sourceRoot":"","sources":["../src/EventContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,sBAAsB;CAAG;AAE1C;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,yBAAyB;CAAG;AAE7C,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG;IAEvD,GAAG,EAAE;SACF,CAAC,IAAI,OAAO,CAAC,MAAM,sBAAsB,EAAE,GAAG,CAAC,GAAG;YACjD,KAAK,EAAE,CAAC,CAAC;YACT,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC;SACpC;KACF,CAAC,OAAO,CAAC,MAAM,sBAAsB,EAAE,GAAG,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAC/D,CAAC,SAAS,GAAG,MAAM,MAAM,IAAI,MAAM,EAAE,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzD,MAAM,MAAM,aAAa,CAAC,MAAM,SAAS,mBAAmB,CAAC,cAAc,CAAC,IACxE,CAAC,MAAM,SAAS,GAAG,GAAG,WAAW,GAAG,KAAK,CAAC,GAC1C,CAAC,MAAM,SAAS,MAAM,yBAAyB,GAAG,MAAM,GAAG,KAAK,CAAC,GACjE;KACG,CAAC,IAAI,MAAM,yBAAyB,GAAG,MAAM,SAAS,yBAAyB,CAAC,CAAC,CAAC,GAC/E,CAAC,GACD,KAAK;CACV,CAAC,MAAM,yBAAyB,CAAC,CAAC;AAEvC,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,cAAc,IACzD,GAAG,GACH,WAAW,CAAC,MAAM,CAAC,GACnB,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,MAAM,yBAAyB,GACxD,yBAAyB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAC9C,KAAK,CAAC,CAAC;AAEf,MAAM,MAAM,sBAAsB,CAAC,MAAM,SAAS,cAAc,IAC5D,MAAM,GACN;IACE,KAAK,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,eAAO,MAAM,sBAAsB,GAAI,MAAM,SAAS,cAAc,EAClE,UAAU,sBAAsB,CAAC,MAAM,CAAC;;;CAczC,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,SAAS,cAAc,EAC7B,cAAc,SAAS,mBAAmB,CAAC,cAAc,CAAC,EAE1D,eAAe,cAAc,EAC7B,OAAO,mBAAmB,CAAC,MAAM,CAAC,EAClC,QAAQ,MAAM,KACb,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,cAAc,CAAC,IAAI,MAAM,EAAE,CAExE,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,MAAM,SAAS,cAAc,IAAI,CAClE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,KAC/B,IAAI,CAAC;AAEV,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,CAAC,MAAM,SAAS,cAAc,EAC9B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,GACvC,WAAW,CAAC;IACf,IAAI,CAAC,MAAM,SAAS,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,EAC9C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,GACjC,IAAI,CAAC;CACT,CAAC;AAeF,eAAO,MAAM,YAAY;SAvBpB,MAAM,SAAS,cAAc;WAI3B,MAAM,SAAS,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;aAwEhD,CAAC"}
1
+ {"version":3,"file":"EventContext.d.ts","sourceRoot":"","sources":["../src/EventContext.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/EventContext.ts"],"sourcesContent":["import { resource, tapMemo } from \"@assistant-ui/tap\";\nimport type { Unsubscribe } from \"./types\";\n\n/**\n * Module augmentation interface for custom events.\n *\n * @example\n * ```typescript\n * declare module \"@assistant-ui/store\" {\n * interface AssistantEventRegistry {\n * \"thread.run-start\": { threadId: string };\n * \"custom.my-event\": { data: string };\n * }\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface AssistantEventRegistry {}\n\n/**\n * Module augmentation interface for event scope configuration.\n * Maps event sources to their parent scopes.\n *\n * @example\n * ```typescript\n * declare module \"@assistant-ui/store\" {\n * interface AssistantEventScopeConfig {\n * composer: \"thread\" | \"message\";\n * thread: never;\n * }\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface AssistantEventScopeConfig {}\n\nexport type AssistantEventMap = AssistantEventRegistry & {\n // Catch-all\n \"*\": {\n [K in Exclude<keyof AssistantEventRegistry, \"*\">]: {\n event: K;\n payload: AssistantEventRegistry[K];\n };\n }[Exclude<keyof AssistantEventRegistry, \"*\">];\n};\n\nexport type AssistantEvent = keyof AssistantEventMap;\n\nexport type EventSource<T extends AssistantEvent = AssistantEvent> =\n T extends `${infer Source}.${string}` ? Source : never;\n\nexport type SourceByScope<TScope extends AssistantEventScope<AssistantEvent>> =\n | (TScope extends \"*\" ? EventSource : never)\n | (TScope extends keyof AssistantEventScopeConfig ? TScope : never)\n | {\n [K in keyof AssistantEventScopeConfig]: TScope extends AssistantEventScopeConfig[K]\n ? K\n : never;\n }[keyof AssistantEventScopeConfig];\n\nexport type AssistantEventScope<TEvent extends AssistantEvent> =\n | \"*\"\n | EventSource<TEvent>\n | (EventSource<TEvent> extends keyof AssistantEventScopeConfig\n ? AssistantEventScopeConfig[EventSource<TEvent>]\n : never);\n\nexport type AssistantEventSelector<TEvent extends AssistantEvent> =\n | TEvent\n | {\n scope: AssistantEventScope<TEvent>;\n event: TEvent;\n };\n\nexport const normalizeEventSelector = <TEvent extends AssistantEvent>(\n selector: AssistantEventSelector<TEvent>,\n) => {\n if (typeof selector === \"string\") {\n const source = selector.split(\".\")[0] as AssistantEventScope<TEvent>;\n return {\n scope: source,\n event: selector,\n };\n }\n\n return {\n scope: selector.scope,\n event: selector.event,\n };\n};\n\nexport const checkEventScope = <\n TEvent extends AssistantEvent,\n TExpectedScope extends AssistantEventScope<AssistantEvent>,\n>(\n expectedScope: TExpectedScope,\n scope: AssistantEventScope<TEvent>,\n _event: TEvent,\n): _event is Extract<TEvent, `${SourceByScope<TExpectedScope>}.${string}`> => {\n return scope === expectedScope;\n};\n\nexport type AssistantEventCallback<TEvent extends AssistantEvent> = (\n payload: AssistantEventMap[TEvent],\n) => void;\n\nexport type EventManager = {\n on<TEvent extends AssistantEvent>(\n event: TEvent,\n callback: AssistantEventCallback<TEvent>,\n ): Unsubscribe;\n emit<TEvent extends Exclude<AssistantEvent, \"*\">>(\n event: TEvent,\n payload: AssistantEventMap[TEvent],\n ): void;\n};\n\ntype ListenerMap = Omit<\n Map<AssistantEvent, Set<AssistantEventCallback<AssistantEvent>>>,\n \"get\" | \"set\"\n> & {\n get<TEvent extends AssistantEvent>(\n event: TEvent,\n ): Set<AssistantEventCallback<TEvent>> | undefined;\n set<TEvent extends AssistantEvent>(\n event: TEvent,\n value: Set<AssistantEventCallback<TEvent>>,\n ): void;\n};\n\nexport const EventManager = resource(() => {\n const events = tapMemo(() => {\n const listeners: ListenerMap = new Map();\n\n return {\n on: (event, callback) => {\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback);\n\n return () => {\n eventListeners.delete(callback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n },\n\n emit: (event, payload) => {\n const eventListeners = listeners.get(event);\n const wildcardListeners = listeners.get(\"*\");\n\n if (!eventListeners && !wildcardListeners) return;\n\n // make sure state updates flush\n queueMicrotask(() => {\n // Emit to specific event listeners\n if (eventListeners) {\n for (const callback of eventListeners) {\n callback(payload);\n }\n }\n\n // Emit to wildcard listeners\n if (wildcardListeners) {\n for (const callback of wildcardListeners) {\n (\n callback as (payload: {\n event: typeof event;\n payload: typeof payload;\n }) => void\n )({ event, payload });\n }\n }\n });\n },\n } satisfies EventManager;\n }, []);\n\n return events;\n});\n"],"mappings":";AAAA,SAAS,UAAU,eAAe;AA0E3B,IAAM,yBAAyB,CACpC,aACG;AACH,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,SAAS,SAAS,MAAM,GAAG,EAAE,CAAC;AACpC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,EAClB;AACF;AAEO,IAAM,kBAAkB,CAI7B,eACA,OACA,WAC4E;AAC5E,SAAO,UAAU;AACnB;AA8BO,IAAM,eAAe,SAAS,MAAM;AACzC,QAAM,SAAS,QAAQ,MAAM;AAC3B,UAAM,YAAyB,oBAAI,IAAI;AAEvC,WAAO;AAAA,MACL,IAAI,CAAC,OAAO,aAAa;AACvB,YAAI,CAAC,UAAU,IAAI,KAAK,GAAG;AACzB,oBAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,QAChC;AAEA,cAAM,iBAAiB,UAAU,IAAI,KAAK;AAC1C,uBAAe,IAAI,QAAQ;AAE3B,eAAO,MAAM;AACX,yBAAe,OAAO,QAAQ;AAC9B,cAAI,eAAe,SAAS,GAAG;AAC7B,sBAAU,OAAO,KAAK;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,CAAC,OAAO,YAAY;AACxB,cAAM,iBAAiB,UAAU,IAAI,KAAK;AAC1C,cAAM,oBAAoB,UAAU,IAAI,GAAG;AAE3C,YAAI,CAAC,kBAAkB,CAAC,kBAAmB;AAG3C,uBAAe,MAAM;AAEnB,cAAI,gBAAgB;AAClB,uBAAW,YAAY,gBAAgB;AACrC,uBAAS,OAAO;AAAA,YAClB;AAAA,UACF;AAGA,cAAI,mBAAmB;AACrB,uBAAW,YAAY,mBAAmB;AACxC,cACE,SAIA,EAAE,OAAO,QAAQ,CAAC;AAAA,YACtB;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/EventContext.ts"],"sourcesContent":["import { resource, tapMemo } from \"@assistant-ui/tap\";\nimport type { AssistantScopes, Unsubscribe } from \"./types\";\n\n/**\n * Module augmentation interface for event scope configuration.\n * Maps event sources to their parent scopes.\n *\n * @example\n * ```typescript\n * declare module \"@assistant-ui/store\" {\n * interface AssistantEventScopeConfig {\n * composer: \"thread\" | \"message\";\n * thread: never;\n * }\n * }\n * ```\n */\nexport interface AssistantEventScopeConfig {}\n\ntype UnionToIntersection<U> = (\n U extends unknown\n ? (x: U) => void\n : never\n) extends (x: infer I) => void\n ? I\n : never;\n\n/**\n * Event map derived from scope event definitions\n */\nexport type ScopeEventMap = UnionToIntersection<\n {\n [K in keyof AssistantScopes]: AssistantScopes[K] extends {\n events: infer E;\n }\n ? E extends Record<string, unknown>\n ? E\n : never\n : never;\n }[keyof AssistantScopes]\n>;\n\ntype WildcardPayload = {\n [K in keyof ScopeEventMap]: {\n event: K;\n payload: ScopeEventMap[K];\n };\n}[keyof ScopeEventMap];\n\nexport type AssistantEventMap = ScopeEventMap & {\n // Catch-all\n \"*\": WildcardPayload;\n};\n\nexport type AssistantEvent = keyof AssistantEventMap;\n\nexport type EventSource<T extends AssistantEvent = AssistantEvent> =\n T extends `${infer Source}.${string}` ? Source : never;\n\nexport type SourceByScope<TScope extends AssistantEventScope<AssistantEvent>> =\n | (TScope extends \"*\" ? EventSource : never)\n | (TScope extends keyof AssistantEventScopeConfig ? TScope : never)\n | {\n [K in keyof AssistantEventScopeConfig]: TScope extends AssistantEventScopeConfig[K]\n ? K\n : never;\n }[keyof AssistantEventScopeConfig];\n\nexport type AssistantEventScope<TEvent extends AssistantEvent> =\n | \"*\"\n | EventSource<TEvent>\n | (EventSource<TEvent> extends keyof AssistantEventScopeConfig\n ? AssistantEventScopeConfig[EventSource<TEvent>]\n : never);\n\nexport type AssistantEventSelector<TEvent extends AssistantEvent> =\n | TEvent\n | {\n scope: AssistantEventScope<TEvent>;\n event: TEvent;\n };\n\nexport const normalizeEventSelector = <TEvent extends AssistantEvent>(\n selector: AssistantEventSelector<TEvent>,\n) => {\n if (typeof selector === \"string\") {\n const source = selector.split(\".\")[0] as AssistantEventScope<TEvent>;\n return {\n scope: source,\n event: selector,\n };\n }\n\n return {\n scope: selector.scope,\n event: selector.event,\n };\n};\n\nexport const checkEventScope = <\n TEvent extends AssistantEvent,\n TExpectedScope extends AssistantEventScope<AssistantEvent>,\n>(\n expectedScope: TExpectedScope,\n scope: AssistantEventScope<TEvent>,\n _event: TEvent,\n): _event is Extract<TEvent, `${SourceByScope<TExpectedScope>}.${string}`> => {\n return scope === expectedScope;\n};\n\nexport type AssistantEventCallback<TEvent extends AssistantEvent> = (\n payload: AssistantEventMap[TEvent],\n) => void;\n\nexport type EventManager = {\n on<TEvent extends AssistantEvent>(\n event: TEvent,\n callback: AssistantEventCallback<TEvent>,\n ): Unsubscribe;\n emit<TEvent extends Exclude<AssistantEvent, \"*\">>(\n event: TEvent,\n payload: AssistantEventMap[TEvent],\n ): void;\n};\n\ntype ListenerMap = Omit<\n Map<AssistantEvent, Set<AssistantEventCallback<AssistantEvent>>>,\n \"get\" | \"set\"\n> & {\n get<TEvent extends AssistantEvent>(\n event: TEvent,\n ): Set<AssistantEventCallback<TEvent>> | undefined;\n set<TEvent extends AssistantEvent>(\n event: TEvent,\n value: Set<AssistantEventCallback<TEvent>>,\n ): void;\n};\n\nexport const EventManager = resource(() => {\n const events = tapMemo(() => {\n const listeners: ListenerMap = new Map();\n\n return {\n on: (event, callback) => {\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback);\n\n return () => {\n eventListeners.delete(callback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n },\n\n emit: (event, payload) => {\n const eventListeners = listeners.get(event);\n const wildcardListeners = listeners.get(\"*\");\n\n if (!eventListeners && !wildcardListeners) return;\n\n // make sure state updates flush\n queueMicrotask(() => {\n // Emit to specific event listeners\n if (eventListeners) {\n for (const callback of eventListeners) {\n callback(payload);\n }\n }\n\n // Emit to wildcard listeners\n if (wildcardListeners) {\n for (const callback of wildcardListeners) {\n callback({ event, payload } as any);\n }\n }\n });\n },\n } satisfies EventManager;\n }, []);\n\n return events;\n});\n"],"mappings":";AAAA,SAAS,UAAU,eAAe;AAkF3B,IAAM,yBAAyB,CACpC,aACG;AACH,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,SAAS,SAAS,MAAM,GAAG,EAAE,CAAC;AACpC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,EAClB;AACF;AAEO,IAAM,kBAAkB,CAI7B,eACA,OACA,WAC4E;AAC5E,SAAO,UAAU;AACnB;AA8BO,IAAM,eAAe,SAAS,MAAM;AACzC,QAAM,SAAS,QAAQ,MAAM;AAC3B,UAAM,YAAyB,oBAAI,IAAI;AAEvC,WAAO;AAAA,MACL,IAAI,CAAC,OAAO,aAAa;AACvB,YAAI,CAAC,UAAU,IAAI,KAAK,GAAG;AACzB,oBAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,QAChC;AAEA,cAAM,iBAAiB,UAAU,IAAI,KAAK;AAC1C,uBAAe,IAAI,QAAQ;AAE3B,eAAO,MAAM;AACX,yBAAe,OAAO,QAAQ;AAC9B,cAAI,eAAe,SAAS,GAAG;AAC7B,sBAAU,OAAO,KAAK;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,CAAC,OAAO,YAAY;AACxB,cAAM,iBAAiB,UAAU,IAAI,KAAK;AAC1C,cAAM,oBAAoB,UAAU,IAAI,GAAG;AAE3C,YAAI,CAAC,kBAAkB,CAAC,kBAAmB;AAG3C,uBAAe,MAAM;AAEnB,cAAI,gBAAgB;AAClB,uBAAW,YAAY,gBAAgB;AACrC,uBAAS,OAAO;AAAA,YAClB;AAAA,UACF;AAGA,cAAI,mBAAmB;AACrB,uBAAW,YAAY,mBAAmB;AACxC,uBAAS,EAAE,OAAO,QAAQ,CAAQ;AAAA,YACpC;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT,CAAC;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,18 +1,14 @@
1
1
  export { useAssistantClient } from "./useAssistantClient";
2
2
  export { useAssistantState } from "./useAssistantState";
3
+ export { useAssistantEvent } from "./useAssistantEvent";
4
+ export { AssistantIf } from "./AssistantIf";
3
5
  export { AssistantProvider } from "./AssistantContext";
4
- export type { AssistantScopes, AssistantClient, AssistantState } from "./types";
5
6
  export { DerivedScope } from "./DerivedScope";
6
- export type { ApiObject } from "./tapApi";
7
- export { tapApi } from "./tapApi";
7
+ export { tapApi, type ApiObject } from "./tapApi";
8
+ export { tapStoreContext, type StoreContextValue } from "./StoreContext";
8
9
  export { tapLookupResources } from "./tapLookupResources";
9
- export { tapStoreList } from "./tapStoreList";
10
- export type { TapStoreListConfig } from "./tapStoreList";
10
+ export { tapStoreList, type TapStoreListConfig } from "./tapStoreList";
11
11
  export { registerAssistantScope } from "./ScopeRegistry";
12
- export type { AssistantScopeRegistry } from "./types";
13
- export { tapStoreContext } from "./StoreContext";
14
- export type { StoreContextValue } from "./StoreContext";
15
- export { useAssistantEvent } from "./useAssistantEvent";
16
- export { normalizeEventSelector, checkEventScope } from "./EventContext";
17
- export type { AssistantEvent, AssistantEventRegistry, AssistantEventScopeConfig, AssistantEventMap, AssistantEventScope, AssistantEventSelector, AssistantEventCallback, EventSource, SourceByScope, EventManager, } from "./EventContext";
12
+ export type { AssistantScopes, AssistantScopeRegistry, AssistantClient, AssistantState, } from "./types";
13
+ export type { AssistantEvent, AssistantEventScopeConfig, AssistantEventMap, AssistantEventScope, AssistantEventSelector, AssistantEventCallback, EventSource, SourceByScope, EventManager, } from "./EventContext";
18
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACzE,YAAY,EACV,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,WAAW,EACX,aAAa,EACb,YAAY,GACb,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,cAAc,GACf,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,cAAc,EACd,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,WAAW,EACX,aAAa,EACb,YAAY,GACb,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,20 +1,19 @@
1
1
  // src/index.ts
2
2
  import { useAssistantClient } from "./useAssistantClient.js";
3
3
  import { useAssistantState } from "./useAssistantState.js";
4
+ import { useAssistantEvent } from "./useAssistantEvent.js";
5
+ import { AssistantIf } from "./AssistantIf.js";
4
6
  import { AssistantProvider } from "./AssistantContext.js";
5
7
  import { DerivedScope } from "./DerivedScope.js";
6
8
  import { tapApi } from "./tapApi.js";
9
+ import { tapStoreContext } from "./StoreContext.js";
7
10
  import { tapLookupResources } from "./tapLookupResources.js";
8
11
  import { tapStoreList } from "./tapStoreList.js";
9
12
  import { registerAssistantScope } from "./ScopeRegistry.js";
10
- import { tapStoreContext } from "./StoreContext.js";
11
- import { useAssistantEvent } from "./useAssistantEvent.js";
12
- import { normalizeEventSelector, checkEventScope } from "./EventContext.js";
13
13
  export {
14
+ AssistantIf,
14
15
  AssistantProvider,
15
16
  DerivedScope,
16
- checkEventScope,
17
- normalizeEventSelector,
18
17
  registerAssistantScope,
19
18
  tapApi,
20
19
  tapLookupResources,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { useAssistantClient } from \"./useAssistantClient\";\nexport { useAssistantState } from \"./useAssistantState\";\nexport { AssistantProvider } from \"./AssistantContext\";\nexport type { AssistantScopes, AssistantClient, AssistantState } from \"./types\";\nexport { DerivedScope } from \"./DerivedScope\";\nexport type { ApiObject } from \"./tapApi\";\nexport { tapApi } from \"./tapApi\";\nexport { tapLookupResources } from \"./tapLookupResources\";\nexport { tapStoreList } from \"./tapStoreList\";\nexport type { TapStoreListConfig } from \"./tapStoreList\";\nexport { registerAssistantScope } from \"./ScopeRegistry\";\n\nexport type { AssistantScopeRegistry } from \"./types\";\n\n// Events & Store Context\nexport { tapStoreContext } from \"./StoreContext\";\nexport type { StoreContextValue } from \"./StoreContext\";\nexport { useAssistantEvent } from \"./useAssistantEvent\";\nexport { normalizeEventSelector, checkEventScope } from \"./EventContext\";\nexport type {\n AssistantEvent,\n AssistantEventRegistry,\n AssistantEventScopeConfig,\n AssistantEventMap,\n AssistantEventScope,\n AssistantEventSelector,\n AssistantEventCallback,\n EventSource,\n SourceByScope,\n EventManager,\n} from \"./EventContext\";\n"],"mappings":";AAAA,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAElC,SAAS,oBAAoB;AAE7B,SAAS,cAAc;AACvB,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAKvC,SAAS,uBAAuB;AAEhC,SAAS,yBAAyB;AAClC,SAAS,wBAAwB,uBAAuB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// hooks\nexport { useAssistantClient } from \"./useAssistantClient\";\nexport { useAssistantState } from \"./useAssistantState\";\nexport { useAssistantEvent } from \"./useAssistantEvent\";\n\n// components\nexport { AssistantIf } from \"./AssistantIf\";\nexport { AssistantProvider } from \"./AssistantContext\";\n\n// resources\nexport { DerivedScope } from \"./DerivedScope\";\n\n// tap hooks\nexport { tapApi, type ApiObject } from \"./tapApi\";\nexport { tapStoreContext, type StoreContextValue } from \"./StoreContext\";\nexport { tapLookupResources } from \"./tapLookupResources\";\nexport { tapStoreList, type TapStoreListConfig } from \"./tapStoreList\";\n\n// registration\nexport { registerAssistantScope } from \"./ScopeRegistry\";\n\n// types\nexport type {\n AssistantScopes,\n AssistantScopeRegistry,\n AssistantClient,\n AssistantState,\n} from \"./types\";\n\nexport type {\n AssistantEvent,\n AssistantEventScopeConfig,\n AssistantEventMap,\n AssistantEventScope,\n AssistantEventSelector,\n AssistantEventCallback,\n EventSource,\n SourceByScope,\n EventManager,\n} from \"./EventContext\";\n"],"mappings":";AACA,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAGlC,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAGlC,SAAS,oBAAoB;AAG7B,SAAS,cAA8B;AACvC,SAAS,uBAA+C;AACxD,SAAS,0BAA0B;AACnC,SAAS,oBAA6C;AAGtD,SAAS,8BAA8B;","names":[]}
package/dist/types.d.ts CHANGED
@@ -9,8 +9,19 @@ import type { AssistantEvent, AssistantEventCallback, AssistantEventSelector } f
9
9
  * interface AssistantScopeRegistry {
10
10
  * foo: {
11
11
  * value: { getState: () => { bar: string }; updateBar: (bar: string) => void };
12
- * source: "root";
13
- * query: Record<string, never>;
12
+ * meta: { source: "root"; query: Record<string, never> };
13
+ * events: {
14
+ * "foo.updated": { id: string; newValue: string };
15
+ * "foo.deleted": { id: string };
16
+ * };
17
+ * };
18
+ * // Example with multiple sources (discriminated union):
19
+ * bar: {
20
+ * value: { getState: () => { id: string } };
21
+ * meta:
22
+ * | { source: "fooList"; query: { index: number } }
23
+ * | { source: "barList"; query: { id: string } };
24
+ * events: Record<string, never>;
14
25
  * };
15
26
  * }
16
27
  * }
@@ -21,26 +32,11 @@ export interface AssistantScopeRegistry {
21
32
  export type AssistantScopes = keyof AssistantScopeRegistry extends never ? Record<"ERROR: No scopes were defined", ScopeDefinition> : {
22
33
  [K in keyof AssistantScopeRegistry]: AssistantScopeRegistry[K];
23
34
  };
24
- /**
25
- * Helper type to extract the value type from a scope definition
26
- */
27
- export type ScopeValue<T extends ScopeDefinition> = T["value"];
28
- /**
29
- * Helper type to extract the source type from a scope definition
30
- */
31
- export type ScopeSource<T extends ScopeDefinition> = T["source"];
32
- /**
33
- * Helper type to extract the query type from a scope definition
34
- */
35
- export type ScopeQuery<T extends ScopeDefinition> = T["query"];
36
35
  /**
37
36
  * Type for a scope field - a function that returns the current API value,
38
- * with source and query metadata attached
37
+ * with source/query metadata attached (derived from meta)
39
38
  */
40
- export type ScopeField<T extends ScopeDefinition> = (() => ScopeValue<T>) & ({
41
- source: ScopeSource<T>;
42
- query: ScopeQuery<T>;
43
- } | {
39
+ export type ScopeField<T extends ScopeDefinition> = (() => T["value"]) & (T["meta"] | {
44
40
  source: null;
45
41
  query: null;
46
42
  });
@@ -48,16 +44,16 @@ export type ScopeField<T extends ScopeDefinition> = (() => ScopeValue<T>) & ({
48
44
  * Props passed to a derived scope resource element
49
45
  */
50
46
  export type DerivedScopeProps<T extends ScopeDefinition> = {
51
- get: (parent: AssistantClient) => ScopeValue<T>;
52
- source: ScopeSource<T>;
53
- query: ScopeQuery<T>;
47
+ get: (parent: AssistantClient) => T["value"];
48
+ source: T["meta"]["source"];
49
+ query: T["meta"]["query"];
54
50
  };
55
51
  /**
56
52
  * Input type for scope definitions - ResourceElement that returns the API value
57
53
  * Can optionally include source/query metadata via DerivedScope
58
54
  */
59
55
  export type ScopeInput<T extends ScopeDefinition> = ResourceElement<{
60
- api: ScopeValue<T>;
56
+ api: T["value"];
61
57
  }>;
62
58
  /**
63
59
  * Map of scope names to their input definitions
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,gBAAgB,CAAC;AAmBxB;;;;;;;;;;;;;;;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;IAClB,EAAE,CAAC,MAAM,SAAS,cAAc,EAC9B,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,GACvC,WAAW,CAAC;CAChB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,gBAAgB,CAAC;AAwBxB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,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;AACvE;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GACpE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,eAAe,IAAI;IACzD,GAAG,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,IAAI,eAAe,CAAC;IAClE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;CACjB,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;IAClB,EAAE,CAAC,MAAM,SAAS,cAAc,EAC9B,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,GACvC,WAAW,CAAC;CAChB,CAAC"}
@@ -18,7 +18,12 @@ export declare const useRootScopes: (rootScopes: ScopesInput, parent: AssistantC
18
18
  * Hook to mount and access derived scopes
19
19
  */
20
20
  export declare const useDerivedScopes: (derivedScopes: ScopesInput, parentClient: AssistantClient) => {
21
- "ERROR: No scopes were defined"?: ScopeField<import("./types").ScopeDefinition<any, any, any>>;
21
+ "ERROR: No scopes were defined"?: ScopeField<import("./types").ScopeDefinition<Record<string, unknown> & {
22
+ getState: () => Record<string, unknown>;
23
+ }, {
24
+ source: string;
25
+ query: Record<string, unknown>;
26
+ }, Record<string, unknown>>>;
22
27
  };
23
28
  /**
24
29
  * Hook to access or extend the AssistantClient
@@ -1 +1 @@
1
- {"version":3,"file":"useAssistantClient.d.ts","sourceRoot":"","sources":["../src/useAssistantClient.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,WAAW,EACX,UAAU,EAGX,MAAM,SAAS,CAAC;AAIjB,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,gBAAgB,CAAC;AA2GxB;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,WAAW,EACvB,QAAQ,eAAe;;SApDT,MAAM,SAAS,cAAc,YAC7B,sBAAsB,CAAC,MAAM,CAAC,YAC9B,sBAAsB,CAAC,MAAM,CAAC;;;;YAoBjC,GACF,CAAC,mCAAuB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAC3D;0BACqB,MAAM,IAAI;;SAzBxB,MAAM,SAAS,cAAc,YAC7B,sBAAsB,CAAC,MAAM,CAAC,YAC9B,sBAAsB,CAAC,MAAM,CAAC;CAqD7C,CAAC;AAqEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,eAAe,WAAW,EAC1B,cAAc,eAAe;;CAK9B,CAAC;AA0BF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAAC;AACtD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"useAssistantClient.d.ts","sourceRoot":"","sources":["../src/useAssistantClient.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,WAAW,EACX,UAAU,EAGX,MAAM,SAAS,CAAC;AAIjB,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,gBAAgB,CAAC;AAqIxB;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,WAAW,EACvB,QAAQ,eAAe;;SApDT,MAAM,SAAS,cAAc,YAC7B,sBAAsB,CAAC,MAAM,CAAC,YAC9B,sBAAsB,CAAC,MAAM,CAAC;;;;YAoBjC,GACF,CAAC,mCAAuB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAC3D;0BACqB,MAAM,IAAI;;SAzBxB,MAAM,SAAS,cAAc,YAC7B,sBAAsB,CAAC,MAAM,CAAC,YAC9B,sBAAsB,CAAC,MAAM,CAAC;CAqD7C,CAAC;AAqEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,eAAe,WAAW,EAC1B,cAAc,eAAe;;;;;;;CAK9B,CAAC;AA0BF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAAC;AACtD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC"}
@@ -17,12 +17,28 @@ import {
17
17
  normalizeEventSelector
18
18
  } from "./EventContext.js";
19
19
  import { withStoreContextProvider } from "./StoreContext.js";
20
+ var RootScopeStoreResource = resource(
21
+ ({
22
+ element,
23
+ events,
24
+ parent
25
+ }) => {
26
+ return withStoreContextProvider(
27
+ { events, parent },
28
+ () => tapInlineResource(element)
29
+ );
30
+ }
31
+ );
20
32
  var RootScopeResource = resource(
21
33
  ({
22
34
  scopeName,
23
- element
35
+ element,
36
+ events,
37
+ parent
24
38
  }) => {
25
- const store = tapResource(asStore(element));
39
+ const store = tapResource(
40
+ asStore(RootScopeStoreResource({ element, events, parent }))
41
+ );
26
42
  return tapMemo(() => {
27
43
  const scopeFunction = (() => store.getState().api);
28
44
  scopeFunction.source = "root";
@@ -41,17 +57,16 @@ var RootScopeResource = resource(
41
57
  var RootScopesResource = resource(
42
58
  ({ scopes, parent }) => {
43
59
  const events = tapInlineResource(EventManager());
44
- const resultEntries = withStoreContextProvider(
45
- { events, parent },
46
- () => tapResources(
47
- Object.entries(scopes).map(
48
- ([scopeName, element]) => RootScopeResource(
49
- {
50
- scopeName,
51
- element
52
- },
53
- { key: scopeName }
54
- )
60
+ const resultEntries = tapResources(
61
+ Object.entries(scopes).map(
62
+ ([scopeName, element]) => RootScopeResource(
63
+ {
64
+ scopeName,
65
+ element,
66
+ events,
67
+ parent
68
+ },
69
+ { key: scopeName }
55
70
  )
56
71
  )
57
72
  );
@@ -1 +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 tapInlineResource,\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\";\nimport {\n EventManager,\n normalizeEventSelector,\n type AssistantEvent,\n type AssistantEventCallback,\n type AssistantEventSelector,\n} from \"./EventContext\";\nimport { withStoreContextProvider } from \"./StoreContext\";\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(\n ({ scopes, parent }: { scopes: ScopesInput; parent: AssistantClient }) => {\n const events = tapInlineResource(EventManager());\n\n const resultEntries = withStoreContextProvider({ events, parent }, () =>\n 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\n const on = <TEvent extends AssistantEvent>(\n selector: AssistantEventSelector<TEvent>,\n callback: AssistantEventCallback<TEvent>,\n ) => {\n const { event } = normalizeEventSelector(selector);\n return events.on(event, callback);\n };\n\n return tapMemo(() => {\n if (resultEntries.length === 0) {\n return {\n scopes: {},\n on,\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 on,\n };\n }, [...resultEntries, events]);\n },\n);\n\n/**\n * Hook to mount and access root scopes\n */\nexport const useRootScopes = (\n rootScopes: ScopesInput,\n parent: AssistantClient,\n) => {\n return useResource(RootScopesResource({ scopes: rootScopes, parent }));\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, baseClient);\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 on: rootFields.on ?? baseClient.on,\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":[]}
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 tapInlineResource,\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\";\nimport {\n EventManager,\n normalizeEventSelector,\n type AssistantEvent,\n type AssistantEventCallback,\n type AssistantEventSelector,\n} from \"./EventContext\";\nimport { withStoreContextProvider } from \"./StoreContext\";\n\n/**\n * Resource that renders a store with the store context provider.\n * This ensures the context is re-established on every re-render.\n */\nconst RootScopeStoreResource = resource(\n <K extends keyof AssistantScopes>({\n element,\n events,\n parent,\n }: {\n element: ScopeInput<AssistantScopes[K]>;\n events: EventManager;\n parent: AssistantClient;\n }) => {\n return withStoreContextProvider({ events, parent }, () =>\n tapInlineResource(element),\n );\n },\n);\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 events,\n parent,\n }: {\n scopeName: K;\n element: ScopeInput<AssistantScopes[K]>;\n events: EventManager;\n parent: AssistantClient;\n }) => {\n const store = tapResource(\n asStore(RootScopeStoreResource({ element, events, parent })),\n );\n\n return tapMemo(() => {\n const scopeFunction = (() => store.getState().api) as ScopeField<\n AssistantScopes[K]\n >;\n scopeFunction.source = \"root\";\n scopeFunction.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(\n ({ scopes, parent }: { scopes: ScopesInput; parent: AssistantClient }) => {\n const events = tapInlineResource(EventManager());\n\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 events,\n parent,\n },\n { key: scopeName },\n ),\n ),\n );\n\n const on = <TEvent extends AssistantEvent>(\n selector: AssistantEventSelector<TEvent>,\n callback: AssistantEventCallback<TEvent>,\n ) => {\n const { event } = normalizeEventSelector(selector);\n return events.on(event, callback);\n };\n\n return tapMemo(() => {\n if (resultEntries.length === 0) {\n return {\n scopes: {},\n on,\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 on,\n };\n }, [...resultEntries, events]);\n },\n);\n\n/**\n * Hook to mount and access root scopes\n */\nexport const useRootScopes = (\n rootScopes: ScopesInput,\n parent: AssistantClient,\n) => {\n return useResource(RootScopesResource({ scopes: rootScopes, parent }));\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, baseClient);\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 on: rootFields.on ?? baseClient.on,\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 return useExtendedAssistantClientImpl(scopes);\n } else {\n return useAssistantContextValue();\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@assistant-ui/store",
3
3
  "description": "Tap-based state management for @assistant-ui",
4
- "version": "0.0.1",
4
+ "version": "0.0.2",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "exports": {
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "sideEffects": false,
22
22
  "dependencies": {
23
- "@assistant-ui/tap": "0.3.1"
23
+ "@assistant-ui/tap": "0.3.2"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "react": "^18.0.0 || ^19.0.0"
@@ -28,7 +28,7 @@
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.10.1",
30
30
  "@types/react": "19.2.7",
31
- "tsx": "^4.20.6",
31
+ "tsx": "^4.21.0",
32
32
  "@assistant-ui/x-buildutils": "0.0.1"
33
33
  },
34
34
  "publishConfig": {
@@ -44,7 +44,6 @@
44
44
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
45
45
  },
46
46
  "scripts": {
47
- "build": "tsx scripts/build.mts",
48
- "lint": "eslint ."
47
+ "build": "tsx scripts/build.mts"
49
48
  }
50
49
  }
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ import type { FC, PropsWithChildren } from "react";
4
+ import { useAssistantState } from "./useAssistantState";
5
+ import type { AssistantState } from "./types";
6
+
7
+ type UseAssistantIfProps = {
8
+ condition: AssistantIf.Condition;
9
+ };
10
+
11
+ const useAssistantIf = (props: UseAssistantIfProps) => {
12
+ return useAssistantState(props.condition);
13
+ };
14
+
15
+ export namespace AssistantIf {
16
+ export type Props = PropsWithChildren<UseAssistantIfProps>;
17
+ export type Condition = (state: AssistantState) => boolean;
18
+ }
19
+
20
+ export const AssistantIf: FC<AssistantIf.Props> = ({ children, condition }) => {
21
+ const result = useAssistantIf({ condition });
22
+ return result ? children : null;
23
+ };
24
+
25
+ AssistantIf.displayName = "AssistantIf";
@@ -1,5 +1,5 @@
1
1
  import { resource } from "@assistant-ui/tap";
2
- import type { ScopeDefinition, ScopeValue, DerivedScopeProps } from "./types";
2
+ import type { ScopeDefinition, DerivedScopeProps } from "./types";
3
3
 
4
4
  /**
5
5
  * Creates a derived scope field that memoizes based on source and query.
@@ -7,15 +7,17 @@ import type { ScopeDefinition, ScopeValue, DerivedScopeProps } from "./types";
7
7
  *
8
8
  * @example
9
9
  * ```typescript
10
- * const MessageScope = DerivedScope<MessageScopeDefinition>({
11
- * source: "thread",
12
- * query: { type: "index", index: 0 },
13
- * get: () => messageApi,
10
+ * const client = useAssistantClient({
11
+ * message: DerivedScope({
12
+ * source: "thread",
13
+ * query: { index: 0 },
14
+ * get: (client) => client.thread().message({ index: 0 }),
15
+ * }),
14
16
  * });
15
17
  * ```
16
18
  */
17
19
  export const DerivedScope = resource(
18
- <T extends ScopeDefinition>(config: DerivedScopeProps<T>): ScopeValue<T> => {
19
- return config;
20
+ <T extends ScopeDefinition>(_config: DerivedScopeProps<T>): null => {
21
+ return null;
20
22
  },
21
23
  );
@@ -1,21 +1,5 @@
1
1
  import { resource, tapMemo } from "@assistant-ui/tap";
2
- import type { Unsubscribe } from "./types";
3
-
4
- /**
5
- * Module augmentation interface for custom events.
6
- *
7
- * @example
8
- * ```typescript
9
- * declare module "@assistant-ui/store" {
10
- * interface AssistantEventRegistry {
11
- * "thread.run-start": { threadId: string };
12
- * "custom.my-event": { data: string };
13
- * }
14
- * }
15
- * ```
16
- */
17
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
18
- export interface AssistantEventRegistry {}
2
+ import type { AssistantScopes, Unsubscribe } from "./types";
19
3
 
20
4
  /**
21
5
  * Module augmentation interface for event scope configuration.
@@ -31,17 +15,41 @@ export interface AssistantEventRegistry {}
31
15
  * }
32
16
  * ```
33
17
  */
34
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
35
18
  export interface AssistantEventScopeConfig {}
36
19
 
37
- export type AssistantEventMap = AssistantEventRegistry & {
20
+ type UnionToIntersection<U> = (
21
+ U extends unknown
22
+ ? (x: U) => void
23
+ : never
24
+ ) extends (x: infer I) => void
25
+ ? I
26
+ : never;
27
+
28
+ /**
29
+ * Event map derived from scope event definitions
30
+ */
31
+ export type ScopeEventMap = UnionToIntersection<
32
+ {
33
+ [K in keyof AssistantScopes]: AssistantScopes[K] extends {
34
+ events: infer E;
35
+ }
36
+ ? E extends Record<string, unknown>
37
+ ? E
38
+ : never
39
+ : never;
40
+ }[keyof AssistantScopes]
41
+ >;
42
+
43
+ type WildcardPayload = {
44
+ [K in keyof ScopeEventMap]: {
45
+ event: K;
46
+ payload: ScopeEventMap[K];
47
+ };
48
+ }[keyof ScopeEventMap];
49
+
50
+ export type AssistantEventMap = ScopeEventMap & {
38
51
  // Catch-all
39
- "*": {
40
- [K in Exclude<keyof AssistantEventRegistry, "*">]: {
41
- event: K;
42
- payload: AssistantEventRegistry[K];
43
- };
44
- }[Exclude<keyof AssistantEventRegistry, "*">];
52
+ "*": WildcardPayload;
45
53
  };
46
54
 
47
55
  export type AssistantEvent = keyof AssistantEventMap;
@@ -167,12 +175,7 @@ export const EventManager = resource(() => {
167
175
  // Emit to wildcard listeners
168
176
  if (wildcardListeners) {
169
177
  for (const callback of wildcardListeners) {
170
- (
171
- callback as (payload: {
172
- event: typeof event;
173
- payload: typeof payload;
174
- }) => void
175
- )({ event, payload });
178
+ callback({ event, payload } as any);
176
179
  }
177
180
  }
178
181
  });
package/src/index.ts CHANGED
@@ -1,25 +1,34 @@
1
+ // hooks
1
2
  export { useAssistantClient } from "./useAssistantClient";
2
3
  export { useAssistantState } from "./useAssistantState";
4
+ export { useAssistantEvent } from "./useAssistantEvent";
5
+
6
+ // components
7
+ export { AssistantIf } from "./AssistantIf";
3
8
  export { AssistantProvider } from "./AssistantContext";
4
- export type { AssistantScopes, AssistantClient, AssistantState } from "./types";
9
+
10
+ // resources
5
11
  export { DerivedScope } from "./DerivedScope";
6
- export type { ApiObject } from "./tapApi";
7
- export { tapApi } from "./tapApi";
12
+
13
+ // tap hooks
14
+ export { tapApi, type ApiObject } from "./tapApi";
15
+ export { tapStoreContext, type StoreContextValue } from "./StoreContext";
8
16
  export { tapLookupResources } from "./tapLookupResources";
9
- export { tapStoreList } from "./tapStoreList";
10
- export type { TapStoreListConfig } from "./tapStoreList";
17
+ export { tapStoreList, type TapStoreListConfig } from "./tapStoreList";
18
+
19
+ // registration
11
20
  export { registerAssistantScope } from "./ScopeRegistry";
12
21
 
13
- export type { AssistantScopeRegistry } from "./types";
22
+ // types
23
+ export type {
24
+ AssistantScopes,
25
+ AssistantScopeRegistry,
26
+ AssistantClient,
27
+ AssistantState,
28
+ } from "./types";
14
29
 
15
- // Events & Store Context
16
- export { tapStoreContext } from "./StoreContext";
17
- export type { StoreContextValue } from "./StoreContext";
18
- export { useAssistantEvent } from "./useAssistantEvent";
19
- export { normalizeEventSelector, checkEventScope } from "./EventContext";
20
30
  export type {
21
31
  AssistantEvent,
22
- AssistantEventRegistry,
23
32
  AssistantEventScopeConfig,
24
33
  AssistantEventMap,
25
34
  AssistantEventScope,
package/src/types.ts CHANGED
@@ -5,21 +5,26 @@ import type {
5
5
  AssistantEventSelector,
6
6
  } from "./EventContext";
7
7
 
8
+ type ScopeValueType = Record<string, unknown> & {
9
+ getState: () => Record<string, unknown>;
10
+ };
11
+ type ScopeMetaType = { source: string; query: Record<string, unknown> };
12
+
8
13
  /**
9
14
  * Definition of a scope in the assistant client (internal type)
10
15
  * @template TValue - The API type (must include getState() and any actions)
11
- * @template TSource - The parent scope name (or "root" for top-level scopes)
12
- * @template TQuery - The query parameters needed to access this scope from its source
16
+ * @template TMeta - Source/query metadata (use ScopeMeta or discriminated union)
17
+ * @template TEvents - Optional events that this scope can emit
13
18
  * @internal
14
19
  */
15
20
  export type ScopeDefinition<
16
- TValue = any,
17
- TSource extends string | "root" = any,
18
- TQuery = any,
21
+ TValue extends ScopeValueType = ScopeValueType,
22
+ TMeta extends ScopeMetaType = ScopeMetaType,
23
+ TEvents extends Record<string, unknown> = Record<string, unknown>,
19
24
  > = {
20
25
  value: TValue;
21
- source: TSource;
22
- query: TQuery;
26
+ meta: TMeta;
27
+ events: TEvents;
23
28
  };
24
29
 
25
30
  /**
@@ -31,58 +36,43 @@ export type ScopeDefinition<
31
36
  * interface AssistantScopeRegistry {
32
37
  * foo: {
33
38
  * value: { getState: () => { bar: string }; updateBar: (bar: string) => void };
34
- * source: "root";
35
- * query: Record<string, never>;
39
+ * meta: { source: "root"; query: Record<string, never> };
40
+ * events: {
41
+ * "foo.updated": { id: string; newValue: string };
42
+ * "foo.deleted": { id: string };
43
+ * };
44
+ * };
45
+ * // Example with multiple sources (discriminated union):
46
+ * bar: {
47
+ * value: { getState: () => { id: string } };
48
+ * meta:
49
+ * | { source: "fooList"; query: { index: number } }
50
+ * | { source: "barList"; query: { id: string } };
51
+ * events: Record<string, never>;
36
52
  * };
37
53
  * }
38
54
  * }
39
55
  * ```
40
56
  */
41
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
42
57
  export interface AssistantScopeRegistry {}
43
58
 
44
59
  export type AssistantScopes = keyof AssistantScopeRegistry extends never
45
60
  ? Record<"ERROR: No scopes were defined", ScopeDefinition>
46
61
  : { [K in keyof AssistantScopeRegistry]: AssistantScopeRegistry[K] };
47
-
48
- /**
49
- * Helper type to extract the value type from a scope definition
50
- */
51
- export type ScopeValue<T extends ScopeDefinition> = T["value"];
52
-
53
- /**
54
- * Helper type to extract the source type from a scope definition
55
- */
56
- export type ScopeSource<T extends ScopeDefinition> = T["source"];
57
-
58
- /**
59
- * Helper type to extract the query type from a scope definition
60
- */
61
- export type ScopeQuery<T extends ScopeDefinition> = T["query"];
62
-
63
62
  /**
64
63
  * Type for a scope field - a function that returns the current API value,
65
- * with source and query metadata attached
64
+ * with source/query metadata attached (derived from meta)
66
65
  */
67
- export type ScopeField<T extends ScopeDefinition> = (() => ScopeValue<T>) &
68
- (
69
- | {
70
- source: ScopeSource<T>;
71
- query: ScopeQuery<T>;
72
- }
73
- | {
74
- source: null;
75
- query: null;
76
- }
77
- );
66
+ export type ScopeField<T extends ScopeDefinition> = (() => T["value"]) &
67
+ (T["meta"] | { source: null; query: null });
78
68
 
79
69
  /**
80
70
  * Props passed to a derived scope resource element
81
71
  */
82
72
  export type DerivedScopeProps<T extends ScopeDefinition> = {
83
- get: (parent: AssistantClient) => ScopeValue<T>;
84
- source: ScopeSource<T>;
85
- query: ScopeQuery<T>;
73
+ get: (parent: AssistantClient) => T["value"];
74
+ source: T["meta"]["source"];
75
+ query: T["meta"]["query"];
86
76
  };
87
77
 
88
78
  /**
@@ -90,7 +80,7 @@ export type DerivedScopeProps<T extends ScopeDefinition> = {
90
80
  * Can optionally include source/query metadata via DerivedScope
91
81
  */
92
82
  export type ScopeInput<T extends ScopeDefinition> = ResourceElement<{
93
- api: ScopeValue<T>;
83
+ api: T["value"];
94
84
  }>;
95
85
 
96
86
  /**
@@ -29,6 +29,26 @@ import {
29
29
  } from "./EventContext";
30
30
  import { withStoreContextProvider } from "./StoreContext";
31
31
 
32
+ /**
33
+ * Resource that renders a store with the store context provider.
34
+ * This ensures the context is re-established on every re-render.
35
+ */
36
+ const RootScopeStoreResource = resource(
37
+ <K extends keyof AssistantScopes>({
38
+ element,
39
+ events,
40
+ parent,
41
+ }: {
42
+ element: ScopeInput<AssistantScopes[K]>;
43
+ events: EventManager;
44
+ parent: AssistantClient;
45
+ }) => {
46
+ return withStoreContextProvider({ events, parent }, () =>
47
+ tapInlineResource(element),
48
+ );
49
+ },
50
+ );
51
+
32
52
  /**
33
53
  * Resource for a single root scope
34
54
  * Returns a tuple of [scopeName, {scopeFunction, subscribe, flushSync}]
@@ -37,18 +57,24 @@ const RootScopeResource = resource(
37
57
  <K extends keyof AssistantScopes>({
38
58
  scopeName,
39
59
  element,
60
+ events,
61
+ parent,
40
62
  }: {
41
63
  scopeName: K;
42
64
  element: ScopeInput<AssistantScopes[K]>;
65
+ events: EventManager;
66
+ parent: AssistantClient;
43
67
  }) => {
44
- const store = tapResource(asStore(element));
68
+ const store = tapResource(
69
+ asStore(RootScopeStoreResource({ element, events, parent })),
70
+ );
45
71
 
46
72
  return tapMemo(() => {
47
73
  const scopeFunction = (() => store.getState().api) as ScopeField<
48
74
  AssistantScopes[K]
49
75
  >;
50
76
  scopeFunction.source = "root";
51
- scopeFunction.query = {} as AssistantScopes[K]["query"];
77
+ scopeFunction.query = {};
52
78
 
53
79
  return [
54
80
  scopeName,
@@ -70,18 +96,18 @@ const RootScopesResource = resource(
70
96
  ({ scopes, parent }: { scopes: ScopesInput; parent: AssistantClient }) => {
71
97
  const events = tapInlineResource(EventManager());
72
98
 
73
- const resultEntries = withStoreContextProvider({ events, parent }, () =>
74
- tapResources(
75
- Object.entries(scopes).map(([scopeName, element]) =>
76
- RootScopeResource(
77
- {
78
- scopeName: scopeName as keyof AssistantScopes,
79
- element: element as ScopeInput<
80
- AssistantScopes[keyof AssistantScopes]
81
- >,
82
- },
83
- { key: scopeName },
84
- ),
99
+ const resultEntries = tapResources(
100
+ Object.entries(scopes).map(([scopeName, element]) =>
101
+ RootScopeResource(
102
+ {
103
+ scopeName: scopeName as keyof AssistantScopes,
104
+ element: element as ScopeInput<
105
+ AssistantScopes[keyof AssistantScopes]
106
+ >,
107
+ events,
108
+ parent,
109
+ },
110
+ { key: scopeName },
85
111
  ),
86
112
  ),
87
113
  );
@@ -270,10 +296,8 @@ export function useAssistantClient(): AssistantClient;
270
296
  export function useAssistantClient(scopes: ScopesInput): AssistantClient;
271
297
  export function useAssistantClient(scopes?: ScopesInput): AssistantClient {
272
298
  if (scopes) {
273
- // eslint-disable-next-line react-hooks/rules-of-hooks
274
299
  return useExtendedAssistantClientImpl(scopes);
275
300
  } else {
276
- // eslint-disable-next-line react-hooks/rules-of-hooks
277
301
  return useAssistantContextValue();
278
302
  }
279
303
  }