🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

@assistant-ui/store

Package Overview
Dependencies
Maintainers
2
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@assistant-ui/store - npm Package Compare versions

Comparing version
0.2.14
to
0.2.16
+120
src/__tests__/useAuiHost.test.tsx
// @vitest-environment jsdom
import type { ReactNode } from "react";
import { useEffect, useLayoutEffect, useState } from "react";
import { act, cleanup, render } from "@testing-library/react";
import { afterEach, describe, expect, it } from "vitest";
import { flushTapSync, resource } from "@assistant-ui/tap";
import { AuiProvider } from "../utils/react-assistant-context";
import { useAui } from "../useAui";
import { useAuiState } from "../useAuiState";
const makeTestClient = (log: string[]) => {
// Runs inside the tap host; "react" imports route to tap's dispatcher.
const useTestClient = () => {
const [count, setCount] = useState(0);
useEffect(() => {
log.push("tap effect");
return () => {
log.push("tap cleanup");
};
}, []);
return {
getState: () => ({ count }),
setCount: (n: number) => setCount(n),
};
};
return resource(useTestClient);
};
const Provider = ({
client,
children,
}: {
client: ReturnType<ReturnType<typeof makeTestClient>>;
children: ReactNode;
}) => {
const aui = useAui({ thread: client } as unknown as useAui.Props);
return <AuiProvider value={aui}>{children}</AuiProvider>;
};
describe("useAui tap host", () => {
afterEach(() => {
cleanup();
});
it("commits client effects passively, ahead of consumer effects", () => {
const log: string[] = [];
const TestClient = makeTestClient(log);
function Consumer() {
useLayoutEffect(() => {
log.push("consumer layout");
}, []);
useEffect(() => {
log.push("consumer effect");
}, []);
return null;
}
render(
<Provider client={TestClient()}>
<Consumer />
</Provider>,
);
// "consumer layout" first: the commit no longer blocks paint.
// "tap effect" before "consumer effect": AuiProvider mounts the host's
// commit ahead of its children's effects, with no opt-in by the child.
expect(log).toEqual(["consumer layout", "tap effect", "consumer effect"]);
});
it("commits via the host's own fallback without an AuiProvider", () => {
const log: string[] = [];
const TestClient = makeTestClient(log);
const client = TestClient();
function HostOnly() {
useAui({ thread: client } as unknown as useAui.Props);
return null;
}
render(<HostOnly />);
expect(log).toEqual(["tap effect"]);
});
it("updates flow through to useAuiState consumers", () => {
const log: string[] = [];
const TestClient = makeTestClient(log);
let api!: { setCount: (n: number) => void };
let observed!: number;
function Consumer() {
const aui = useAui();
api = (aui as any).thread();
observed = useAuiState((s) => (s as any).thread.count);
return null;
}
render(
<Provider client={TestClient()}>
<Consumer />
</Provider>,
);
expect(observed).toBe(0);
act(() => flushTapSync(() => api.setCount(7)));
expect(observed).toBe(7);
});
it("cleans up client effects when the host unmounts", () => {
const log: string[] = [];
const TestClient = makeTestClient(log);
const { unmount } = render(
<Provider client={TestClient()}>{null}</Provider>,
);
unmount();
expect(log).toEqual(["tap effect", "tap cleanup"]);
});
});
+4
-4
import { AssistantClient, ClientElement, ClientNames } from "./types/client.js";
import { DerivedElement } from "./Derived.js";
import { ResourceElement } from "@assistant-ui/tap";

@@ -8,7 +7,8 @@ //#region src/attachTransformScopes.d.ts

type TransformScopesFn = (scopes: ScopesConfig, parent: AssistantClient) => void;
declare function attachTransformScopes<T extends (...args: any[]) => ResourceElement<any>>(resource: T, transform: TransformScopesFn): void;
declare function forwardTransformScopes<T extends (...args: any[]) => ResourceElement<any>, S extends (...args: any[]) => ResourceElement<any>>(target: T, source: S): void;
declare function getTransformScopes<T extends (...args: any[]) => ResourceElement<any>>(resource: T): TransformScopesFn | undefined;
type Hook = (...args: any[]) => any;
declare function attachTransformScopes(hook: Hook, transform: TransformScopesFn): void;
declare function forwardTransformScopes(target: Hook, source: Hook): void;
declare function getTransformScopes(hook: Hook): TransformScopesFn | undefined;
//#endregion
export { ScopesConfig, attachTransformScopes, forwardTransformScopes, getTransformScopes };
//# sourceMappingURL=attachTransformScopes.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"attachTransformScopes.d.ts","names":[],"sources":["../src/attachTransformScopes.ts"],"mappings":";;;;;KAUY,YAAA,WACJ,WAAA,IAAe,aAAA,CAAc,CAAA,IAAK,cAAA,CAAe,CAAA;AAAA,KAGpD,iBAAA,IACH,MAAA,EAAQ,YAAA,EACR,MAAA,EAAQ,eAAe;AAAA,iBAOT,qBAAA,eACA,IAAA,YAAgB,eAAA,OAC9B,QAAA,EAAU,CAAA,EAAG,SAAA,EAAW,iBAAA;AAAA,iBAQV,sBAAA,eACA,IAAA,YAAgB,eAAA,qBAChB,IAAA,YAAgB,eAAA,OAC9B,MAAA,EAAQ,CAAA,EAAG,MAAA,EAAQ,CAAA;AAAA,iBAgBL,kBAAA,eACA,IAAA,YAAgB,eAAA,OAC9B,QAAA,EAAU,CAAA,GAAI,iBAAA"}
{"version":3,"file":"attachTransformScopes.d.ts","names":[],"sources":["../src/attachTransformScopes.ts"],"mappings":";;;;KASY,YAAA,WACJ,WAAA,IAAe,aAAA,CAAc,CAAA,IAAK,cAAA,CAAe,CAAA;AAAA,KAGpD,iBAAA,IACH,MAAA,EAAQ,YAAA,EACR,MAAA,EAAQ,eAAe;AAAA,KAKpB,IAAA,OAAW,IAAI;AAAA,iBAKJ,qBAAA,CACd,IAAA,EAAM,IAAA,EACN,SAAA,EAAW,iBAAiB;AAAA,iBASd,sBAAA,CAAuB,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,IAAI;AAAA,iBAgBjD,kBAAA,CAAmB,IAAA,EAAM,IAAA,GAAO,iBAAiB"}
//#region src/attachTransformScopes.ts
const TRANSFORM_SCOPES = Symbol("assistant-ui.transform-scopes");
function attachTransformScopes(resource, transform) {
const r = resource;
if (r[TRANSFORM_SCOPES]) throw new Error("transformScopes is already attached to this resource");
r[TRANSFORM_SCOPES] = transform;
function attachTransformScopes(hook, transform) {
const h = hook;
if (h[TRANSFORM_SCOPES]) throw new Error("transformScopes is already attached to this resource");
h[TRANSFORM_SCOPES] = transform;
}

@@ -11,12 +11,12 @@ function forwardTransformScopes(target, source) {

if (!sourceTransform) return;
const r = target;
const existingTransform = r[TRANSFORM_SCOPES];
if (existingTransform) r[TRANSFORM_SCOPES] = (scopes, parent) => {
const t = target;
const existingTransform = t[TRANSFORM_SCOPES];
if (existingTransform) t[TRANSFORM_SCOPES] = (scopes, parent) => {
sourceTransform(scopes, parent);
existingTransform(scopes, parent);
};
else r[TRANSFORM_SCOPES] = sourceTransform;
else t[TRANSFORM_SCOPES] = sourceTransform;
}
function getTransformScopes(resource) {
return resource[TRANSFORM_SCOPES];
function getTransformScopes(hook) {
return hook[TRANSFORM_SCOPES];
}

@@ -23,0 +23,0 @@ //#endregion

@@ -1,1 +0,1 @@

{"version":3,"file":"attachTransformScopes.js","names":[],"sources":["../src/attachTransformScopes.ts"],"sourcesContent":["import { type ResourceElement } from \"@assistant-ui/tap\";\nimport type {\n AssistantClient,\n ClientElement,\n ClientNames,\n} from \"./types/client\";\nimport type { DerivedElement } from \"./Derived\";\n\nconst TRANSFORM_SCOPES = Symbol(\"assistant-ui.transform-scopes\");\n\nexport type ScopesConfig = {\n [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;\n};\n\ntype TransformScopesFn = (\n scopes: ScopesConfig,\n parent: AssistantClient,\n) => void;\n\ntype ResourceWithTransformScopes = {\n [TRANSFORM_SCOPES]?: TransformScopesFn;\n};\n\nexport function attachTransformScopes<\n T extends (...args: any[]) => ResourceElement<any>,\n>(resource: T, transform: TransformScopesFn): void {\n const r = resource as T & ResourceWithTransformScopes;\n if (r[TRANSFORM_SCOPES]) {\n throw new Error(\"transformScopes is already attached to this resource\");\n }\n r[TRANSFORM_SCOPES] = transform;\n}\n\nexport function forwardTransformScopes<\n T extends (...args: any[]) => ResourceElement<any>,\n S extends (...args: any[]) => ResourceElement<any>,\n>(target: T, source: S): void {\n const sourceTransform = getTransformScopes(source);\n if (!sourceTransform) return;\n\n const r = target as T & ResourceWithTransformScopes;\n const existingTransform = r[TRANSFORM_SCOPES];\n if (existingTransform) {\n r[TRANSFORM_SCOPES] = (scopes, parent) => {\n sourceTransform(scopes, parent);\n existingTransform(scopes, parent);\n };\n } else {\n r[TRANSFORM_SCOPES] = sourceTransform;\n }\n}\n\nexport function getTransformScopes<\n T extends (...args: any[]) => ResourceElement<any>,\n>(resource: T): TransformScopesFn | undefined {\n return (resource as T & ResourceWithTransformScopes)[TRANSFORM_SCOPES];\n}\n"],"mappings":";AAQA,MAAM,mBAAmB,OAAO,+BAA+B;AAe/D,SAAgB,sBAEd,UAAa,WAAoC;CACjD,MAAM,IAAI;CACV,IAAI,EAAE,mBACJ,MAAM,IAAI,MAAM,sDAAsD;CAExE,EAAE,oBAAoB;AACxB;AAEA,SAAgB,uBAGd,QAAW,QAAiB;CAC5B,MAAM,kBAAkB,mBAAmB,MAAM;CACjD,IAAI,CAAC,iBAAiB;CAEtB,MAAM,IAAI;CACV,MAAM,oBAAoB,EAAE;CAC5B,IAAI,mBACF,EAAE,qBAAqB,QAAQ,WAAW;EACxC,gBAAgB,QAAQ,MAAM;EAC9B,kBAAkB,QAAQ,MAAM;CAClC;MAEA,EAAE,oBAAoB;AAE1B;AAEA,SAAgB,mBAEd,UAA4C;CAC5C,OAAQ,SAA6C;AACvD"}
{"version":3,"file":"attachTransformScopes.js","names":[],"sources":["../src/attachTransformScopes.ts"],"sourcesContent":["import type {\n AssistantClient,\n ClientElement,\n ClientNames,\n} from \"./types/client\";\nimport type { DerivedElement } from \"./Derived\";\n\nconst TRANSFORM_SCOPES = Symbol(\"assistant-ui.transform-scopes\");\n\nexport type ScopesConfig = {\n [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;\n};\n\ntype TransformScopesFn = (\n scopes: ScopesConfig,\n parent: AssistantClient,\n) => void;\n\n// Transforms are keyed by the resource's underlying hook (the function passed to\n// `resource()`), since that is the identity a `ResourceElement` carries.\ntype Hook = (...args: any[]) => any;\ntype HookWithTransformScopes = Hook & {\n [TRANSFORM_SCOPES]?: TransformScopesFn;\n};\n\nexport function attachTransformScopes(\n hook: Hook,\n transform: TransformScopesFn,\n): void {\n const h = hook as HookWithTransformScopes;\n if (h[TRANSFORM_SCOPES]) {\n throw new Error(\"transformScopes is already attached to this resource\");\n }\n h[TRANSFORM_SCOPES] = transform;\n}\n\nexport function forwardTransformScopes(target: Hook, source: Hook): void {\n const sourceTransform = getTransformScopes(source);\n if (!sourceTransform) return;\n\n const t = target as HookWithTransformScopes;\n const existingTransform = t[TRANSFORM_SCOPES];\n if (existingTransform) {\n t[TRANSFORM_SCOPES] = (scopes, parent) => {\n sourceTransform(scopes, parent);\n existingTransform(scopes, parent);\n };\n } else {\n t[TRANSFORM_SCOPES] = sourceTransform;\n }\n}\n\nexport function getTransformScopes(hook: Hook): TransformScopesFn | undefined {\n return (hook as HookWithTransformScopes)[TRANSFORM_SCOPES];\n}\n"],"mappings":";AAOA,MAAM,mBAAmB,OAAO,+BAA+B;AAkB/D,SAAgB,sBACd,MACA,WACM;CACN,MAAM,IAAI;CACV,IAAI,EAAE,mBACJ,MAAM,IAAI,MAAM,sDAAsD;CAExE,EAAE,oBAAoB;AACxB;AAEA,SAAgB,uBAAuB,QAAc,QAAoB;CACvE,MAAM,kBAAkB,mBAAmB,MAAM;CACjD,IAAI,CAAC,iBAAiB;CAEtB,MAAM,IAAI;CACV,MAAM,oBAAoB,EAAE;CAC5B,IAAI,mBACF,EAAE,qBAAqB,QAAQ,WAAW;EACxC,gBAAgB,QAAQ,MAAM;EAC9B,kBAAkB,QAAQ,MAAM;CAClC;MAEA,EAAE,oBAAoB;AAE1B;AAEA,SAAgB,mBAAmB,MAA2C;CAC5E,OAAQ,KAAiC;AAC3C"}

@@ -24,4 +24,5 @@ import { AssistantClient, AssistantClientAccessor, ClientMeta, ClientNames } from "./types/client.js";

*/
declare const Derived: <K extends ClientNames>(props: Derived.Props<K>) => ResourceElement<null, Derived.Props<K>>;
type DerivedElement<K extends ClientNames> = ResourceElement<null, Derived.Props<K>>;
declare const useDerived: <K extends ClientNames>(_config: Derived.Props<K>) => null;
declare const Derived: <K extends ClientNames>(_config: Derived.Props<K>) => ResourceElement<null, [_config: Derived.Props<K>]>;
type DerivedElement<K extends ClientNames> = ResourceElement<null, [Derived.Props<K>]>;
declare namespace Derived {

@@ -36,3 +37,3 @@ /**

//#endregion
export { Derived, DerivedElement };
export { Derived, DerivedElement, useDerived };
//# sourceMappingURL=Derived.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"Derived.d.ts","names":[],"sources":["../src/Derived.ts"],"mappings":";;;;;;AA2BA;;;;;;;;;;;;;;;;;cAAa,OAAA,aAA8C,WAAA,EAAW,KAAA,EAAA,OAAA,CAAA,KAAA,CAAA,CAAA,MAAA,eAAA,OAAA,OAAA,CAAA,KAAA,CAAA,CAAA;AAAA,KAM1D,cAAA,WAAyB,WAAA,IAAe,eAAA,OAElD,OAAA,CAAQ,KAAA,CAAM,CAAA;AAAA,kBAGC,OAAA;EAXqD;;AAAA;EAAA,KAexD,KAAA,WAAgB,WAAA;IAC1B,GAAA,GAAM,MAAA,EAAQ,eAAA,KAAoB,UAAA,CAAW,uBAAA,CAAwB,CAAA;EAAA,IACnE,UAAA,CAAW,CAAA;AAAA"}
{"version":3,"file":"Derived.d.ts","names":[],"sources":["../src/Derived.ts"],"mappings":";;;;;;AA6BA;;;;;;;;;;;;;;;AAC2B;AAK3B;cANa,UAAA,aAAwB,WAAA,EACnC,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,CAAA;AAAA,cAKZ,OAAA,aANwB,WAAA,EAAW,OAAA,EAAA,OAAA,CAAA,KAAA,CAAA,CAAA,MAAA,eAAA,QAAA,OAAA,EAAA,OAAA,CAAA,KAAA,CAAA,CAAA;AAAA,KAQpC,cAAA,WAAyB,WAAA,IAAe,eAAA,QAEjD,OAAA,CAAQ,KAAA,CAAM,CAAA;AAAA,kBAGA,OAAA;EAb+B;;;EAAA,KAiBlC,KAAA,WAAgB,WAAA;IAC1B,GAAA,GAAM,MAAA,EAAQ,eAAA,KAAoB,UAAA,CAAW,uBAAA,CAAwB,CAAA;EAAA,IACnE,UAAA,CAAW,CAAA;AAAA"}

@@ -22,8 +22,9 @@ import { resource } from "@assistant-ui/tap";

*/
const Derived = resource(function Derived(_config) {
const useDerived = (_config) => {
return null;
});
};
const Derived = resource(useDerived);
//#endregion
export { Derived };
export { Derived, useDerived };
//# sourceMappingURL=Derived.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"Derived.js","names":[],"sources":["../src/Derived.ts"],"sourcesContent":["import { resource, type ResourceElement } from \"@assistant-ui/tap\";\nimport type {\n AssistantClient,\n ClientNames,\n AssistantClientAccessor,\n ClientMeta,\n} from \"./types/client\";\n\n/**\n * Creates a derived client field that references a client from a parent scope.\n * The get callback always calls the most recent version (useEffectEvent pattern).\n *\n * IMPORTANT: The `get` callback must return a client that was created via\n * `useClientResource` (or `useClientLookup`/`useClientList` which use it internally).\n * This is required for event scoping to work correctly.\n *\n * @example\n * ```typescript\n * const aui = useAui({\n * message: Derived({\n * source: \"thread\",\n * query: { index: 0 },\n * get: (aui) => aui.thread().message({ index: 0 }),\n * }),\n * });\n * ```\n */\nexport const Derived = resource(function Derived<K extends ClientNames>(\n _config: Derived.Props<K>,\n): null {\n return null;\n});\n\nexport type DerivedElement<K extends ClientNames> = ResourceElement<\n null,\n Derived.Props<K>\n>;\n\nexport namespace Derived {\n /**\n * Props passed to a derived client resource element.\n */\n export type Props<K extends ClientNames> = {\n get: (client: AssistantClient) => ReturnType<AssistantClientAccessor<K>>;\n } & ClientMeta<K>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,UAAU,SAAS,SAAS,QACvC,SACM;CACN,OAAO;AACT,CAAC"}
{"version":3,"file":"Derived.js","names":[],"sources":["../src/Derived.ts"],"sourcesContent":["import { resource, type ResourceElement } from \"@assistant-ui/tap\";\nimport type {\n AssistantClient,\n ClientNames,\n AssistantClientAccessor,\n ClientMeta,\n} from \"./types/client\";\n\n/**\n * Creates a derived client field that references a client from a parent scope.\n * The get callback always calls the most recent version (useEffectEvent pattern).\n *\n * IMPORTANT: The `get` callback must return a client that was created via\n * `useClientResource` (or `useClientLookup`/`useClientList` which use it internally).\n * This is required for event scoping to work correctly.\n *\n * @example\n * ```typescript\n * const aui = useAui({\n * message: Derived({\n * source: \"thread\",\n * query: { index: 0 },\n * get: (aui) => aui.thread().message({ index: 0 }),\n * }),\n * });\n * ```\n */\n// Exported so consumers (e.g. splitClients) can identify a derived element by its\n// hook: a `Derived(...)` element carries `hook === useDerived`.\nexport const useDerived = <K extends ClientNames>(\n _config: Derived.Props<K>,\n): null => {\n return null;\n};\n\nexport const Derived = resource(useDerived);\n\nexport type DerivedElement<K extends ClientNames> = ResourceElement<\n null,\n [Derived.Props<K>]\n>;\n\nexport namespace Derived {\n /**\n * Props passed to a derived client resource element.\n */\n export type Props<K extends ClientNames> = {\n get: (client: AssistantClient) => ReturnType<AssistantClientAccessor<K>>;\n } & ClientMeta<K>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,cACX,YACS;CACT,OAAO;AACT;AAEA,MAAa,UAAU,SAAS,UAAU"}

@@ -77,3 +77,3 @@ import { AssistantEventCallback, AssistantEventName, AssistantEventSelector } from "./events.js";

* ```typescript
* const FooResource = resource(function FooResource(): ClientResourceOutput<"foo"> {
* const useFoo = (): ClientResourceOutput<"foo"> => {
* const [state, setState] = useState({ bar: "hello" });

@@ -84,3 +84,5 @@ * return {

* };
* });
* };
*
* const FooResource = resource(useFoo);
* ```

@@ -87,0 +89,0 @@ */

@@ -1,1 +0,1 @@

{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/types/client.ts"],"mappings":";;;;;;AAUA;UAAiB,aAAA;EAAA,CACd,GAAA,wBAA2B,IAAI;AAAA;AAAA,KAG7B,cAAA;EAAmB,MAAA,EAAQ,WAAA;EAAa,KAAA,EAAO,MAAM;AAAA;;;;;;;AAAA;KAS9C,YAAA,kBACO,aAAA,GAAgB,aAAA,gBACnB,cAAA,0BACE,MAAA;EAEhB,OAAA,EAAS,QAAA;EACT,IAAA,GAAO,KAAA;EACP,MAAA,GAAS,OAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;AAAO;AAgClB;;;;AAA8B;AAAG;;UAAhB,aAAA;AAAA,KAEZ,gBAAA,WAA2B,WAAA,IAAe,MAAA,IAC1C,CAAA;AAAA,KAIA,WAAA;EACH,OAAA,EAAS,MAAA,CAAO,CAAA,QAAS,CAAA;EACzB,IAAA;IAAQ,MAAA,EAAQ,WAAA;IAAa,KAAA,EAAO,MAAA,CAAO,CAAA,EAAG,CAAA;EAAA;EAC9C,MAAA,EAAQ,MAAA,IAAU,CAAA,KAAM,CAAA;AAAA;AAAA,KAGrB,cAAA,iBAA+B,aAAA,IAAiB,aAAA,CAAc,CAAA;EACjE,OAAA,EAAS,aAAA;AAAA,yBAEc,aAAA,CAAc,CAAA,IACjC,aAAA,CAAc,CAAA,kBAAmB,cAAA,0BACR,aAAA,CAAc,CAAA,IACnC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA,IACd,WAAA,WAAsB,CAAA,uCACxB,aAAA,CAAc,CAAA,IAChB,WAAA,WAAsB,CAAA,4DACD,aAAA,CAAc,CAAA,IACnC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA,IACd,WAAA,WAAsB,CAAA,uCACxB,aAAA,CAAc,CAAA,IAClB,WAAA,WAAsB,CAAA;AAAA,KAErB,aAAA,SAAsB,aAAA;EAErB,gCAAA,EAAkC,WAAA;AAAA,kBAEtB,aAAA,GAAgB,cAAA,CAAe,CAAA;;;;;;;;;;;;;;;KAgBrC,YAAA,WAAuB,WAAA,IAAe,aAAA,CAAc,CAAA,eAC9D,aAAA;AAAA,KAEU,WAAA,SAAoB,aAAa,mBAAmB,CAAA;AAAA,KAEpD,YAAA,WAAuB,WAAA,2BACV,aAAA,CAAc,CAAA,IACjC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA;AAAA,KAIV,UAAA,WAAqB,WAAA,yBACV,aAAA,CAAc,CAAA,IAC/B,IAAA,CACE,aAAA,CAAc,CAAA,kBAAmB,cAAA,GAC7B,aAAA,CAAc,CAAA;AAAA,KAMd,aAAA,WAAwB,WAAA,IAAe,eAAA,CACjD,YAAA,CAAa,CAAA;;;;KAMH,WAAA;;;AAtEe;KA2Ef,cAAA,WACJ,WAAA,GAAc,aAAA,CAAc,CAAA;EAChC,QAAA;AAAA,IAEE,CAAA;;;;;KAQM,uBAAA,WAAkC,WAAA,WACrC,aAAA,CAAc,CAAA,iBAEf,UAAA,CAAW,CAAA;EACT,MAAA;EAAgB,KAAA,EAAO,MAAA;AAAA;EACvB,MAAA;EAAc,KAAA;AAAA;EACd,IAAA,EAAM,CAAA;AAAA;;;;KAKJ,eAAA,WACJ,WAAA,GAAc,uBAAA,CAAwB,CAAA;EAE5C,SAAA,CAAU,QAAA,eAAuB,WAAA;EACjC,EAAA,gBAAkB,kBAAA,EAChB,QAAA,EAAU,sBAAA,CAAuB,MAAA,GACjC,QAAA,EAAU,sBAAA,CAAuB,MAAA,IAChC,WAAA;AAAA"}
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/types/client.ts"],"mappings":";;;;;;AAUA;UAAiB,aAAA;EAAA,CACd,GAAA,wBAA2B,IAAI;AAAA;AAAA,KAG7B,cAAA;EAAmB,MAAA,EAAQ,WAAA;EAAa,KAAA,EAAO,MAAM;AAAA;;;;;;;AAAA;KAS9C,YAAA,kBACO,aAAA,GAAgB,aAAA,gBACnB,cAAA,0BACE,MAAA;EAEhB,OAAA,EAAS,QAAA;EACT,IAAA,GAAO,KAAA;EACP,MAAA,GAAS,OAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;AAAO;AAgClB;;;;AAA8B;AAAG;;UAAhB,aAAA;AAAA,KAEZ,gBAAA,WAA2B,WAAA,IAAe,MAAA,IAC1C,CAAA;AAAA,KAIA,WAAA;EACH,OAAA,EAAS,MAAA,CAAO,CAAA,QAAS,CAAA;EACzB,IAAA;IAAQ,MAAA,EAAQ,WAAA;IAAa,KAAA,EAAO,MAAA,CAAO,CAAA,EAAG,CAAA;EAAA;EAC9C,MAAA,EAAQ,MAAA,IAAU,CAAA,KAAM,CAAA;AAAA;AAAA,KAGrB,cAAA,iBAA+B,aAAA,IAAiB,aAAA,CAAc,CAAA;EACjE,OAAA,EAAS,aAAA;AAAA,yBAEc,aAAA,CAAc,CAAA,IACjC,aAAA,CAAc,CAAA,kBAAmB,cAAA,0BACR,aAAA,CAAc,CAAA,IACnC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA,IACd,WAAA,WAAsB,CAAA,uCACxB,aAAA,CAAc,CAAA,IAChB,WAAA,WAAsB,CAAA,4DACD,aAAA,CAAc,CAAA,IACnC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA,IACd,WAAA,WAAsB,CAAA,uCACxB,aAAA,CAAc,CAAA,IAClB,WAAA,WAAsB,CAAA;AAAA,KAErB,aAAA,SAAsB,aAAA;EAErB,gCAAA,EAAkC,WAAA;AAAA,kBAEtB,aAAA,GAAgB,cAAA,CAAe,CAAA;;;;;;;;;;;;;;;;;KAkBrC,YAAA,WAAuB,WAAA,IAAe,aAAA,CAAc,CAAA,eAC9D,aAAA;AAAA,KAEU,WAAA,SAAoB,aAAa,mBAAmB,CAAA;AAAA,KAEpD,YAAA,WAAuB,WAAA,2BACV,aAAA,CAAc,CAAA,IACjC,aAAA,CAAc,CAAA,oBAAqB,gBAAA,CAAiB,CAAA,IAClD,aAAA,CAAc,CAAA;AAAA,KAIV,UAAA,WAAqB,WAAA,yBACV,aAAA,CAAc,CAAA,IAC/B,IAAA,CACE,aAAA,CAAc,CAAA,kBAAmB,cAAA,GAC7B,aAAA,CAAc,CAAA;AAAA,KAMd,aAAA,WAAwB,WAAA,IAAe,eAAA,CACjD,YAAA,CAAa,CAAA;;;;KAMH,WAAA;AAxEe;AAAA;;AAAA,KA6Ef,cAAA,WACJ,WAAA,GAAc,aAAA,CAAc,CAAA;EAChC,QAAA;AAAA,IAEE,CAAA;;;;;KAQM,uBAAA,WAAkC,WAAA,WACrC,aAAA,CAAc,CAAA,iBAEf,UAAA,CAAW,CAAA;EACT,MAAA;EAAgB,KAAA,EAAO,MAAA;AAAA;EACvB,MAAA;EAAc,KAAA;AAAA;EACd,IAAA,EAAM,CAAA;AAAA;;;;KAKJ,eAAA,WACJ,WAAA,GAAc,uBAAA,CAAwB,CAAA;EAE5C,SAAA,CAAU,QAAA,eAAuB,WAAA;EACjC,EAAA,gBAAkB,kBAAA,EAChB,QAAA,EAAU,sBAAA,CAAuB,MAAA,GACjC,QAAA,EAAU,sBAAA,CAAuB,MAAA,IAChC,WAAA;AAAA"}

@@ -5,12 +5,2 @@ import { AssistantClient, ClientElement, ClientNames } from "./types/client.js";

//#region src/useAui.d.ts
/**
* Resource that creates an extended AssistantClient.
*/
declare const AssistantClientResource: (props: {
parent: AssistantClient;
clients: useAui.Props;
}) => import("@assistant-ui/tap").ResourceElement<AssistantClient, {
parent: AssistantClient;
clients: useAui.Props;
}>;
declare namespace useAui {

@@ -84,3 +74,3 @@ type Props = { [K in ClientNames]?: ClientElement<K> | DerivedElement<K> };

//#endregion
export { AssistantClientResource, useAui };
export { useAui };
//# sourceMappingURL=useAui.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"useAui.d.ts","names":[],"sources":["../src/useAui.ts"],"mappings":";;;;;;AA6SA;cAAa,uBAAA,GAAuB,KAAA;UAKxB,eAAA;WACC,MAAA,CAAO,KAAA;AAAA;UADR,eAAA;WACC,MAAA,CAAO,KAAA;AAAA;AAAA,kBAuDH,MAAA;EAAA,KACH,KAAA,WACJ,WAAA,IAAe,aAAA,CAAc,CAAA,IAAK,cAAA,CAAe,CAAA;AAAA;;;;;;;;;;;;AAzDlC;AAuDzB;;;;;;;;;;;;;;;;;;AAE4D;AAuC5D;;;;iBAAgB,MAAA,IAAU,eAAe;AAsBzC;;;;;;;;;AAA8D;AAI9D;;;;;;;;;;;AAJA,iBAAgB,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,KAAA,GAAQ,eAAe;;;;iBAI9C,MAAA,CACd,OAAA,EAAS,MAAA,CAAO,KAAA,EAChB,MAAA;EAAU,MAAA,SAAe,eAAA;AAAA,IACxB,eAAA"}
{"version":3,"file":"useAui.d.ts","names":[],"sources":["../src/useAui.ts"],"mappings":";;;;kBA2XiB,MAAA;EAAA,KACH,KAAA,WACJ,WAAA,IAAe,aAAA,CAAc,CAAA,IAAK,cAAA,CAAe,CAAA;AAAA;;;;;;;;;;;;;;;;AAAC;AAuC5D;;;;AAAyC;AAsBzC;;;;;;;;;AAA8D;AAI9D;;;;iBA1BgB,MAAA,IAAU,eAAe;;;;;;;;;;;;AA6BvB;;;;;;;;;;iBAPF,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,KAAA,GAAQ,eAAe;;;;iBAI9C,MAAA,CACd,OAAA,EAAS,MAAA,CAAO,KAAA,EAChB,MAAA;EAAU,MAAA,SAAe,eAAA;AAAA,IACxB,eAAA"}

@@ -5,3 +5,3 @@ "use client";

import { PROXIED_ASSISTANT_STATE_SYMBOL, createProxiedAssistantState } from "./utils/proxied-assistant-state.js";
import { DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue } from "./utils/react-assistant-context.js";
import { AUI_USE_EFFECTS_SYMBOL, DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue } from "./utils/react-assistant-context.js";
import { useSplitClients } from "./utils/splitClients.js";

@@ -12,3 +12,3 @@ import { normalizeEventSelector } from "./types/events.js";

import { useEffect, useMemo, useRef } from "@assistant-ui/tap/react-shim";
import { resource, useResource, useResourceRoot, useResources, withKey } from "@assistant-ui/tap";
import { resource, useResource, useResources, useTapHost, useTapRoot, withKey } from "@assistant-ui/tap";
//#region src/useAui.ts

@@ -18,7 +18,9 @@ const useShallowMemoArray = (array) => {

};
const RootClientResource = resource(function RootClientResource({ element, emit, clientRef }) {
const useRootClientResource = ({ element, emit, clientRef }) => {
const { methods, state } = withAssistantTapContextProvider({
clientRef,
emit
}, () => useClientResource(element));
}, function WithTapContext() {
return useClientResource(element);
});
return useMemo(() => ({

@@ -28,9 +30,11 @@ state,

}), [methods, state]);
});
const RootClientAccessorResource = resource(function RootClientAccessorResource({ element, notifications, clientRef, name }) {
const store = useResourceRoot(RootClientResource({
element,
emit: notifications.emit,
clientRef
}));
};
const useRootClientAccessorResource = ({ element, notifications, clientRef, name }) => {
const store = useTapRoot(function RootClient() {
return useRootClientResource({
element,
emit: notifications.emit,
clientRef
});
});
useEffect(() => {

@@ -57,4 +61,5 @@ return store.subscribe(notifications.notifySubscribers);

}, [store, name]);
});
const NoOpRootClientsAccessorsResource = resource(function NoOpRootClientsAccessorsResource() {
};
const RootClientAccessorResource = resource(useRootClientAccessorResource);
const useNoOpRootClientsAccessorsResource = () => {
return useMemo(() => ({

@@ -65,4 +70,5 @@ clients: [],

}), []);
});
const RootClientsAccessorsResource = resource(function RootClientsAccessorsResource({ clients: inputClients, clientRef }) {
};
const NoOpRootClientsAccessorsResource = resource(useNoOpRootClientsAccessorsResource);
const useRootClientsAccessorsResource = ({ clients: inputClients, clientRef }) => {
const notifications = useResource(NotificationManager());

@@ -111,6 +117,7 @@ useEffect(() => clientRef.parent.subscribe(notifications.notifySubscribers), [clientRef, notifications]);

]);
});
const DerivedClientAccessorResource = resource(function DerivedClientAccessorResource({ element, clientRef, name }) {
const propsRef = useRef(element.props);
propsRef.current = element.props;
};
const RootClientsAccessorsResource = resource(useRootClientsAccessorsResource);
const useDerivedClientAccessorResource = ({ element, clientRef, name }) => {
const propsRef = useRef(element.args[0]);
propsRef.current = element.args[0];
return useMemo(() => {

@@ -128,3 +135,4 @@ const clientFunction = () => propsRef.current.get(clientRef.current);

}, [clientRef, name]);
});
};
const DerivedClientAccessorResource = resource(useDerivedClientAccessorResource);
const serializeMeta = (name, meta) => {

@@ -141,7 +149,7 @@ let queryKey;

};
const DerivedClientsAccessorsResource = resource(function DerivedClientsAccessorsResource({ clients, clientRef }) {
const useDerivedClientsAccessorsResource = ({ clients, clientRef }) => {
return useShallowMemoArray(useResources(() => Object.keys(clients).map((key) => {
const name = key;
const element = clients[name];
return withKey(serializeMeta(name, element.props), DerivedClientAccessorResource({
return withKey(serializeMeta(name, element.args[0]), DerivedClientAccessorResource({
element,

@@ -152,7 +160,7 @@ clientRef,

}), [clients, clientRef]));
});
};
/**
* Resource that creates an extended AssistantClient.
*/
const AssistantClientResource = resource(function AssistantClientResource({ parent, clients }) {
const useAssistantClient = ({ parent, clients }) => {
const { rootClients, derivedClients } = useSplitClients(clients, parent);

@@ -170,6 +178,6 @@ const clientRef = useRef({

}) : NoOpRootClientsAccessorsResource());
const derivedFields = useResource(DerivedClientsAccessorsResource({
const derivedFields = useDerivedClientsAccessorsResource({
clients: derivedClients,
clientRef
}));
});
const client = useMemo(() => {

@@ -193,9 +201,16 @@ const proto = parent === DefaultAssistantClient ? createRootAssistantClient() : parent;

return client;
});
};
const useHostedAssistantClient = (props) => {
const { value: client, effects } = useTapHost(function AssistantClientHost() {
return useAssistantClient(props);
});
client[AUI_USE_EFFECTS_SYMBOL] = effects;
return client;
};
/** @deprecated This API is highly experimental and may be changed in a minor release */
function useAui(clients, { parent } = { parent: useAssistantContextValue() }) {
if (clients) return useResource(AssistantClientResource({
if (clients) return useHostedAssistantClient({
parent: parent ?? DefaultAssistantClient,
clients
}));
});
if (parent === null) throw new Error("received null parent, this usage is not allowed");

@@ -205,4 +220,4 @@ return parent;

//#endregion
export { AssistantClientResource, useAui };
export { useAui };
//# sourceMappingURL=useAui.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"useAui.js","names":[],"sources":["../src/useAui.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useResource,\n useResources,\n useResourceRoot,\n resource,\n withKey,\n} from \"@assistant-ui/tap\";\nimport { useMemo, useEffect, useRef } from \"react\";\n\nimport type {\n AssistantClient,\n AssistantClientAccessor,\n ClientNames,\n ClientElement,\n ClientMeta,\n} from \"./types/client\";\nimport type { DerivedElement } from \"./Derived\";\nimport {\n useAssistantContextValue,\n DefaultAssistantClient,\n createRootAssistantClient,\n} from \"./utils/react-assistant-context\";\nimport {\n type DerivedClients,\n type RootClients,\n useSplitClients,\n} from \"./utils/splitClients\";\nimport {\n normalizeEventSelector,\n type AssistantEventName,\n type AssistantEventCallback,\n type AssistantEventSelector,\n} from \"./types/events\";\nimport { NotificationManager } from \"./utils/NotificationManager\";\nimport { withAssistantTapContextProvider } from \"./utils/tap-assistant-context\";\nimport { useClientResource } from \"./useClientResource\";\nimport { getClientIndex } from \"./utils/tap-client-stack-context\";\nimport {\n PROXIED_ASSISTANT_STATE_SYMBOL,\n createProxiedAssistantState,\n} from \"./utils/proxied-assistant-state\";\n\nconst useShallowMemoArray = <T>(array: readonly T[]) => {\n // oxlint-disable-next-line react/exhaustive-deps -- shallow memo over the array itself\n return useMemo(() => array, array);\n};\n\nconst RootClientResource = resource(function RootClientResource<\n K extends ClientNames,\n>({\n element,\n emit,\n clientRef,\n}: {\n element: ClientElement<K>;\n emit: NotificationManager[\"emit\"];\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n}) {\n const { methods, state } = withAssistantTapContextProvider(\n { clientRef, emit },\n // oxlint-disable-next-line react/rules-of-hooks -- withAssistantTapContextProvider runs this callback synchronously during render, so hook order is preserved\n () => useClientResource(element),\n );\n return useMemo(() => ({ state, methods }), [methods, state]);\n});\n\nconst RootClientAccessorResource = resource(function RootClientAccessorResource<\n K extends ClientNames,\n>({\n element,\n notifications,\n clientRef,\n name,\n}: {\n element: ClientElement<K>;\n notifications: NotificationManager;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n name: K;\n}): AssistantClientAccessor<K> {\n const store = useResourceRoot(\n RootClientResource({ element, emit: notifications.emit, clientRef }),\n );\n\n useEffect(() => {\n return store.subscribe(notifications.notifySubscribers);\n }, [store, notifications]);\n\n return useMemo(() => {\n const clientFunction = () => store.getValue().methods;\n Object.defineProperties(clientFunction, {\n source: {\n value: \"root\" as const,\n writable: false,\n },\n query: {\n value: {} as Record<string, never>,\n writable: false,\n },\n name: {\n value: name,\n configurable: true,\n },\n });\n return clientFunction as AssistantClientAccessor<K>;\n }, [store, name]);\n});\n\nconst NoOpRootClientsAccessorsResource = resource(\n function NoOpRootClientsAccessorsResource() {\n return useMemo(\n () => ({\n clients: [] as AssistantClientAccessor<ClientNames>[],\n subscribe: undefined,\n on: undefined,\n }),\n [],\n );\n },\n);\n\nconst RootClientsAccessorsResource = resource(\n function RootClientsAccessorsResource({\n clients: inputClients,\n clientRef,\n }: {\n clients: RootClients;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n }) {\n const notifications = useResource(NotificationManager());\n\n useEffect(\n () => clientRef.parent.subscribe(notifications.notifySubscribers),\n [clientRef, notifications],\n );\n\n const results = useShallowMemoArray(\n useResources(\n () =>\n Object.keys(inputClients).map((key) =>\n withKey(\n key,\n RootClientAccessorResource({\n element: inputClients[key as keyof typeof inputClients]!,\n notifications,\n clientRef,\n name: key as keyof typeof inputClients,\n }),\n ),\n ),\n [inputClients, notifications, clientRef],\n ),\n );\n\n return useMemo(() => {\n return {\n clients: results,\n subscribe: notifications.subscribe,\n on: function <TEvent extends AssistantEventName>(\n this: AssistantClient,\n selector: AssistantEventSelector<TEvent>,\n callback: AssistantEventCallback<TEvent>,\n ) {\n if (!this) {\n throw new Error(\n \"const { on } = useAui() is not supported. Use aui.on() instead.\",\n );\n }\n\n const { scope, event } = normalizeEventSelector(selector);\n\n if (scope !== \"*\") {\n const source = this[scope as ClientNames].source;\n if (source === null) {\n throw new Error(\n `Scope \"${scope}\" is not available. Use { scope: \"*\", event: \"${event}\" } to listen globally.`,\n );\n }\n }\n\n const localUnsub = notifications.on(event, (payload, clientStack) => {\n if (scope === \"*\") {\n callback(payload);\n return;\n }\n\n const scopeClient = this[scope as ClientNames]();\n const index = getClientIndex(scopeClient);\n if (scopeClient === clientStack[index]) {\n callback(payload);\n }\n });\n if (\n scope !== \"*\" &&\n clientRef.parent[scope as ClientNames].source === null\n )\n return localUnsub;\n\n const parentUnsub = clientRef.parent.on(selector, callback);\n\n return () => {\n localUnsub();\n parentUnsub();\n };\n },\n };\n }, [results, notifications, clientRef]);\n },\n);\n\nconst DerivedClientAccessorResource = resource(\n function DerivedClientAccessorResource<K extends ClientNames>({\n element,\n clientRef,\n name,\n }: {\n element: DerivedElement<K>;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n name: K;\n }) {\n // Track the latest props on a ref updated in render. The fiber is\n // keyed on the scope's meta by DerivedClientsAccessorsResource, so\n // source/query are stable for this fiber's lifetime and the only\n // value that can change between renders for the same fiber is the\n // identity of the `get` closure. Routing reads through the ref so\n // they take effect without a one-commit lag.\n const propsRef = useRef(element.props);\n propsRef.current = element.props;\n\n return useMemo(() => {\n const clientFunction = () => propsRef.current.get(clientRef.current!);\n Object.defineProperties(clientFunction, {\n source: {\n value: propsRef.current.source,\n },\n query: {\n value: propsRef.current.query,\n },\n name: {\n value: name,\n configurable: true,\n },\n });\n return clientFunction as AssistantClientAccessor<K>;\n }, [clientRef, name]);\n },\n);\n\nconst serializeMeta = <K extends ClientNames>(\n name: K,\n meta: ClientMeta<K>,\n): string => {\n // Sort top-level keys so {a, b} and {b, a} hash to the same fiber\n // identity, and guard JSON.stringify against unusual values (BigInt,\n // circular refs) so render never throws here.\n let queryKey: string;\n try {\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(meta.query as object).sort()) {\n sorted[k] = (meta.query as Record<string, unknown>)[k];\n }\n queryKey = JSON.stringify(sorted);\n } catch {\n queryKey = String(meta.query);\n }\n return `${name}::${meta.source}::${queryKey}`;\n};\n\nconst DerivedClientsAccessorsResource = resource(\n function DerivedClientsAccessorsResource({\n clients,\n clientRef,\n }: {\n clients: DerivedClients;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n }) {\n return useShallowMemoArray(\n useResources(\n () =>\n Object.keys(clients).map((key) => {\n const name = key as keyof typeof clients;\n const element = clients[name]!;\n return withKey(\n serializeMeta(name, element.props),\n DerivedClientAccessorResource({\n element,\n clientRef,\n name,\n }),\n );\n }),\n [clients, clientRef],\n ),\n );\n },\n);\n\n/**\n * Resource that creates an extended AssistantClient.\n */\nexport const AssistantClientResource = resource(\n function AssistantClientResource({\n parent,\n clients,\n }: {\n parent: AssistantClient;\n clients: useAui.Props;\n }): AssistantClient {\n const { rootClients, derivedClients } = useSplitClients(clients, parent);\n\n const clientRef = useRef({\n parent: parent,\n current: null as AssistantClient | null,\n }).current;\n\n useEffect(() => {\n clientRef.current = client;\n });\n\n const rootFields = useResource(\n Object.keys(rootClients).length > 0\n ? RootClientsAccessorsResource({ clients: rootClients, clientRef })\n : NoOpRootClientsAccessorsResource(),\n );\n\n const derivedFields = useResource(\n DerivedClientsAccessorsResource({ clients: derivedClients, clientRef }),\n );\n\n const client = useMemo(() => {\n // Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message\n const proto =\n parent === DefaultAssistantClient\n ? createRootAssistantClient()\n : parent;\n\n const client = Object.create(proto) as AssistantClient;\n Object.assign(client, {\n subscribe: rootFields.subscribe ?? parent.subscribe,\n on: rootFields.on ?? parent.on,\n [PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),\n });\n\n for (const field of rootFields.clients) {\n (client as any)[field.name] = field;\n }\n for (const field of derivedFields) {\n (client as any)[field.name] = field;\n }\n\n return client;\n }, [parent, rootFields, derivedFields]);\n\n if (clientRef.current === null) {\n clientRef.current = client;\n }\n\n return client;\n },\n);\n\nexport namespace useAui {\n export type Props = {\n [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;\n };\n}\n\n/**\n * Returns the current `AssistantClient` from context.\n *\n * Read the client supplied by the nearest {@link AuiProvider} or\n * {@link AssistantRuntimeProvider}, then access a scope on it —\n * `aui.thread()`, `aui.composer()`, `aui.message()`, and so on. Pair\n * with {@link useAuiState} to read reactive state and {@link useAuiEvent}\n * to subscribe to events. The returned client also exposes lower-level\n * methods such as `aui.on(...)` and `aui.subscribe(...)`; prefer\n * `useAuiEvent` for React event subscriptions.\n *\n * Rendered outside a provider, the returned client's scope accessors\n * throw a descriptive error whenever they are called.\n *\n * @example\n * ```tsx\n * const aui = useAui();\n *\n * const onSend = () => aui.composer().send();\n * const onCancel = () => aui.thread().cancelRun();\n * ```\n *\n * @example\n * ```tsx\n * // Combine with useAuiState to drive disabled state.\n * const aui = useAui();\n * const isRunning = useAuiState((s) => s.thread.isRunning);\n *\n * return (\n * <button disabled={isRunning} onClick={() => aui.composer().send()}>\n * Send\n * </button>\n * );\n * ```\n */\nexport function useAui(): AssistantClient;\n/**\n * Extends the parent `AssistantClient` with additional scopes.\n *\n * Advanced overload used when building primitives or providers — for example,\n * when a custom provider needs to register a `message`, `part`, or other scope\n * onto the client visible to its descendants. Application code rarely reaches\n * for this; use {@link useAui} with no arguments to read the existing client.\n *\n * @example\n * ```tsx\n * const aui = useAui({\n * message: Derived({\n * source: \"thread\",\n * query: { index: 0 },\n * get: (aui) => aui.thread().message({ index: 0 }),\n * }),\n * });\n *\n * const role = useAuiState((s) => s.message.role);\n * ```\n */\nexport function useAui(clients: useAui.Props): AssistantClient;\n/**\n * Extends an explicit parent `AssistantClient` with additional scopes.\n */\nexport function useAui(\n clients: useAui.Props,\n config: { parent: null | AssistantClient },\n): AssistantClient;\n/** @deprecated This API is highly experimental and may be changed in a minor release */\nexport function useAui(\n clients?: useAui.Props,\n { parent }: { parent: null | AssistantClient } = {\n parent: useAssistantContextValue(),\n },\n): AssistantClient {\n if (clients) {\n return useResource(\n AssistantClientResource({\n parent: parent ?? DefaultAssistantClient,\n clients,\n }),\n );\n }\n if (parent === null)\n throw new Error(\"received null parent, this usage is not allowed\");\n return parent;\n}\n"],"mappings":"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"}
{"version":3,"file":"useAui.js","names":[],"sources":["../src/useAui.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useResource,\n useResources,\n useTapHost,\n useTapRoot,\n resource,\n withKey,\n} from \"@assistant-ui/tap\";\nimport { useMemo, useEffect, useRef } from \"react\";\n\nimport type {\n AssistantClient,\n AssistantClientAccessor,\n ClientNames,\n ClientElement,\n ClientMeta,\n} from \"./types/client\";\nimport type { DerivedElement } from \"./Derived\";\nimport {\n useAssistantContextValue,\n DefaultAssistantClient,\n createRootAssistantClient,\n AUI_USE_EFFECTS_SYMBOL,\n} from \"./utils/react-assistant-context\";\nimport {\n type DerivedClients,\n type RootClients,\n useSplitClients,\n} from \"./utils/splitClients\";\nimport {\n normalizeEventSelector,\n type AssistantEventName,\n type AssistantEventCallback,\n type AssistantEventSelector,\n} from \"./types/events\";\nimport { NotificationManager } from \"./utils/NotificationManager\";\nimport { withAssistantTapContextProvider } from \"./utils/tap-assistant-context\";\nimport { useClientResource } from \"./useClientResource\";\nimport { getClientIndex } from \"./utils/tap-client-stack-context\";\nimport {\n PROXIED_ASSISTANT_STATE_SYMBOL,\n createProxiedAssistantState,\n} from \"./utils/proxied-assistant-state\";\n\nconst useShallowMemoArray = <T>(array: readonly T[]) => {\n // oxlint-disable-next-line react/exhaustive-deps -- shallow memo over the array itself\n return useMemo(() => array, array);\n};\n\nconst useRootClientResource = <K extends ClientNames>({\n element,\n emit,\n clientRef,\n}: {\n element: ClientElement<K>;\n emit: NotificationManager[\"emit\"];\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n}) => {\n const { methods, state } = withAssistantTapContextProvider(\n { clientRef, emit },\n function WithTapContext() {\n return useClientResource(element);\n },\n );\n return useMemo(() => ({ state, methods }), [methods, state]);\n};\n\nconst useRootClientAccessorResource = <K extends ClientNames>({\n element,\n notifications,\n clientRef,\n name,\n}: {\n element: ClientElement<K>;\n notifications: NotificationManager;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n name: K;\n}): AssistantClientAccessor<K> => {\n const store = useTapRoot(function RootClient() {\n return useRootClientResource({\n element,\n emit: notifications.emit,\n clientRef,\n });\n });\n\n useEffect(() => {\n return store.subscribe(notifications.notifySubscribers);\n }, [store, notifications]);\n\n return useMemo(() => {\n const clientFunction = () => store.getValue().methods;\n Object.defineProperties(clientFunction, {\n source: {\n value: \"root\" as const,\n writable: false,\n },\n query: {\n value: {} as Record<string, never>,\n writable: false,\n },\n name: {\n value: name,\n configurable: true,\n },\n });\n return clientFunction as AssistantClientAccessor<K>;\n }, [store, name]);\n};\n\nconst RootClientAccessorResource = resource(useRootClientAccessorResource);\n\nconst useNoOpRootClientsAccessorsResource = () => {\n return useMemo(\n () => ({\n clients: [] as AssistantClientAccessor<ClientNames>[],\n subscribe: undefined,\n on: undefined,\n }),\n [],\n );\n};\n\nconst NoOpRootClientsAccessorsResource = resource(\n useNoOpRootClientsAccessorsResource,\n);\n\nconst useRootClientsAccessorsResource = ({\n clients: inputClients,\n clientRef,\n}: {\n clients: RootClients;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n}) => {\n const notifications = useResource(NotificationManager());\n\n useEffect(\n () => clientRef.parent.subscribe(notifications.notifySubscribers),\n [clientRef, notifications],\n );\n\n const results = useShallowMemoArray(\n useResources(\n () =>\n Object.keys(inputClients).map((key) =>\n withKey(\n key,\n RootClientAccessorResource({\n element: inputClients[key as keyof typeof inputClients]!,\n notifications,\n clientRef,\n name: key as keyof typeof inputClients,\n }),\n ),\n ),\n [inputClients, notifications, clientRef],\n ),\n );\n\n return useMemo(() => {\n return {\n clients: results,\n subscribe: notifications.subscribe,\n on: function <TEvent extends AssistantEventName>(\n this: AssistantClient,\n selector: AssistantEventSelector<TEvent>,\n callback: AssistantEventCallback<TEvent>,\n ) {\n if (!this) {\n throw new Error(\n \"const { on } = useAui() is not supported. Use aui.on() instead.\",\n );\n }\n\n const { scope, event } = normalizeEventSelector(selector);\n\n if (scope !== \"*\") {\n const source = this[scope as ClientNames].source;\n if (source === null) {\n throw new Error(\n `Scope \"${scope}\" is not available. Use { scope: \"*\", event: \"${event}\" } to listen globally.`,\n );\n }\n }\n\n const localUnsub = notifications.on(event, (payload, clientStack) => {\n if (scope === \"*\") {\n callback(payload);\n return;\n }\n\n const scopeClient = this[scope as ClientNames]();\n const index = getClientIndex(scopeClient);\n if (scopeClient === clientStack[index]) {\n callback(payload);\n }\n });\n if (\n scope !== \"*\" &&\n clientRef.parent[scope as ClientNames].source === null\n )\n return localUnsub;\n\n const parentUnsub = clientRef.parent.on(selector, callback);\n\n return () => {\n localUnsub();\n parentUnsub();\n };\n },\n };\n }, [results, notifications, clientRef]);\n};\n\nconst RootClientsAccessorsResource = resource(useRootClientsAccessorsResource);\n\nconst useDerivedClientAccessorResource = <K extends ClientNames>({\n element,\n clientRef,\n name,\n}: {\n element: DerivedElement<K>;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n name: K;\n}) => {\n // Track the latest props on a ref updated in render. The fiber is\n // keyed on the scope's meta by DerivedClientsAccessorsResource, so\n // source/query are stable for this fiber's lifetime and the only\n // value that can change between renders for the same fiber is the\n // identity of the `get` closure. Routing reads through the ref so\n // they take effect without a one-commit lag.\n const propsRef = useRef(element.args[0]);\n propsRef.current = element.args[0];\n\n return useMemo(() => {\n const clientFunction = () => propsRef.current.get(clientRef.current!);\n Object.defineProperties(clientFunction, {\n source: {\n value: propsRef.current.source,\n },\n query: {\n value: propsRef.current.query,\n },\n name: {\n value: name,\n configurable: true,\n },\n });\n return clientFunction as AssistantClientAccessor<K>;\n }, [clientRef, name]);\n};\n\nconst DerivedClientAccessorResource = resource(\n useDerivedClientAccessorResource,\n);\n\nconst serializeMeta = <K extends ClientNames>(\n name: K,\n meta: ClientMeta<K>,\n): string => {\n // Sort top-level keys so {a, b} and {b, a} hash to the same fiber\n // identity, and guard JSON.stringify against unusual values (BigInt,\n // circular refs) so render never throws here.\n let queryKey: string;\n try {\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(meta.query as object).sort()) {\n sorted[k] = (meta.query as Record<string, unknown>)[k];\n }\n queryKey = JSON.stringify(sorted);\n } catch {\n queryKey = String(meta.query);\n }\n return `${name}::${meta.source}::${queryKey}`;\n};\n\nconst useDerivedClientsAccessorsResource = ({\n clients,\n clientRef,\n}: {\n clients: DerivedClients;\n clientRef: { parent: AssistantClient; current: AssistantClient | null };\n}) => {\n return useShallowMemoArray(\n useResources(\n () =>\n Object.keys(clients).map((key) => {\n const name = key as keyof typeof clients;\n const element = clients[name]!;\n return withKey(\n serializeMeta(name, element.args[0]),\n DerivedClientAccessorResource({\n element,\n clientRef,\n name,\n }),\n );\n }),\n [clients, clientRef],\n ),\n );\n};\n\n/**\n * Resource that creates an extended AssistantClient.\n */\nconst useAssistantClient = ({\n parent,\n clients,\n}: {\n parent: AssistantClient;\n clients: useAui.Props;\n}): AssistantClient => {\n const { rootClients, derivedClients } = useSplitClients(clients, parent);\n\n const clientRef = useRef({\n parent: parent,\n current: null as AssistantClient | null,\n }).current;\n\n useEffect(() => {\n clientRef.current = client;\n });\n\n const rootFields = useResource(\n Object.keys(rootClients).length > 0\n ? RootClientsAccessorsResource({ clients: rootClients, clientRef })\n : NoOpRootClientsAccessorsResource(),\n );\n\n const derivedFields = useDerivedClientsAccessorsResource({\n clients: derivedClients,\n clientRef,\n });\n\n const client = useMemo(() => {\n // Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message\n const proto =\n parent === DefaultAssistantClient ? createRootAssistantClient() : parent;\n\n const client = Object.create(proto) as AssistantClient;\n Object.assign(client, {\n subscribe: rootFields.subscribe ?? parent.subscribe,\n on: rootFields.on ?? parent.on,\n [PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),\n });\n\n for (const field of rootFields.clients) {\n (client as any)[field.name] = field;\n }\n for (const field of derivedFields) {\n (client as any)[field.name] = field;\n }\n\n return client;\n }, [parent, rootFields, derivedFields]);\n\n if (clientRef.current === null) {\n clientRef.current = client;\n }\n\n return client;\n};\n\nconst useHostedAssistantClient = (props: {\n parent: AssistantClient;\n clients: useAui.Props;\n}): AssistantClient => {\n const { value: client, effects } = useTapHost(function AssistantClientHost() {\n return useAssistantClient(props);\n });\n\n (client as Record<symbol, unknown>)[AUI_USE_EFFECTS_SYMBOL] = effects;\n\n return client;\n};\n\nexport namespace useAui {\n export type Props = {\n [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;\n };\n}\n\n/**\n * Returns the current `AssistantClient` from context.\n *\n * Read the client supplied by the nearest {@link AuiProvider} or\n * {@link AssistantRuntimeProvider}, then access a scope on it —\n * `aui.thread()`, `aui.composer()`, `aui.message()`, and so on. Pair\n * with {@link useAuiState} to read reactive state and {@link useAuiEvent}\n * to subscribe to events. The returned client also exposes lower-level\n * methods such as `aui.on(...)` and `aui.subscribe(...)`; prefer\n * `useAuiEvent` for React event subscriptions.\n *\n * Rendered outside a provider, the returned client's scope accessors\n * throw a descriptive error whenever they are called.\n *\n * @example\n * ```tsx\n * const aui = useAui();\n *\n * const onSend = () => aui.composer().send();\n * const onCancel = () => aui.thread().cancelRun();\n * ```\n *\n * @example\n * ```tsx\n * // Combine with useAuiState to drive disabled state.\n * const aui = useAui();\n * const isRunning = useAuiState((s) => s.thread.isRunning);\n *\n * return (\n * <button disabled={isRunning} onClick={() => aui.composer().send()}>\n * Send\n * </button>\n * );\n * ```\n */\nexport function useAui(): AssistantClient;\n/**\n * Extends the parent `AssistantClient` with additional scopes.\n *\n * Advanced overload used when building primitives or providers — for example,\n * when a custom provider needs to register a `message`, `part`, or other scope\n * onto the client visible to its descendants. Application code rarely reaches\n * for this; use {@link useAui} with no arguments to read the existing client.\n *\n * @example\n * ```tsx\n * const aui = useAui({\n * message: Derived({\n * source: \"thread\",\n * query: { index: 0 },\n * get: (aui) => aui.thread().message({ index: 0 }),\n * }),\n * });\n *\n * const role = useAuiState((s) => s.message.role);\n * ```\n */\nexport function useAui(clients: useAui.Props): AssistantClient;\n/**\n * Extends an explicit parent `AssistantClient` with additional scopes.\n */\nexport function useAui(\n clients: useAui.Props,\n config: { parent: null | AssistantClient },\n): AssistantClient;\n/** @deprecated This API is highly experimental and may be changed in a minor release */\nexport function useAui(\n clients?: useAui.Props,\n { parent }: { parent: null | AssistantClient } = {\n parent: useAssistantContextValue(),\n },\n): AssistantClient {\n if (clients) {\n return useHostedAssistantClient({\n parent: parent ?? DefaultAssistantClient,\n clients,\n });\n }\n if (parent === null)\n throw new Error(\"received null parent, this usage is not allowed\");\n return parent;\n}\n"],"mappings":"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"}

@@ -26,3 +26,3 @@ import { ClientMethods } from "./types/client.js";

getKey: (data: TData) => string;
resource: ContravariantResource<TMethods, ResourceProps<TData>>;
resource: ContravariantResource<TMethods, [ResourceProps<TData>]>;
};

@@ -29,0 +29,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientList.d.ts","names":[],"sources":["../src/useClientList.ts"],"mappings":";;;;KAMK,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,cAwBS,aAAA,2BAAyC,aAAA,EACpD,KAAA,EAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,QAAA;EAElC,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,GAAA,GAAM,MAAA;IAAU,KAAA;EAAA;IAAoB,GAAA;EAAA,MAAkB,QAAA;EACtD,GAAA,GAAM,WAAA,EAAa,KAAA;AAAA;AAAA,kBAuEJ,aAAA;EAAA,KACH,aAAA;IACV,GAAA;IACA,cAAA,QAAsB,KAAA;IACtB,MAAA;EAAA;EAAA,KAGU,KAAA,yBAA8B,aAAA;IACxC,aAAA,EAAe,KAAA;IACf,MAAA,GAAS,IAAA,EAAM,KAAA;IACf,QAAA,EAAU,qBAAA,CAAsB,QAAA,EAAU,aAAA,CAAc,KAAA;EAAA;AAAA"}
{"version":3,"file":"useClientList.d.ts","names":[],"sources":["../src/useClientList.ts"],"mappings":";;;;KAMK,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,cAwBS,aAAA,2BAAyC,aAAA,EACpD,KAAA,EAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,QAAA;EAElC,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,GAAA,GAAM,MAAA;IAAU,KAAA;EAAA;IAAoB,GAAA;EAAA,MAAkB,QAAA;EACtD,GAAA,GAAM,WAAA,EAAa,KAAA;AAAA;AAAA,kBAuEJ,aAAA;EAAA,KACH,aAAA;IACV,GAAA;IACA,cAAA,QAAsB,KAAA;IACtB,MAAA;EAAA;EAAA,KAGU,KAAA,yBAA8B,aAAA;IACxC,aAAA,EAAe,KAAA;IACf,MAAA,GAAS,IAAA,EAAM,KAAA;IACf,QAAA,EAAU,qBAAA,CAAsB,QAAA,GAAW,aAAA,CAAc,KAAA;EAAA;AAAA"}

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientList.js","names":[],"sources":["../src/useClientList.ts"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { withKey, type ContravariantResource } from \"@assistant-ui/tap\";\n\nimport { useClientLookup } from \"./useClientLookup\";\nimport type { ClientMethods } from \"./types/client\";\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : unknown;\n\ntype DataHandle<TData> = { data: TData | undefined; hasData: boolean };\n\nconst createProps = <TData>(\n key: string,\n data: DataHandle<TData>,\n remove: () => void,\n): useClientList.ResourceProps<TData> => {\n return {\n key,\n getInitialData: () => {\n if (!data.hasData) {\n throw new Error(\n \"getInitialData may only be called during initial render\",\n );\n }\n return data.data!;\n },\n remove,\n };\n};\n\nexport const useClientList = <TData, TMethods extends ClientMethods>(\n props: useClientList.Props<TData, TMethods>,\n): {\n state: InferClientState<TMethods>[];\n get: (lookup: { index: number } | { key: string }) => TMethods;\n add: (initialData: TData) => void;\n} => {\n const { initialValues, getKey, resource: Resource } = props;\n\n type Props = useClientList.ResourceProps<TData>;\n\n const initialDataHandles: DataHandle<TData>[] = useMemo(() => [], []);\n\n const [items, setItems] = useState<Record<string, Props>>(() => {\n const entries: [string, Props][] = [];\n for (const data of initialValues) {\n const key = getKey(data);\n const handle = { data, hasData: true };\n entries.push([\n key,\n createProps(key, handle, () => {\n setItems((items) => {\n const newItems = { ...items };\n delete newItems[key];\n return newItems;\n });\n }),\n ]);\n initialDataHandles.push(handle);\n }\n return Object.fromEntries(entries);\n });\n\n const lookup = useClientLookup<TMethods>(\n () =>\n Object.values(items).map((props) => withKey(props.key, Resource(props))),\n [items, Resource],\n );\n\n initialDataHandles.forEach((handle) => {\n handle.data = undefined;\n handle.hasData = false;\n });\n\n const add = (data: TData) => {\n const key = getKey(data);\n setItems((items) => {\n if (key in items) {\n throw new Error(\n `Tried to add item with a key ${key} that already exists`,\n );\n }\n\n const handle = { data, hasData: true };\n initialDataHandles.push(handle);\n\n return {\n ...items,\n [key]: createProps(key, handle, () => {\n setItems((items) => {\n const newItems = { ...items };\n delete newItems[key];\n return newItems;\n });\n }),\n };\n });\n };\n\n return {\n state: lookup.state,\n get: lookup.get,\n add,\n };\n};\n\nexport namespace useClientList {\n export type ResourceProps<TData> = {\n key: string;\n getInitialData: () => TData;\n remove: () => void;\n };\n\n export type Props<TData, TMethods extends ClientMethods> = {\n initialValues: TData[];\n getKey: (data: TData) => string;\n resource: ContravariantResource<TMethods, ResourceProps<TData>>;\n };\n}\n"],"mappings":";;;;AAcA,MAAM,eACJ,KACA,MACA,WACuC;CACvC,OAAO;EACL;EACA,sBAAsB;GACpB,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MACR,yDACF;GAEF,OAAO,KAAK;EACd;EACA;CACF;AACF;AAEA,MAAa,iBACX,UAKG;CACH,MAAM,EAAE,eAAe,QAAQ,UAAU,aAAa;CAItD,MAAM,qBAA0C,cAAc,CAAC,GAAG,CAAC,CAAC;CAEpE,MAAM,CAAC,OAAO,YAAY,eAAsC;EAC9D,MAAM,UAA6B,CAAC;EACpC,KAAK,MAAM,QAAQ,eAAe;GAChC,MAAM,MAAM,OAAO,IAAI;GACvB,MAAM,SAAS;IAAE;IAAM,SAAS;GAAK;GACrC,QAAQ,KAAK,CACX,KACA,YAAY,KAAK,cAAc;IAC7B,UAAU,UAAU;KAClB,MAAM,WAAW,EAAE,GAAG,MAAM;KAC5B,OAAO,SAAS;KAChB,OAAO;IACT,CAAC;GACH,CAAC,CACH,CAAC;GACD,mBAAmB,KAAK,MAAM;EAChC;EACA,OAAO,OAAO,YAAY,OAAO;CACnC,CAAC;CAED,MAAM,SAAS,sBAEX,OAAO,OAAO,KAAK,CAAC,CAAC,KAAK,UAAU,QAAQ,MAAM,KAAK,SAAS,KAAK,CAAC,CAAC,GACzE,CAAC,OAAO,QAAQ,CAClB;CAEA,mBAAmB,SAAS,WAAW;EACrC,OAAO,OAAO,KAAA;EACd,OAAO,UAAU;CACnB,CAAC;CAED,MAAM,OAAO,SAAgB;EAC3B,MAAM,MAAM,OAAO,IAAI;EACvB,UAAU,UAAU;GAClB,IAAI,OAAO,OACT,MAAM,IAAI,MACR,gCAAgC,IAAI,qBACtC;GAGF,MAAM,SAAS;IAAE;IAAM,SAAS;GAAK;GACrC,mBAAmB,KAAK,MAAM;GAE9B,OAAO;IACL,GAAG;KACF,MAAM,YAAY,KAAK,cAAc;KACpC,UAAU,UAAU;MAClB,MAAM,WAAW,EAAE,GAAG,MAAM;MAC5B,OAAO,SAAS;MAChB,OAAO;KACT,CAAC;IACH,CAAC;GACH;EACF,CAAC;CACH;CAEA,OAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ;CACF;AACF"}
{"version":3,"file":"useClientList.js","names":[],"sources":["../src/useClientList.ts"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { withKey, type ContravariantResource } from \"@assistant-ui/tap\";\n\nimport { useClientLookup } from \"./useClientLookup\";\nimport type { ClientMethods } from \"./types/client\";\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : unknown;\n\ntype DataHandle<TData> = { data: TData | undefined; hasData: boolean };\n\nconst createProps = <TData>(\n key: string,\n data: DataHandle<TData>,\n remove: () => void,\n): useClientList.ResourceProps<TData> => {\n return {\n key,\n getInitialData: () => {\n if (!data.hasData) {\n throw new Error(\n \"getInitialData may only be called during initial render\",\n );\n }\n return data.data!;\n },\n remove,\n };\n};\n\nexport const useClientList = <TData, TMethods extends ClientMethods>(\n props: useClientList.Props<TData, TMethods>,\n): {\n state: InferClientState<TMethods>[];\n get: (lookup: { index: number } | { key: string }) => TMethods;\n add: (initialData: TData) => void;\n} => {\n const { initialValues, getKey, resource: Resource } = props;\n\n type Props = useClientList.ResourceProps<TData>;\n\n const initialDataHandles: DataHandle<TData>[] = useMemo(() => [], []);\n\n const [items, setItems] = useState<Record<string, Props>>(() => {\n const entries: [string, Props][] = [];\n for (const data of initialValues) {\n const key = getKey(data);\n const handle = { data, hasData: true };\n entries.push([\n key,\n createProps(key, handle, () => {\n setItems((items) => {\n const newItems = { ...items };\n delete newItems[key];\n return newItems;\n });\n }),\n ]);\n initialDataHandles.push(handle);\n }\n return Object.fromEntries(entries);\n });\n\n const lookup = useClientLookup<TMethods>(\n () =>\n Object.values(items).map((props) => withKey(props.key, Resource(props))),\n [items, Resource],\n );\n\n initialDataHandles.forEach((handle) => {\n handle.data = undefined;\n handle.hasData = false;\n });\n\n const add = (data: TData) => {\n const key = getKey(data);\n setItems((items) => {\n if (key in items) {\n throw new Error(\n `Tried to add item with a key ${key} that already exists`,\n );\n }\n\n const handle = { data, hasData: true };\n initialDataHandles.push(handle);\n\n return {\n ...items,\n [key]: createProps(key, handle, () => {\n setItems((items) => {\n const newItems = { ...items };\n delete newItems[key];\n return newItems;\n });\n }),\n };\n });\n };\n\n return {\n state: lookup.state,\n get: lookup.get,\n add,\n };\n};\n\nexport namespace useClientList {\n export type ResourceProps<TData> = {\n key: string;\n getInitialData: () => TData;\n remove: () => void;\n };\n\n export type Props<TData, TMethods extends ClientMethods> = {\n initialValues: TData[];\n getKey: (data: TData) => string;\n resource: ContravariantResource<TMethods, [ResourceProps<TData>]>;\n };\n}\n"],"mappings":";;;;AAcA,MAAM,eACJ,KACA,MACA,WACuC;CACvC,OAAO;EACL;EACA,sBAAsB;GACpB,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MACR,yDACF;GAEF,OAAO,KAAK;EACd;EACA;CACF;AACF;AAEA,MAAa,iBACX,UAKG;CACH,MAAM,EAAE,eAAe,QAAQ,UAAU,aAAa;CAItD,MAAM,qBAA0C,cAAc,CAAC,GAAG,CAAC,CAAC;CAEpE,MAAM,CAAC,OAAO,YAAY,eAAsC;EAC9D,MAAM,UAA6B,CAAC;EACpC,KAAK,MAAM,QAAQ,eAAe;GAChC,MAAM,MAAM,OAAO,IAAI;GACvB,MAAM,SAAS;IAAE;IAAM,SAAS;GAAK;GACrC,QAAQ,KAAK,CACX,KACA,YAAY,KAAK,cAAc;IAC7B,UAAU,UAAU;KAClB,MAAM,WAAW,EAAE,GAAG,MAAM;KAC5B,OAAO,SAAS;KAChB,OAAO;IACT,CAAC;GACH,CAAC,CACH,CAAC;GACD,mBAAmB,KAAK,MAAM;EAChC;EACA,OAAO,OAAO,YAAY,OAAO;CACnC,CAAC;CAED,MAAM,SAAS,sBAEX,OAAO,OAAO,KAAK,CAAC,CAAC,KAAK,UAAU,QAAQ,MAAM,KAAK,SAAS,KAAK,CAAC,CAAC,GACzE,CAAC,OAAO,QAAQ,CAClB;CAEA,mBAAmB,SAAS,WAAW;EACrC,OAAO,OAAO,KAAA;EACd,OAAO,UAAU;CACnB,CAAC;CAED,MAAM,OAAO,SAAgB;EAC3B,MAAM,MAAM,OAAO,IAAI;EACvB,UAAU,UAAU;GAClB,IAAI,OAAO,OACT,MAAM,IAAI,MACR,gCAAgC,IAAI,qBACtC;GAGF,MAAM,SAAS;IAAE;IAAM,SAAS;GAAK;GACrC,mBAAmB,KAAK,MAAM;GAE9B,OAAO;IACL,GAAG;KACF,MAAM,YAAY,KAAK,cAAc;KACpC,UAAU,UAAU;MAClB,MAAM,WAAW,EAAE,GAAG,MAAM;MAC5B,OAAO,SAAS;MAChB,OAAO;KACT,CAAC;IACH,CAAC;GACH;EACF,CAAC;CACH;CAEA,OAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ;CACF;AACF"}

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientLookup.d.ts","names":[],"sources":["../src/useClientLookup.ts"],"mappings":";;;;KAUK,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,iBAgBY,eAAA,kBAAiC,aAAA,EAC/C,WAAA,iBAA4B,eAAA,CAAgB,QAAA,KAC5C,eAAA;EAEA,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,GAAA,GAAM,MAAA;IAAU,KAAA;EAAA;IAAoB,GAAA;EAAA,MAAkB,QAAA;AAAA"}
{"version":3,"file":"useClientLookup.d.ts","names":[],"sources":["../src/useClientLookup.ts"],"mappings":";;;;KAKK,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,iBAUY,eAAA,kBAAiC,aAAA,EAC/C,WAAA,iBAA4B,eAAA,CAAgB,QAAA,KAC5C,eAAA;EAEA,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,GAAA,GAAM,MAAA;IAAU,KAAA;EAAA;IAAoB,GAAA;EAAA,MAAkB,QAAA;AAAA"}

@@ -1,12 +0,11 @@

import { wrapperResource } from "./wrapperResource.js";
import { ClientResource } from "./useClientResource.js";
import { useMemo } from "@assistant-ui/tap/react-shim";
import { useResource, useResources } from "@assistant-ui/tap";
import { useResources, withKey } from "@assistant-ui/tap";
//#region src/useClientLookup.ts
const ClientResourceWithKey = wrapperResource((el) => {
if (el.key === void 0) throw new Error("useClientResource: Element has no key");
return useResource(ClientResource(el));
});
const getElementKey = (el) => {
if (el.key === void 0) throw new Error("useClientLookup: Element has no key");
return el.key;
};
function useClientLookup(getElements, getElementsDeps) {
const resources = useResources(() => getElements().map((el) => ClientResourceWithKey(el)), getElementsDeps);
const resources = useResources(() => getElements().map((el) => withKey(getElementKey(el), ClientResource(el))), getElementsDeps);
const keys = useMemo(() => Object.keys(resources), [resources]);

@@ -13,0 +12,0 @@ const keyToIndex = useMemo(() => {

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientLookup.js","names":[],"sources":["../src/useClientLookup.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n useResource,\n useResources,\n type ResourceElement,\n} from \"@assistant-ui/tap\";\nimport type { ClientMethods } from \"./types/client\";\nimport { ClientResource } from \"./useClientResource\";\nimport { wrapperResource } from \"./wrapperResource\";\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : unknown;\n\nconst ClientResourceWithKey = wrapperResource(\n <TMethods extends ClientMethods>(el: ResourceElement<TMethods>) => {\n if (el.key === undefined) {\n throw new Error(\"useClientResource: Element has no key\");\n }\n return useResource(ClientResource(el)) as {\n methods: TMethods;\n state: InferClientState<TMethods>;\n key: string | number;\n };\n },\n);\n\nexport function useClientLookup<TMethods extends ClientMethods>(\n getElements: () => readonly ResourceElement<TMethods>[],\n getElementsDeps: readonly unknown[],\n): {\n state: InferClientState<TMethods>[];\n get: (lookup: { index: number } | { key: string }) => TMethods;\n} {\n const resources = useResources(\n () => getElements().map((el) => ClientResourceWithKey(el)),\n // oxlint-disable-next-line react/exhaustive-deps -- caller-supplied deps array\n getElementsDeps,\n );\n\n const keys = useMemo(() => Object.keys(resources), [resources]);\n\n // For arrays, track element key -> index mapping\n const keyToIndex = useMemo(() => {\n return resources.reduce(\n (acc, resource, index) => {\n acc[resource.key] = index;\n return acc;\n },\n {} as Record<string, number>,\n );\n }, [resources]);\n\n const state = useMemo(() => {\n return resources.map((r) => r.state);\n }, [resources]);\n\n return {\n state,\n get: (lookup: { index: number } | { key: string }) => {\n if (\"index\" in lookup) {\n if (lookup.index < 0 || lookup.index >= keys.length) {\n throw new Error(\n `useClientLookup: Index ${lookup.index} out of bounds (length: ${keys.length})`,\n );\n }\n return resources[lookup.index]!.methods;\n }\n\n const index = keyToIndex[lookup.key];\n if (index === undefined) {\n throw new Error(`useClientLookup: Key \"${lookup.key}\" not found`);\n }\n return resources[index]!.methods;\n },\n };\n}\n"],"mappings":";;;;;AAgBA,MAAM,wBAAwB,iBACK,OAAkC;CACjE,IAAI,GAAG,QAAQ,KAAA,GACb,MAAM,IAAI,MAAM,uCAAuC;CAEzD,OAAO,YAAY,eAAe,EAAE,CAAC;AAKvC,CACF;AAEA,SAAgB,gBACd,aACA,iBAIA;CACA,MAAM,YAAY,mBACV,YAAY,CAAC,CAAC,KAAK,OAAO,sBAAsB,EAAE,CAAC,GAEzD,eACF;CAEA,MAAM,OAAO,cAAc,OAAO,KAAK,SAAS,GAAG,CAAC,SAAS,CAAC;CAG9D,MAAM,aAAa,cAAc;EAC/B,OAAO,UAAU,QACd,KAAK,UAAU,UAAU;GACxB,IAAI,SAAS,OAAO;GACpB,OAAO;EACT,GACA,CAAC,CACH;CACF,GAAG,CAAC,SAAS,CAAC;CAMd,OAAO;EACL,OALY,cAAc;GAC1B,OAAO,UAAU,KAAK,MAAM,EAAE,KAAK;EACrC,GAAG,CAAC,SAAS,CAGP;EACJ,MAAM,WAAgD;GACpD,IAAI,WAAW,QAAQ;IACrB,IAAI,OAAO,QAAQ,KAAK,OAAO,SAAS,KAAK,QAC3C,MAAM,IAAI,MACR,0BAA0B,OAAO,MAAM,0BAA0B,KAAK,OAAO,EAC/E;IAEF,OAAO,UAAU,OAAO,MAAM,CAAE;GAClC;GAEA,MAAM,QAAQ,WAAW,OAAO;GAChC,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,yBAAyB,OAAO,IAAI,YAAY;GAElE,OAAO,UAAU,MAAM,CAAE;EAC3B;CACF;AACF"}
{"version":3,"file":"useClientLookup.js","names":[],"sources":["../src/useClientLookup.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useResources, withKey, type ResourceElement } from \"@assistant-ui/tap\";\nimport type { ClientMethods } from \"./types/client\";\nimport { ClientResource } from \"./useClientResource\";\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : unknown;\n\nconst getElementKey = (el: ResourceElement<unknown>) => {\n if (el.key === undefined) {\n throw new Error(\"useClientLookup: Element has no key\");\n }\n return el.key;\n};\n\nexport function useClientLookup<TMethods extends ClientMethods>(\n getElements: () => readonly ResourceElement<TMethods>[],\n getElementsDeps: readonly unknown[],\n): {\n state: InferClientState<TMethods>[];\n get: (lookup: { index: number } | { key: string }) => TMethods;\n} {\n const resources = useResources(\n () =>\n getElements().map((el) => withKey(getElementKey(el), ClientResource(el))),\n // oxlint-disable-next-line react/exhaustive-deps -- caller-supplied deps array\n getElementsDeps,\n );\n\n const keys = useMemo(() => Object.keys(resources), [resources]);\n\n // For arrays, track element key -> index mapping\n const keyToIndex = useMemo(() => {\n return resources.reduce(\n (acc, resource, index) => {\n acc[resource.key!] = index;\n return acc;\n },\n {} as Record<string, number>,\n );\n }, [resources]);\n\n const state = useMemo(() => {\n return resources.map((r) => r.state);\n }, [resources]);\n\n return {\n state,\n get: (lookup: { index: number } | { key: string }) => {\n if (\"index\" in lookup) {\n if (lookup.index < 0 || lookup.index >= keys.length) {\n throw new Error(\n `useClientLookup: Index ${lookup.index} out of bounds (length: ${keys.length})`,\n );\n }\n return resources[lookup.index]!.methods;\n }\n\n const index = keyToIndex[lookup.key];\n if (index === undefined) {\n throw new Error(`useClientLookup: Key \"${lookup.key}\" not found`);\n }\n return resources[index]!.methods;\n },\n };\n}\n"],"mappings":";;;;AAWA,MAAM,iBAAiB,OAAiC;CACtD,IAAI,GAAG,QAAQ,KAAA,GACb,MAAM,IAAI,MAAM,qCAAqC;CAEvD,OAAO,GAAG;AACZ;AAEA,SAAgB,gBACd,aACA,iBAIA;CACA,MAAM,YAAY,mBAEd,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,cAAc,EAAE,GAAG,eAAe,EAAE,CAAC,CAAC,GAE1E,eACF;CAEA,MAAM,OAAO,cAAc,OAAO,KAAK,SAAS,GAAG,CAAC,SAAS,CAAC;CAG9D,MAAM,aAAa,cAAc;EAC/B,OAAO,UAAU,QACd,KAAK,UAAU,UAAU;GACxB,IAAI,SAAS,OAAQ;GACrB,OAAO;EACT,GACA,CAAC,CACH;CACF,GAAG,CAAC,SAAS,CAAC;CAMd,OAAO;EACL,OALY,cAAc;GAC1B,OAAO,UAAU,KAAK,MAAM,EAAE,KAAK;EACrC,GAAG,CAAC,SAAS,CAGP;EACJ,MAAM,WAAgD;GACpD,IAAI,WAAW,QAAQ;IACrB,IAAI,OAAO,QAAQ,KAAK,OAAO,SAAS,KAAK,QAC3C,MAAM,IAAI,MACR,0BAA0B,OAAO,MAAM,0BAA0B,KAAK,OAAO,EAC/E;IAEF,OAAO,UAAU,OAAO,MAAM,CAAE;GAClC;GAEA,MAAM,QAAQ,WAAW,OAAO;GAChC,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,yBAAyB,OAAO,IAAI,YAAY;GAElE,OAAO,UAAU,MAAM,CAAE;EAC3B;CACF;AACF"}

@@ -14,4 +14,9 @@ import { ClientMethods } from "./types/client.js";

};
declare const ClientResource: <TMethods extends ClientMethods>(element: ResourceElement<TMethods>) => ResourceElement<{
state: InferClientState<TMethods>;
methods: TMethods;
key: string | number | undefined;
}, [element: ResourceElement<TMethods>]>;
//#endregion
export { getClientState, useClientResource };
export { ClientResource, getClientState, useClientResource };
//# sourceMappingURL=useClientResource.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientResource.d.ts","names":[],"sources":["../src/useClientResource.ts"],"mappings":";;;;cAwBa,cAAA,GAAkB,MAAqB,EAAb,aAAa;AAAA,KA6I/C,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,cAGS,iBAAA,oBAAsC,aAAA,EACjD,OAAA,EAAS,eAAA,CAAgB,QAAA;EAEzB,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,OAAA,EAAS,QAAA;EACT,GAAA;AAAA"}
{"version":3,"file":"useClientResource.d.ts","names":[],"sources":["../src/useClientResource.ts"],"mappings":";;;;cAuBa,cAAA,GAAkB,MAAqB,EAAb,aAAa;AAAA,KAkG/C,gBAAA,aAA6B,QAAQ;EACxC,QAAA;AAAA,IAEE,CAAA;AAAA,cAGS,iBAAA,oBAAsC,aAAA,EACjD,OAAA,EAAS,eAAA,CAAgB,QAAA;EAEzB,KAAA,EAAO,gBAAA,CAAiB,QAAA;EACxB,OAAA,EAAS,QAAA;EACT,GAAA;AAAA;AAAA,cA8BW,cAAA,oBAnCsC,aAAA,EAAa,OAAA,EAAA,eAAA,CAAA,QAAA,MAAA,eAAA;SAGvD,gBAAA,CAAiB,QAAA;WACf,QAAA"}
import { SYMBOL_CLIENT_INDEX, useClientStack, useWithClientStack } from "./utils/tap-client-stack-context.js";
import { BaseProxyHandler, handleIntrospectionProp } from "./utils/BaseProxyHandler.js";
import { wrapperResource } from "./wrapperResource.js";
import { useEffect, useMemo, useRef } from "@assistant-ui/tap/react-shim";
import { useResource } from "@assistant-ui/tap";
import { resource, useResource } from "@assistant-ui/tap";
//#region src/useClientResource.ts

@@ -73,16 +72,9 @@ /**

};
/**
* Resource that wraps a plain resource element to create a stable client proxy.
*
* Takes a ResourceElement that returns methods (with optional getState()) and
* wraps it to produce a stable client proxy. This adds the client to the
* client stack, enabling event scoping.
*
* @internal
*/
const ClientResource = wrapperResource((element) => {
const useClientResource = (element) => {
const valueRef = useRef(null);
const index = useClientStack().length;
const methods = useMemo(() => new Proxy({}, new ClientProxyHandler(valueRef, index)), [index]);
const value = useWithClientStack(methods, () => useResource(element));
const value = useWithClientStack(methods, function WithClientStack() {
return useResource(element);
});
if (!valueRef.current) valueRef.current = value;

@@ -97,6 +89,4 @@ useEffect(() => {

};
});
const useClientResource = (element) => {
return useResource(ClientResource(element));
};
const ClientResource = resource(useClientResource);
//#endregion

@@ -103,0 +93,0 @@ export { ClientResource, getClientState, useClientResource };

@@ -1,1 +0,1 @@

{"version":3,"file":"useClientResource.js","names":[],"sources":["../src/useClientResource.ts"],"sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport { useResource, type ResourceElement } from \"@assistant-ui/tap\";\nimport type { ClientMethods } from \"./types/client\";\nimport {\n useClientStack,\n useWithClientStack,\n SYMBOL_CLIENT_INDEX,\n} from \"./utils/tap-client-stack-context\";\nimport {\n BaseProxyHandler,\n handleIntrospectionProp,\n} from \"./utils/BaseProxyHandler\";\nimport { wrapperResource } from \"./wrapperResource\";\n\n/**\n * Symbol used internally to get state from ClientProxy.\n * This allows getState() to be optional in the user-facing client.\n */\nconst SYMBOL_GET_OUTPUT = Symbol(\"assistant-ui.store.getValue\");\n\ntype ClientInternal = {\n [SYMBOL_GET_OUTPUT]: ClientMethods;\n};\n\nexport const getClientState = (client: ClientMethods) => {\n const output = (client as unknown as ClientInternal)[SYMBOL_GET_OUTPUT];\n if (!output) {\n throw new Error(\n \"Client scope contains a non-client resource. \" +\n \"Ensure your Derived get() returns a client created with useClientResource(), not a plain resource.\",\n );\n }\n return (output as any).getState?.();\n};\n\n// Global cache for function templates by field name\nconst fieldAccessFns = new Map<\n string | symbol,\n (this: unknown, ...args: unknown[]) => unknown\n>();\n\nfunction getOrCreateProxyFn(prop: string | symbol) {\n let template = fieldAccessFns.get(prop);\n if (!template) {\n template = function (this: unknown, ...args: unknown[]) {\n if (!this || typeof this !== \"object\") {\n throw new Error(\n `Method \"${String(prop)}\" called without proper context. ` +\n `This may indicate the function was called incorrectly.`,\n );\n }\n\n const output = (this as ClientInternal)[SYMBOL_GET_OUTPUT];\n if (!output) {\n throw new Error(\n `Method \"${String(prop)}\" called on invalid client proxy. ` +\n `Ensure you are calling this method on a valid client instance.`,\n );\n }\n\n const method = output[prop];\n if (!method)\n throw new Error(`Method \"${String(prop)}\" is not implemented.`);\n if (typeof method !== \"function\")\n throw new Error(`\"${String(prop)}\" is not a function.`);\n return method(...args);\n };\n fieldAccessFns.set(prop, template);\n }\n return template;\n}\n\nclass ClientProxyHandler\n extends BaseProxyHandler\n implements ProxyHandler<object>\n{\n private boundFns:\n | Map<string | symbol, (...args: never) => unknown>\n | undefined;\n private cachedReceiver: unknown;\n\n constructor(\n private readonly outputRef: {\n current: ClientMethods;\n },\n private readonly index: number,\n ) {\n super();\n }\n\n get(_: unknown, prop: string | symbol, receiver: unknown) {\n if (prop === SYMBOL_GET_OUTPUT) return this.outputRef.current;\n if (prop === SYMBOL_CLIENT_INDEX) return this.index;\n const introspection = handleIntrospectionProp(prop, \"ClientProxy\");\n if (introspection !== false) return introspection;\n const value = this.outputRef.current[prop];\n if (typeof value === \"function\") {\n if (this.cachedReceiver !== receiver) {\n this.boundFns = new Map();\n this.cachedReceiver = receiver;\n }\n let bound = this.boundFns!.get(prop);\n if (!bound) {\n bound = getOrCreateProxyFn(prop).bind(receiver);\n this.boundFns!.set(prop, bound);\n }\n return bound;\n }\n return value;\n }\n\n ownKeys(): ArrayLike<string | symbol> {\n return Object.keys(this.outputRef.current);\n }\n\n has(_: unknown, prop: string | symbol) {\n if (prop === SYMBOL_GET_OUTPUT) return true;\n if (prop === SYMBOL_CLIENT_INDEX) return true;\n return prop in this.outputRef.current;\n }\n}\n\n/**\n * Resource that wraps a plain resource element to create a stable client proxy.\n *\n * Takes a ResourceElement that returns methods (with optional getState()) and\n * wraps it to produce a stable client proxy. This adds the client to the\n * client stack, enabling event scoping.\n *\n * @internal\n */\nexport const ClientResource = wrapperResource(\n <TMethods extends ClientMethods>(\n element: ResourceElement<TMethods>,\n ): {\n methods: TMethods;\n state: unknown;\n key: string | number | undefined;\n } => {\n const valueRef = useRef(null as unknown as TMethods);\n\n const index = useClientStack().length;\n const methods = useMemo(\n () =>\n new Proxy<TMethods>(\n {} as TMethods,\n new ClientProxyHandler(valueRef, index),\n ),\n [index],\n );\n\n const value = useWithClientStack(methods, () => useResource(element));\n if (!valueRef.current) {\n valueRef.current = value;\n }\n\n useEffect(() => {\n valueRef.current = value;\n });\n\n const state = (value as any).getState?.();\n return { methods, state, key: element.key };\n },\n);\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : undefined;\n\nexport const useClientResource = <TMethods extends ClientMethods>(\n element: ResourceElement<TMethods>,\n): {\n state: InferClientState<TMethods>;\n methods: TMethods;\n key: string | number | undefined;\n} => {\n return useResource(ClientResource(element)) as {\n state: InferClientState<TMethods>;\n methods: TMethods;\n key: string | number | undefined;\n };\n};\n"],"mappings":";;;;;;;;;;AAkBA,MAAM,oBAAoB,OAAO,6BAA6B;AAM9D,MAAa,kBAAkB,WAA0B;CACvD,MAAM,SAAU,OAAqC;CACrD,IAAI,CAAC,QACH,MAAM,IAAI,MACR,iJAEF;CAEF,OAAQ,OAAe,WAAW;AACpC;AAGA,MAAM,iCAAiB,IAAI,IAGzB;AAEF,SAAS,mBAAmB,MAAuB;CACjD,IAAI,WAAW,eAAe,IAAI,IAAI;CACtC,IAAI,CAAC,UAAU;EACb,WAAW,SAAyB,GAAG,MAAiB;GACtD,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,MAAM,IAAI,MACR,WAAW,OAAO,IAAI,EAAE,wFAE1B;GAGF,MAAM,SAAU,KAAwB;GACxC,IAAI,CAAC,QACH,MAAM,IAAI,MACR,WAAW,OAAO,IAAI,EAAE,iGAE1B;GAGF,MAAM,SAAS,OAAO;GACtB,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,WAAW,OAAO,IAAI,EAAE,sBAAsB;GAChE,IAAI,OAAO,WAAW,YACpB,MAAM,IAAI,MAAM,IAAI,OAAO,IAAI,EAAE,qBAAqB;GACxD,OAAO,OAAO,GAAG,IAAI;EACvB;EACA,eAAe,IAAI,MAAM,QAAQ;CACnC;CACA,OAAO;AACT;AAEA,IAAM,qBAAN,cACU,iBAEV;CAOqB;CAGA;CATnB;CAGA;CAEA,YACE,WAGA,OACA;EACA,MAAM;EALW,KAAA,YAAA;EAGA,KAAA,QAAA;CAGnB;CAEA,IAAI,GAAY,MAAuB,UAAmB;EACxD,IAAI,SAAS,mBAAmB,OAAO,KAAK,UAAU;EACtD,IAAI,SAAS,qBAAqB,OAAO,KAAK;EAC9C,MAAM,gBAAgB,wBAAwB,MAAM,aAAa;EACjE,IAAI,kBAAkB,OAAO,OAAO;EACpC,MAAM,QAAQ,KAAK,UAAU,QAAQ;EACrC,IAAI,OAAO,UAAU,YAAY;GAC/B,IAAI,KAAK,mBAAmB,UAAU;IACpC,KAAK,2BAAW,IAAI,IAAI;IACxB,KAAK,iBAAiB;GACxB;GACA,IAAI,QAAQ,KAAK,SAAU,IAAI,IAAI;GACnC,IAAI,CAAC,OAAO;IACV,QAAQ,mBAAmB,IAAI,CAAC,CAAC,KAAK,QAAQ;IAC9C,KAAK,SAAU,IAAI,MAAM,KAAK;GAChC;GACA,OAAO;EACT;EACA,OAAO;CACT;CAEA,UAAsC;EACpC,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO;CAC3C;CAEA,IAAI,GAAY,MAAuB;EACrC,IAAI,SAAS,mBAAmB,OAAO;EACvC,IAAI,SAAS,qBAAqB,OAAO;EACzC,OAAO,QAAQ,KAAK,UAAU;CAChC;AACF;;;;;;;;;;AAWA,MAAa,iBAAiB,iBAE1B,YAKG;CACH,MAAM,WAAW,OAAO,IAA2B;CAEnD,MAAM,QAAQ,eAAe,CAAC,CAAC;CAC/B,MAAM,UAAU,cAEZ,IAAI,MACF,CAAC,GACD,IAAI,mBAAmB,UAAU,KAAK,CACxC,GACF,CAAC,KAAK,CACR;CAEA,MAAM,QAAQ,mBAAmB,eAAe,YAAY,OAAO,CAAC;CACpE,IAAI,CAAC,SAAS,SACZ,SAAS,UAAU;CAGrB,gBAAgB;EACd,SAAS,UAAU;CACrB,CAAC;CAGD,OAAO;EAAE;EAAS,OADH,MAAc,WAAW;EACf,KAAK,QAAQ;CAAI;AAC5C,CACF;AAQA,MAAa,qBACX,YAKG;CACH,OAAO,YAAY,eAAe,OAAO,CAAC;AAK5C"}
{"version":3,"file":"useClientResource.js","names":[],"sources":["../src/useClientResource.ts"],"sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport { resource, useResource, type ResourceElement } from \"@assistant-ui/tap\";\nimport type { ClientMethods } from \"./types/client\";\nimport {\n useClientStack,\n useWithClientStack,\n SYMBOL_CLIENT_INDEX,\n} from \"./utils/tap-client-stack-context\";\nimport {\n BaseProxyHandler,\n handleIntrospectionProp,\n} from \"./utils/BaseProxyHandler\";\n\n/**\n * Symbol used internally to get state from ClientProxy.\n * This allows getState() to be optional in the user-facing client.\n */\nconst SYMBOL_GET_OUTPUT = Symbol(\"assistant-ui.store.getValue\");\n\ntype ClientInternal = {\n [SYMBOL_GET_OUTPUT]: ClientMethods;\n};\n\nexport const getClientState = (client: ClientMethods) => {\n const output = (client as unknown as ClientInternal)[SYMBOL_GET_OUTPUT];\n if (!output) {\n throw new Error(\n \"Client scope contains a non-client resource. \" +\n \"Ensure your Derived get() returns a client created with useClientResource(), not a plain resource.\",\n );\n }\n return (output as any).getState?.();\n};\n\n// Global cache for function templates by field name\nconst fieldAccessFns = new Map<\n string | symbol,\n (this: unknown, ...args: unknown[]) => unknown\n>();\n\nfunction getOrCreateProxyFn(prop: string | symbol) {\n let template = fieldAccessFns.get(prop);\n if (!template) {\n template = function (this: unknown, ...args: unknown[]) {\n if (!this || typeof this !== \"object\") {\n throw new Error(\n `Method \"${String(prop)}\" called without proper context. ` +\n `This may indicate the function was called incorrectly.`,\n );\n }\n\n const output = (this as ClientInternal)[SYMBOL_GET_OUTPUT];\n if (!output) {\n throw new Error(\n `Method \"${String(prop)}\" called on invalid client proxy. ` +\n `Ensure you are calling this method on a valid client instance.`,\n );\n }\n\n const method = output[prop];\n if (!method)\n throw new Error(`Method \"${String(prop)}\" is not implemented.`);\n if (typeof method !== \"function\")\n throw new Error(`\"${String(prop)}\" is not a function.`);\n return method(...args);\n };\n fieldAccessFns.set(prop, template);\n }\n return template;\n}\n\nclass ClientProxyHandler\n extends BaseProxyHandler\n implements ProxyHandler<object>\n{\n private boundFns:\n | Map<string | symbol, (...args: never) => unknown>\n | undefined;\n private cachedReceiver: unknown;\n\n constructor(\n private readonly outputRef: {\n current: ClientMethods;\n },\n private readonly index: number,\n ) {\n super();\n }\n\n get(_: unknown, prop: string | symbol, receiver: unknown) {\n if (prop === SYMBOL_GET_OUTPUT) return this.outputRef.current;\n if (prop === SYMBOL_CLIENT_INDEX) return this.index;\n const introspection = handleIntrospectionProp(prop, \"ClientProxy\");\n if (introspection !== false) return introspection;\n const value = this.outputRef.current[prop];\n if (typeof value === \"function\") {\n if (this.cachedReceiver !== receiver) {\n this.boundFns = new Map();\n this.cachedReceiver = receiver;\n }\n let bound = this.boundFns!.get(prop);\n if (!bound) {\n bound = getOrCreateProxyFn(prop).bind(receiver);\n this.boundFns!.set(prop, bound);\n }\n return bound;\n }\n return value;\n }\n\n ownKeys(): ArrayLike<string | symbol> {\n return Object.keys(this.outputRef.current);\n }\n\n has(_: unknown, prop: string | symbol) {\n if (prop === SYMBOL_GET_OUTPUT) return true;\n if (prop === SYMBOL_CLIENT_INDEX) return true;\n return prop in this.outputRef.current;\n }\n}\n\ntype InferClientState<TMethods> = TMethods extends {\n getState: () => infer S;\n}\n ? S\n : undefined;\n\nexport const useClientResource = <TMethods extends ClientMethods>(\n element: ResourceElement<TMethods>,\n): {\n state: InferClientState<TMethods>;\n methods: TMethods;\n key: string | number | undefined;\n} => {\n const valueRef = useRef(null as unknown as TMethods);\n\n const index = useClientStack().length;\n const methods = useMemo(\n () =>\n new Proxy<TMethods>(\n {} as TMethods,\n new ClientProxyHandler(valueRef, index),\n ),\n [index],\n );\n\n const value = useWithClientStack(methods, function WithClientStack() {\n return useResource(element);\n });\n\n if (!valueRef.current) {\n valueRef.current = value;\n }\n\n useEffect(() => {\n valueRef.current = value;\n });\n\n const state = (value as any).getState?.();\n return { methods, state, key: element.key };\n};\n\nexport const ClientResource = resource(useClientResource);\n"],"mappings":";;;;;;;;;AAiBA,MAAM,oBAAoB,OAAO,6BAA6B;AAM9D,MAAa,kBAAkB,WAA0B;CACvD,MAAM,SAAU,OAAqC;CACrD,IAAI,CAAC,QACH,MAAM,IAAI,MACR,iJAEF;CAEF,OAAQ,OAAe,WAAW;AACpC;AAGA,MAAM,iCAAiB,IAAI,IAGzB;AAEF,SAAS,mBAAmB,MAAuB;CACjD,IAAI,WAAW,eAAe,IAAI,IAAI;CACtC,IAAI,CAAC,UAAU;EACb,WAAW,SAAyB,GAAG,MAAiB;GACtD,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,MAAM,IAAI,MACR,WAAW,OAAO,IAAI,EAAE,wFAE1B;GAGF,MAAM,SAAU,KAAwB;GACxC,IAAI,CAAC,QACH,MAAM,IAAI,MACR,WAAW,OAAO,IAAI,EAAE,iGAE1B;GAGF,MAAM,SAAS,OAAO;GACtB,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,WAAW,OAAO,IAAI,EAAE,sBAAsB;GAChE,IAAI,OAAO,WAAW,YACpB,MAAM,IAAI,MAAM,IAAI,OAAO,IAAI,EAAE,qBAAqB;GACxD,OAAO,OAAO,GAAG,IAAI;EACvB;EACA,eAAe,IAAI,MAAM,QAAQ;CACnC;CACA,OAAO;AACT;AAEA,IAAM,qBAAN,cACU,iBAEV;CAOqB;CAGA;CATnB;CAGA;CAEA,YACE,WAGA,OACA;EACA,MAAM;EALW,KAAA,YAAA;EAGA,KAAA,QAAA;CAGnB;CAEA,IAAI,GAAY,MAAuB,UAAmB;EACxD,IAAI,SAAS,mBAAmB,OAAO,KAAK,UAAU;EACtD,IAAI,SAAS,qBAAqB,OAAO,KAAK;EAC9C,MAAM,gBAAgB,wBAAwB,MAAM,aAAa;EACjE,IAAI,kBAAkB,OAAO,OAAO;EACpC,MAAM,QAAQ,KAAK,UAAU,QAAQ;EACrC,IAAI,OAAO,UAAU,YAAY;GAC/B,IAAI,KAAK,mBAAmB,UAAU;IACpC,KAAK,2BAAW,IAAI,IAAI;IACxB,KAAK,iBAAiB;GACxB;GACA,IAAI,QAAQ,KAAK,SAAU,IAAI,IAAI;GACnC,IAAI,CAAC,OAAO;IACV,QAAQ,mBAAmB,IAAI,CAAC,CAAC,KAAK,QAAQ;IAC9C,KAAK,SAAU,IAAI,MAAM,KAAK;GAChC;GACA,OAAO;EACT;EACA,OAAO;CACT;CAEA,UAAsC;EACpC,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO;CAC3C;CAEA,IAAI,GAAY,MAAuB;EACrC,IAAI,SAAS,mBAAmB,OAAO;EACvC,IAAI,SAAS,qBAAqB,OAAO;EACzC,OAAO,QAAQ,KAAK,UAAU;CAChC;AACF;AAQA,MAAa,qBACX,YAKG;CACH,MAAM,WAAW,OAAO,IAA2B;CAEnD,MAAM,QAAQ,eAAe,CAAC,CAAC;CAC/B,MAAM,UAAU,cAEZ,IAAI,MACF,CAAC,GACD,IAAI,mBAAmB,UAAU,KAAK,CACxC,GACF,CAAC,KAAK,CACR;CAEA,MAAM,QAAQ,mBAAmB,SAAS,SAAS,kBAAkB;EACnE,OAAO,YAAY,OAAO;CAC5B,CAAC;CAED,IAAI,CAAC,SAAS,SACZ,SAAS,UAAU;CAGrB,gBAAgB;EACd,SAAS,UAAU;CACrB,CAAC;CAGD,OAAO;EAAE;EAAS,OADH,MAAc,WAAW;EACf,KAAK,QAAQ;CAAI;AAC5C;AAEA,MAAa,iBAAiB,SAAS,iBAAiB"}

@@ -12,5 +12,5 @@ import { AssistantEventName, AssistantEventPayload } from "../types/events.js";

};
declare const NotificationManager: () => import("@assistant-ui/tap").ResourceElement<NotificationManager, undefined>;
declare const NotificationManager: import("@assistant-ui/tap").Resource<NotificationManager, []>;
//#endregion
export { NotificationManager };
//# sourceMappingURL=NotificationManager.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"NotificationManager.d.ts","names":[],"sources":["../../src/utils/NotificationManager.ts"],"mappings":";;;;;KAWY,mBAAA;EACV,EAAA,gBAAkB,kBAAA,EAChB,KAAA,EAAO,MAAA,EACP,QAAA,GACE,OAAA,EAAS,qBAAA,CAAsB,MAAA,GAC/B,WAAA,EAAa,WAAA,YAEd,WAAA;EACH,IAAA,gBAAoB,OAAA,CAAQ,kBAAA,QAC1B,KAAA,EAAO,MAAA,EACP,OAAA,EAAS,qBAAA,CAAsB,MAAA,GAC/B,WAAA,EAAa,WAAA;EAEf,SAAA,CAAU,QAAA,eAAuB,WAAA;EACjC,iBAAA;AAAA;AAAA,cAGW,mBAAA,oCAAmB,eAAA,CAAA,mBAAA"}
{"version":3,"file":"NotificationManager.d.ts","names":[],"sources":["../../src/utils/NotificationManager.ts"],"mappings":";;;;;KAWY,mBAAA;EACV,EAAA,gBAAkB,kBAAA,EAChB,KAAA,EAAO,MAAA,EACP,QAAA,GACE,OAAA,EAAS,qBAAA,CAAsB,MAAA,GAC/B,WAAA,EAAa,WAAA,YAEd,WAAA;EACH,IAAA,gBAAoB,OAAA,CAAQ,kBAAA,QAC1B,KAAA,EAAO,MAAA,EACP,OAAA,EAAS,qBAAA,CAAsB,MAAA,GAC/B,WAAA,EAAa,WAAA;EAEf,SAAA,CAAU,QAAA,eAAuB,WAAA;EACjC,iBAAA;AAAA;AAAA,cA0FW,mBAAA,8BAAmB,QAAA,CAAA,mBAAA"}
import { useMemo } from "@assistant-ui/tap/react-shim";
import { resource } from "@assistant-ui/tap";
//#region src/utils/NotificationManager.ts
const NotificationManager = resource(function NotificationManager() {
const useNotificationManager = () => {
return useMemo(() => {

@@ -68,3 +68,4 @@ const listeners = /* @__PURE__ */ new Map();

}, []);
});
};
const NotificationManager = resource(useNotificationManager);
//#endregion

@@ -71,0 +72,0 @@ export { NotificationManager };

@@ -1,1 +0,1 @@

{"version":3,"file":"NotificationManager.js","names":[],"sources":["../../src/utils/NotificationManager.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type { ClientStack } from \"./tap-client-stack-context\";\nimport type {\n AssistantEventName,\n AssistantEventPayload,\n} from \"../types/events\";\nimport type { Unsubscribe } from \"../types/client\";\n\ntype InternalCallback = (payload: unknown, clientStack: ClientStack) => void;\n\nexport type NotificationManager = {\n on<TEvent extends AssistantEventName>(\n event: TEvent,\n callback: (\n payload: AssistantEventPayload[TEvent],\n clientStack: ClientStack,\n ) => void,\n ): Unsubscribe;\n emit<TEvent extends Exclude<AssistantEventName, \"*\">>(\n event: TEvent,\n payload: AssistantEventPayload[TEvent],\n clientStack: ClientStack,\n ): void;\n subscribe(callback: () => void): Unsubscribe;\n notifySubscribers(): void;\n};\n\nexport const NotificationManager = resource(\n function NotificationManager(): NotificationManager {\n return useMemo(() => {\n const listeners = new Map<string, Set<InternalCallback>>();\n const wildcardListeners = new Set<InternalCallback>();\n const subscribers = new Set<() => void>();\n\n return {\n on(event, callback) {\n const cb = callback as InternalCallback;\n if (event === \"*\") {\n wildcardListeners.add(cb);\n return () => wildcardListeners.delete(cb);\n }\n\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(cb);\n\n return () => {\n set!.delete(cb);\n if (set!.size === 0) listeners.delete(event);\n };\n },\n\n emit(event, payload, clientStack) {\n const eventListeners = listeners.get(event);\n if (!eventListeners && wildcardListeners.size === 0) return;\n\n queueMicrotask(() => {\n const errors = [];\n if (eventListeners) {\n for (const cb of eventListeners) {\n try {\n cb(payload, clientStack);\n } catch (e) {\n errors.push(e);\n }\n }\n }\n if (wildcardListeners.size > 0) {\n const wrapped = { event, payload };\n for (const cb of wildcardListeners) {\n try {\n cb(wrapped, clientStack);\n } catch (e) {\n errors.push(e);\n }\n }\n }\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(\n errors,\n \"Errors occurred during event emission\",\n );\n }\n }\n });\n },\n\n subscribe(callback) {\n subscribers.add(callback);\n return () => subscribers.delete(callback);\n },\n\n notifySubscribers() {\n for (const cb of subscribers) {\n try {\n cb();\n } catch (e) {\n console.error(\n \"NotificationManager: subscriber callback error\",\n e,\n );\n }\n }\n },\n };\n }, []);\n },\n);\n"],"mappings":";;;AA4BA,MAAa,sBAAsB,SACjC,SAAS,sBAA2C;CAClD,OAAO,cAAc;EACnB,MAAM,4BAAY,IAAI,IAAmC;EACzD,MAAM,oCAAoB,IAAI,IAAsB;EACpD,MAAM,8BAAc,IAAI,IAAgB;EAExC,OAAO;GACL,GAAG,OAAO,UAAU;IAClB,MAAM,KAAK;IACX,IAAI,UAAU,KAAK;KACjB,kBAAkB,IAAI,EAAE;KACxB,aAAa,kBAAkB,OAAO,EAAE;IAC1C;IAEA,IAAI,MAAM,UAAU,IAAI,KAAK;IAC7B,IAAI,CAAC,KAAK;KACR,sBAAM,IAAI,IAAI;KACd,UAAU,IAAI,OAAO,GAAG;IAC1B;IACA,IAAI,IAAI,EAAE;IAEV,aAAa;KACX,IAAK,OAAO,EAAE;KACd,IAAI,IAAK,SAAS,GAAG,UAAU,OAAO,KAAK;IAC7C;GACF;GAEA,KAAK,OAAO,SAAS,aAAa;IAChC,MAAM,iBAAiB,UAAU,IAAI,KAAK;IAC1C,IAAI,CAAC,kBAAkB,kBAAkB,SAAS,GAAG;IAErD,qBAAqB;KACnB,MAAM,SAAS,CAAC;KAChB,IAAI,gBACF,KAAK,MAAM,MAAM,gBACf,IAAI;MACF,GAAG,SAAS,WAAW;KACzB,SAAS,GAAG;MACV,OAAO,KAAK,CAAC;KACf;KAGJ,IAAI,kBAAkB,OAAO,GAAG;MAC9B,MAAM,UAAU;OAAE;OAAO;MAAQ;MACjC,KAAK,MAAM,MAAM,mBACf,IAAI;OACF,GAAG,SAAS,WAAW;MACzB,SAAS,GAAG;OACV,OAAO,KAAK,CAAC;MACf;KAEJ;KAEA,IAAI,OAAO,SAAS,GAClB,IAAI,OAAO,WAAW,GACpB,MAAM,OAAO;UACR;MACL,KAAK,MAAM,SAAS,QAClB,QAAQ,MAAM,KAAK;MAErB,MAAM,IAAI,eACR,QACA,uCACF;KACF;IAEJ,CAAC;GACH;GAEA,UAAU,UAAU;IAClB,YAAY,IAAI,QAAQ;IACxB,aAAa,YAAY,OAAO,QAAQ;GAC1C;GAEA,oBAAoB;IAClB,KAAK,MAAM,MAAM,aACf,IAAI;KACF,GAAG;IACL,SAAS,GAAG;KACV,QAAQ,MACN,kDACA,CACF;IACF;GAEJ;EACF;CACF,GAAG,CAAC,CAAC;AACP,CACF"}
{"version":3,"file":"NotificationManager.js","names":[],"sources":["../../src/utils/NotificationManager.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type { ClientStack } from \"./tap-client-stack-context\";\nimport type {\n AssistantEventName,\n AssistantEventPayload,\n} from \"../types/events\";\nimport type { Unsubscribe } from \"../types/client\";\n\ntype InternalCallback = (payload: unknown, clientStack: ClientStack) => void;\n\nexport type NotificationManager = {\n on<TEvent extends AssistantEventName>(\n event: TEvent,\n callback: (\n payload: AssistantEventPayload[TEvent],\n clientStack: ClientStack,\n ) => void,\n ): Unsubscribe;\n emit<TEvent extends Exclude<AssistantEventName, \"*\">>(\n event: TEvent,\n payload: AssistantEventPayload[TEvent],\n clientStack: ClientStack,\n ): void;\n subscribe(callback: () => void): Unsubscribe;\n notifySubscribers(): void;\n};\n\nconst useNotificationManager = (): NotificationManager => {\n return useMemo(() => {\n const listeners = new Map<string, Set<InternalCallback>>();\n const wildcardListeners = new Set<InternalCallback>();\n const subscribers = new Set<() => void>();\n\n return {\n on(event, callback) {\n const cb = callback as InternalCallback;\n if (event === \"*\") {\n wildcardListeners.add(cb);\n return () => wildcardListeners.delete(cb);\n }\n\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(cb);\n\n return () => {\n set!.delete(cb);\n if (set!.size === 0) listeners.delete(event);\n };\n },\n\n emit(event, payload, clientStack) {\n const eventListeners = listeners.get(event);\n if (!eventListeners && wildcardListeners.size === 0) return;\n\n queueMicrotask(() => {\n const errors = [];\n if (eventListeners) {\n for (const cb of eventListeners) {\n try {\n cb(payload, clientStack);\n } catch (e) {\n errors.push(e);\n }\n }\n }\n if (wildcardListeners.size > 0) {\n const wrapped = { event, payload };\n for (const cb of wildcardListeners) {\n try {\n cb(wrapped, clientStack);\n } catch (e) {\n errors.push(e);\n }\n }\n }\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(\n errors,\n \"Errors occurred during event emission\",\n );\n }\n }\n });\n },\n\n subscribe(callback) {\n subscribers.add(callback);\n return () => subscribers.delete(callback);\n },\n\n notifySubscribers() {\n for (const cb of subscribers) {\n try {\n cb();\n } catch (e) {\n console.error(\"NotificationManager: subscriber callback error\", e);\n }\n }\n },\n };\n }, []);\n};\n\nexport const NotificationManager = resource(useNotificationManager);\n"],"mappings":";;;AA4BA,MAAM,+BAAoD;CACxD,OAAO,cAAc;EACnB,MAAM,4BAAY,IAAI,IAAmC;EACzD,MAAM,oCAAoB,IAAI,IAAsB;EACpD,MAAM,8BAAc,IAAI,IAAgB;EAExC,OAAO;GACL,GAAG,OAAO,UAAU;IAClB,MAAM,KAAK;IACX,IAAI,UAAU,KAAK;KACjB,kBAAkB,IAAI,EAAE;KACxB,aAAa,kBAAkB,OAAO,EAAE;IAC1C;IAEA,IAAI,MAAM,UAAU,IAAI,KAAK;IAC7B,IAAI,CAAC,KAAK;KACR,sBAAM,IAAI,IAAI;KACd,UAAU,IAAI,OAAO,GAAG;IAC1B;IACA,IAAI,IAAI,EAAE;IAEV,aAAa;KACX,IAAK,OAAO,EAAE;KACd,IAAI,IAAK,SAAS,GAAG,UAAU,OAAO,KAAK;IAC7C;GACF;GAEA,KAAK,OAAO,SAAS,aAAa;IAChC,MAAM,iBAAiB,UAAU,IAAI,KAAK;IAC1C,IAAI,CAAC,kBAAkB,kBAAkB,SAAS,GAAG;IAErD,qBAAqB;KACnB,MAAM,SAAS,CAAC;KAChB,IAAI,gBACF,KAAK,MAAM,MAAM,gBACf,IAAI;MACF,GAAG,SAAS,WAAW;KACzB,SAAS,GAAG;MACV,OAAO,KAAK,CAAC;KACf;KAGJ,IAAI,kBAAkB,OAAO,GAAG;MAC9B,MAAM,UAAU;OAAE;OAAO;MAAQ;MACjC,KAAK,MAAM,MAAM,mBACf,IAAI;OACF,GAAG,SAAS,WAAW;MACzB,SAAS,GAAG;OACV,OAAO,KAAK,CAAC;MACf;KAEJ;KAEA,IAAI,OAAO,SAAS,GAClB,IAAI,OAAO,WAAW,GACpB,MAAM,OAAO;UACR;MACL,KAAK,MAAM,SAAS,QAClB,QAAQ,MAAM,KAAK;MAErB,MAAM,IAAI,eACR,QACA,uCACF;KACF;IAEJ,CAAC;GACH;GAEA,UAAU,UAAU;IAClB,YAAY,IAAI,QAAQ;IACxB,aAAa,YAAY,OAAO,QAAQ;GAC1C;GAEA,oBAAoB;IAClB,KAAK,MAAM,MAAM,aACf,IAAI;KACF,GAAG;IACL,SAAS,GAAG;KACV,QAAQ,MAAM,kDAAkD,CAAC;IACnE;GAEJ;EACF;CACF,GAAG,CAAC,CAAC;AACP;AAEA,MAAa,sBAAsB,SAAS,sBAAsB"}

@@ -9,2 +9,7 @@ import { AssistantClient } from "../types/client.js";

declare const createRootAssistantClient: () => AssistantClient;
/**
* Carries the tap host's effects callback on the client so AuiProvider can
* mount the host's commit ahead of its children's effects.
*/
declare const AUI_USE_EFFECTS_SYMBOL: unique symbol;
declare const useAssistantContextValue: () => AssistantClient;

@@ -40,3 +45,3 @@ /**

//#endregion
export { AuiProvider, DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue };
export { AUI_USE_EFFECTS_SYMBOL, AuiProvider, DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue };
//# sourceMappingURL=react-assistant-context.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"react-assistant-context.d.ts","names":[],"sources":["../../src/utils/react-assistant-context.tsx"],"mappings":";;;;;cAsDa,sBAAA,EAAwB,eAIlC;AAJH;AAAA,cAWa,yBAAA,QAAgC,eAUzC;AAAA,cAOS,wBAAA,QAA+B,eAE3C;;AA1BE;AAOH;;;;AAUI;AAOJ;;;;AAEC;AAuBD;;;;;;;;;cAAa,WAAA;EAAe,KAAA;EAAA;AAAA;EAAA,iDAK1B,KAAA,EAAO,eAAA,EALmB;EAO1B,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA,MACd,KAAA,CAAM,YAAA"}
{"version":3,"file":"react-assistant-context.d.ts","names":[],"sources":["../../src/utils/react-assistant-context.tsx"],"mappings":";;;;;cAsDa,sBAAA,EAAwB,eAIlC;AAJH;AAAA,cAWa,yBAAA,QAAgC,eAUzC;;;AAjBD;AAOH;cAqBa,sBAAA;AAAA,cAmBA,wBAAA,QAA+B,eAE3C;;AAhCG;AAWJ;;;;AAA6E;AAmB7E;;;;AAEC;AAuBD;;;;;;;;;cAAa,WAAA;EAAe,KAAA;EAAA;AAAA;EAAA,iDAK1B,KAAA,EAAO,eAAA,EALmB;EAO1B,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA,MACd,KAAA,CAAM,YAAA"}
import { BaseProxyHandler, handleIntrospectionProp } from "./BaseProxyHandler.js";
import { PROXIED_ASSISTANT_STATE_SYMBOL, createProxiedAssistantState } from "./proxied-assistant-state.js";
import { createContext, useContext } from "@assistant-ui/tap/react-shim";
import { jsx } from "react/jsx-runtime";
import { createContext, useContext, useEffect } from "@assistant-ui/tap/react-shim";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/utils/react-assistant-context.tsx

@@ -48,2 +48,16 @@ const NO_OP_SUBSCRIBE = () => () => {};

const AssistantContext = createContext(DefaultAssistantClient);
/**
* Carries the tap host's effects callback on the client so AuiProvider can
* mount the host's commit ahead of its children's effects.
*/
const AUI_USE_EFFECTS_SYMBOL = Symbol("assistant-ui.store.useEffects");
const NOOP_EFFECT = () => {};
const getTapEffects = (client) => {
return client[AUI_USE_EFFECTS_SYMBOL] ?? NOOP_EFFECT;
};
const UseTapEffects = () => {
"use no memo";
useEffect(getTapEffects(useAssistantContextValue()));
return null;
};
const useAssistantContextValue = () => {

@@ -74,10 +88,11 @@ return useContext(AssistantContext);

const AuiProvider = ({ value, children }) => {
return /* @__PURE__ */ jsx(AssistantContext.Provider, {
"use no memo";
return /* @__PURE__ */ jsxs(AssistantContext.Provider, {
value,
children
children: [/* @__PURE__ */ jsx(UseTapEffects, {}), children]
});
};
//#endregion
export { AuiProvider, DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue };
export { AUI_USE_EFFECTS_SYMBOL, AuiProvider, DefaultAssistantClient, createRootAssistantClient, useAssistantContextValue };
//# sourceMappingURL=react-assistant-context.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"react-assistant-context.js","names":[],"sources":["../../src/utils/react-assistant-context.tsx"],"sourcesContent":["import type React from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { AssistantClient, AssistantClientAccessor } from \"../types/client\";\nimport {\n createProxiedAssistantState,\n PROXIED_ASSISTANT_STATE_SYMBOL,\n} from \"./proxied-assistant-state\";\nimport { BaseProxyHandler, handleIntrospectionProp } from \"./BaseProxyHandler\";\n\nconst NO_OP_SUBSCRIBE = () => () => {};\n\nconst createErrorClientField = (\n message: string,\n): AssistantClientAccessor<never> => {\n const fn = (() => {\n throw new Error(message);\n }) as AssistantClientAccessor<never>;\n fn.source = null;\n fn.query = null;\n return fn;\n};\n\nclass DefaultAssistantClientProxyHandler\n extends BaseProxyHandler\n implements ProxyHandler<AssistantClient>\n{\n get(_: unknown, prop: string | symbol) {\n if (prop === \"subscribe\") return NO_OP_SUBSCRIBE;\n if (prop === \"on\") return NO_OP_SUBSCRIBE;\n if (prop === PROXIED_ASSISTANT_STATE_SYMBOL)\n return DefaultAssistantClientProxiedAssistantState;\n const introspection = handleIntrospectionProp(\n prop,\n \"DefaultAssistantClient\",\n );\n if (introspection !== false) return introspection;\n return createErrorClientField(\n \"You are using a component or hook that requires an AuiProvider. Wrap your component in an <AuiProvider> component.\",\n );\n }\n\n ownKeys(): ArrayLike<string | symbol> {\n return [\"subscribe\", \"on\", PROXIED_ASSISTANT_STATE_SYMBOL];\n }\n\n has(_: unknown, prop: string | symbol): boolean {\n return (\n prop === \"subscribe\" ||\n prop === \"on\" ||\n prop === PROXIED_ASSISTANT_STATE_SYMBOL\n );\n }\n}\n/** Default context value - throws \"wrap in AuiProvider\" error */\nexport const DefaultAssistantClient: AssistantClient =\n new Proxy<AssistantClient>(\n {} as AssistantClient,\n new DefaultAssistantClientProxyHandler(),\n );\n\nconst DefaultAssistantClientProxiedAssistantState = createProxiedAssistantState(\n DefaultAssistantClient,\n);\n\n/** Root prototype for created clients - throws \"scope not defined\" error */\nexport const createRootAssistantClient = (): AssistantClient =>\n new Proxy<AssistantClient>({} as AssistantClient, {\n get(_: AssistantClient, prop: string | symbol) {\n const introspection = handleIntrospectionProp(prop, \"AssistantClient\");\n if (introspection !== false) return introspection;\n\n return createErrorClientField(\n `The current scope does not have a \"${String(prop)}\" property.`,\n );\n },\n });\n\n/**\n * React Context for the AssistantClient\n */\nconst AssistantContext = createContext<AssistantClient>(DefaultAssistantClient);\n\nexport const useAssistantContextValue = (): AssistantClient => {\n return useContext(AssistantContext);\n};\n\n/**\n * Supplies an `AssistantClient` to the React tree.\n *\n * Place near the root of any subtree that uses {@link useAui} or the\n * primitives built on it. Components rendered outside an `AuiProvider`\n * receive a default client whose scope accessors throw on use, so\n * missing-provider mistakes surface at the point of use.\n *\n * When mounting a runtime built with one of the runtime hooks, use\n * {@link AssistantRuntimeProvider} — it installs an `AuiProvider`\n * internally — rather than wiring `AuiProvider` yourself.\n *\n * @example\n * ```tsx\n * function ScopedAssistant({ children, scopes }) {\n * const aui = useAui(scopes);\n *\n * return <AuiProvider value={aui}>{children}</AuiProvider>;\n * }\n * ```\n */\nexport const AuiProvider = ({\n value,\n children,\n}: {\n /** Assistant client to expose to descendants. */\n value: AssistantClient;\n /** Subtree that may read from the client. */\n children: React.ReactNode;\n}): React.ReactElement => {\n return (\n <AssistantContext.Provider value={value}>\n {children}\n </AssistantContext.Provider>\n );\n};\n"],"mappings":";;;;;AASA,MAAM,8BAA8B,CAAC;AAErC,MAAM,0BACJ,YACmC;CACnC,MAAM,YAAY;EAChB,MAAM,IAAI,MAAM,OAAO;CACzB;CACA,GAAG,SAAS;CACZ,GAAG,QAAQ;CACX,OAAO;AACT;AAEA,IAAM,qCAAN,cACU,iBAEV;CACE,IAAI,GAAY,MAAuB;EACrC,IAAI,SAAS,aAAa,OAAO;EACjC,IAAI,SAAS,MAAM,OAAO;EAC1B,IAAI,SAAS,gCACX,OAAO;EACT,MAAM,gBAAgB,wBACpB,MACA,wBACF;EACA,IAAI,kBAAkB,OAAO,OAAO;EACpC,OAAO,uBACL,oHACF;CACF;CAEA,UAAsC;EACpC,OAAO;GAAC;GAAa;GAAM;EAA8B;CAC3D;CAEA,IAAI,GAAY,MAAgC;EAC9C,OACE,SAAS,eACT,SAAS,QACT,SAAS;CAEb;AACF;;AAEA,MAAa,yBACX,IAAI,MACF,CAAC,GACD,IAAI,mCAAmC,CACzC;AAEF,MAAM,8CAA8C,4BAClD,sBACF;;AAGA,MAAa,kCACX,IAAI,MAAuB,CAAC,GAAsB,EAChD,IAAI,GAAoB,MAAuB;CAC7C,MAAM,gBAAgB,wBAAwB,MAAM,iBAAiB;CACrE,IAAI,kBAAkB,OAAO,OAAO;CAEpC,OAAO,uBACL,sCAAsC,OAAO,IAAI,EAAE,YACrD;AACF,EACF,CAAC;;;;AAKH,MAAM,mBAAmB,cAA+B,sBAAsB;AAE9E,MAAa,iCAAkD;CAC7D,OAAO,WAAW,gBAAgB;AACpC;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,eAAe,EAC1B,OACA,eAMwB;CACxB,OACE,oBAAC,iBAAiB,UAAlB;EAAkC;EAC/B;CACwB,CAAA;AAE/B"}
{"version":3,"file":"react-assistant-context.js","names":[],"sources":["../../src/utils/react-assistant-context.tsx"],"sourcesContent":["import type React from \"react\";\nimport { createContext, useContext, useEffect } from \"react\";\nimport type { AssistantClient, AssistantClientAccessor } from \"../types/client\";\nimport {\n createProxiedAssistantState,\n PROXIED_ASSISTANT_STATE_SYMBOL,\n} from \"./proxied-assistant-state\";\nimport { BaseProxyHandler, handleIntrospectionProp } from \"./BaseProxyHandler\";\n\nconst NO_OP_SUBSCRIBE = () => () => {};\n\nconst createErrorClientField = (\n message: string,\n): AssistantClientAccessor<never> => {\n const fn = (() => {\n throw new Error(message);\n }) as AssistantClientAccessor<never>;\n fn.source = null;\n fn.query = null;\n return fn;\n};\n\nclass DefaultAssistantClientProxyHandler\n extends BaseProxyHandler\n implements ProxyHandler<AssistantClient>\n{\n get(_: unknown, prop: string | symbol) {\n if (prop === \"subscribe\") return NO_OP_SUBSCRIBE;\n if (prop === \"on\") return NO_OP_SUBSCRIBE;\n if (prop === PROXIED_ASSISTANT_STATE_SYMBOL)\n return DefaultAssistantClientProxiedAssistantState;\n const introspection = handleIntrospectionProp(\n prop,\n \"DefaultAssistantClient\",\n );\n if (introspection !== false) return introspection;\n return createErrorClientField(\n \"You are using a component or hook that requires an AuiProvider. Wrap your component in an <AuiProvider> component.\",\n );\n }\n\n ownKeys(): ArrayLike<string | symbol> {\n return [\"subscribe\", \"on\", PROXIED_ASSISTANT_STATE_SYMBOL];\n }\n\n has(_: unknown, prop: string | symbol): boolean {\n return (\n prop === \"subscribe\" ||\n prop === \"on\" ||\n prop === PROXIED_ASSISTANT_STATE_SYMBOL\n );\n }\n}\n/** Default context value - throws \"wrap in AuiProvider\" error */\nexport const DefaultAssistantClient: AssistantClient =\n new Proxy<AssistantClient>(\n {} as AssistantClient,\n new DefaultAssistantClientProxyHandler(),\n );\n\nconst DefaultAssistantClientProxiedAssistantState = createProxiedAssistantState(\n DefaultAssistantClient,\n);\n\n/** Root prototype for created clients - throws \"scope not defined\" error */\nexport const createRootAssistantClient = (): AssistantClient =>\n new Proxy<AssistantClient>({} as AssistantClient, {\n get(_: AssistantClient, prop: string | symbol) {\n const introspection = handleIntrospectionProp(prop, \"AssistantClient\");\n if (introspection !== false) return introspection;\n\n return createErrorClientField(\n `The current scope does not have a \"${String(prop)}\" property.`,\n );\n },\n });\n\n/**\n * React Context for the AssistantClient\n */\nconst AssistantContext = createContext<AssistantClient>(DefaultAssistantClient);\n\n/**\n * Carries the tap host's effects callback on the client so AuiProvider can\n * mount the host's commit ahead of its children's effects.\n */\nexport const AUI_USE_EFFECTS_SYMBOL = Symbol(\"assistant-ui.store.useEffects\");\n\nconst NOOP_EFFECT = () => {};\n\nconst getTapEffects = (client: AssistantClient): (() => void) => {\n return (\n (client as Record<symbol, never>)[AUI_USE_EFFECTS_SYMBOL] ?? NOOP_EFFECT\n );\n};\n\nconst UseTapEffects = () => {\n \"use no memo\";\n\n const aui = useAssistantContextValue();\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n useEffect(getTapEffects(aui));\n return null;\n};\n\nexport const useAssistantContextValue = (): AssistantClient => {\n return useContext(AssistantContext);\n};\n\n/**\n * Supplies an `AssistantClient` to the React tree.\n *\n * Place near the root of any subtree that uses {@link useAui} or the\n * primitives built on it. Components rendered outside an `AuiProvider`\n * receive a default client whose scope accessors throw on use, so\n * missing-provider mistakes surface at the point of use.\n *\n * When mounting a runtime built with one of the runtime hooks, use\n * {@link AssistantRuntimeProvider} — it installs an `AuiProvider`\n * internally — rather than wiring `AuiProvider` yourself.\n *\n * @example\n * ```tsx\n * function ScopedAssistant({ children, scopes }) {\n * const aui = useAui(scopes);\n *\n * return <AuiProvider value={aui}>{children}</AuiProvider>;\n * }\n * ```\n */\nexport const AuiProvider = ({\n value,\n children,\n}: {\n /** Assistant client to expose to descendants. */\n value: AssistantClient;\n /** Subtree that may read from the client. */\n children: React.ReactNode;\n}): React.ReactElement => {\n // The <UseTapEffects /> element must be created fresh each render\n \"use no memo\";\n return (\n <AssistantContext.Provider value={value}>\n <UseTapEffects />\n {children}\n </AssistantContext.Provider>\n );\n};\n"],"mappings":";;;;;AASA,MAAM,8BAA8B,CAAC;AAErC,MAAM,0BACJ,YACmC;CACnC,MAAM,YAAY;EAChB,MAAM,IAAI,MAAM,OAAO;CACzB;CACA,GAAG,SAAS;CACZ,GAAG,QAAQ;CACX,OAAO;AACT;AAEA,IAAM,qCAAN,cACU,iBAEV;CACE,IAAI,GAAY,MAAuB;EACrC,IAAI,SAAS,aAAa,OAAO;EACjC,IAAI,SAAS,MAAM,OAAO;EAC1B,IAAI,SAAS,gCACX,OAAO;EACT,MAAM,gBAAgB,wBACpB,MACA,wBACF;EACA,IAAI,kBAAkB,OAAO,OAAO;EACpC,OAAO,uBACL,oHACF;CACF;CAEA,UAAsC;EACpC,OAAO;GAAC;GAAa;GAAM;EAA8B;CAC3D;CAEA,IAAI,GAAY,MAAgC;EAC9C,OACE,SAAS,eACT,SAAS,QACT,SAAS;CAEb;AACF;;AAEA,MAAa,yBACX,IAAI,MACF,CAAC,GACD,IAAI,mCAAmC,CACzC;AAEF,MAAM,8CAA8C,4BAClD,sBACF;;AAGA,MAAa,kCACX,IAAI,MAAuB,CAAC,GAAsB,EAChD,IAAI,GAAoB,MAAuB;CAC7C,MAAM,gBAAgB,wBAAwB,MAAM,iBAAiB;CACrE,IAAI,kBAAkB,OAAO,OAAO;CAEpC,OAAO,uBACL,sCAAsC,OAAO,IAAI,EAAE,YACrD;AACF,EACF,CAAC;;;;AAKH,MAAM,mBAAmB,cAA+B,sBAAsB;;;;;AAM9E,MAAa,yBAAyB,OAAO,+BAA+B;AAE5E,MAAM,oBAAoB,CAAC;AAE3B,MAAM,iBAAiB,WAA0C;CAC/D,OACG,OAAiC,2BAA2B;AAEjE;AAEA,MAAM,sBAAsB;CAC1B;CAIA,UAAU,cAFE,yBAEc,CAAC,CAAC;CAC5B,OAAO;AACT;AAEA,MAAa,iCAAkD;CAC7D,OAAO,WAAW,gBAAgB;AACpC;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,eAAe,EAC1B,OACA,eAMwB;CAExB;CACA,OACE,qBAAC,iBAAiB,UAAlB;EAAkC;YAAlC,CACE,oBAAC,eAAD,CAAgB,CAAA,GACf,QACwB;;AAE/B"}

@@ -1,1 +0,1 @@

{"version":3,"file":"splitClients.d.ts","names":[],"sources":["../../src/utils/splitClients.ts"],"mappings":";;;;;KAWY,WAAA,GAAc,OAAA,CACxB,MAAA,CAAO,WAAA,EAAa,aAAA,CAAc,WAAA;AAAA,KAExB,cAAA,GAAiB,OAAA,CAC3B,MAAA,CAAO,WAAA,EAAa,cAAA,CAAe,WAAA;AAAA,cAyDxB,eAAA,GACX,OAAA,EAAS,MAAA,CAAO,KAAA,EAChB,UAAA,EAAY,eAAA"}
{"version":3,"file":"splitClients.d.ts","names":[],"sources":["../../src/utils/splitClients.ts"],"mappings":";;;;;KAUY,WAAA,GAAc,OAAA,CACxB,MAAA,CAAO,WAAA,EAAa,aAAA,CAAc,WAAA;AAAA,KAExB,cAAA,GAAiB,OAAA,CAC3B,MAAA,CAAO,WAAA,EAAa,cAAA,CAAe,WAAA;AAAA,cAuDxB,eAAA,GACX,OAAA,EAAS,MAAA,CAAO,KAAA,EAChB,UAAA,EAAY,eAAA"}

@@ -1,2 +0,2 @@

import { Derived } from "../Derived.js";
import { useDerived } from "../Derived.js";
import { getTransformScopes } from "../attachTransformScopes.js";

@@ -16,6 +16,6 @@ import { useMemo } from "@assistant-ui/tap/react-shim";

for (const clientElement of Object.values(scopes)) {
if (clientElement.type === Derived) continue;
if (visited.has(clientElement.type)) continue;
visited.add(clientElement.type);
const transform = getTransformScopes(clientElement.type);
if (clientElement.hook === useDerived) continue;
if (visited.has(clientElement.hook)) continue;
visited.add(clientElement.hook);
const transform = getTransformScopes(clientElement.hook);
if (transform) {

@@ -30,3 +30,3 @@ transform(scopes, baseClient);

const derivedClients = {};
for (const [key, clientElement] of Object.entries(scopes)) if (clientElement.type === Derived) derivedClients[key] = clientElement;
for (const [key, clientElement] of Object.entries(scopes)) if (clientElement.hook === useDerived) derivedClients[key] = clientElement;
else rootClients[key] = clientElement;

@@ -33,0 +33,0 @@ return {

@@ -1,1 +0,1 @@

{"version":3,"file":"splitClients.js","names":[],"sources":["../../src/utils/splitClients.ts"],"sourcesContent":["import { Derived, type DerivedElement } from \"../Derived\";\nimport type {\n AssistantClient,\n ClientElement,\n ClientNames,\n} from \"../types/client\";\nimport { getTransformScopes } from \"../attachTransformScopes\";\nimport type { useAui } from \"../useAui\";\nimport { useMemo } from \"react\";\nimport { type ResourceElement } from \"@assistant-ui/tap\";\n\nexport type RootClients = Partial<\n Record<ClientNames, ClientElement<ClientNames>>\n>;\nexport type DerivedClients = Partial<\n Record<ClientNames, DerivedElement<ClientNames>>\n>;\n\n/**\n * Splits a clients object into root clients and derived clients,\n * applying transformScopes from root client elements.\n */\nfunction splitClients(clients: useAui.Props, baseClient: AssistantClient) {\n // 1. Collect transforms from root elements and run them iteratively\n const scopes = { ...clients } as Record<\n string,\n ClientElement<ClientNames> | DerivedElement<ClientNames>\n >;\n const visited = new Set<(...args: any[]) => any>();\n\n let changed = true;\n while (changed) {\n changed = false;\n for (const clientElement of Object.values(scopes)) {\n if (clientElement.type === (Derived as unknown)) continue;\n if (visited.has(clientElement.type)) continue;\n visited.add(clientElement.type);\n\n const transform = getTransformScopes(\n clientElement.type as (props: any) => ResourceElement<any>,\n );\n if (transform) {\n transform(scopes, baseClient);\n changed = true;\n break; // restart iteration since scopes may have new root elements\n }\n }\n }\n\n // 2. Split result into root/derived\n const rootClients: RootClients = {};\n const derivedClients: DerivedClients = {};\n\n for (const [key, clientElement] of Object.entries(scopes) as [\n ClientNames,\n ClientElement<ClientNames> | DerivedElement<ClientNames>,\n ][]) {\n if (clientElement.type === (Derived as unknown)) {\n derivedClients[key] = clientElement as DerivedElement<ClientNames>;\n } else {\n rootClients[key] = clientElement as ClientElement<ClientNames>;\n }\n }\n\n return { rootClients, derivedClients };\n}\n\nconst useShallowMemoObject = <T extends object>(object: T) => {\n // oxlint-disable-next-line react/exhaustive-deps -- shallow memo over the object's flattened entries\n return useMemo(() => object, [...Object.entries(object).flat()]);\n};\n\nexport const useSplitClients = (\n clients: useAui.Props,\n baseClient: AssistantClient,\n) => {\n const { rootClients, derivedClients } = splitClients(clients, baseClient);\n\n return {\n rootClients: useShallowMemoObject(rootClients),\n derivedClients: useShallowMemoObject(derivedClients),\n };\n};\n"],"mappings":";;;;;;;;AAsBA,SAAS,aAAa,SAAuB,YAA6B;CAExE,MAAM,SAAS,EAAE,GAAG,QAAQ;CAI5B,MAAM,0BAAU,IAAI,IAA6B;CAEjD,IAAI,UAAU;CACd,OAAO,SAAS;EACd,UAAU;EACV,KAAK,MAAM,iBAAiB,OAAO,OAAO,MAAM,GAAG;GACjD,IAAI,cAAc,SAAU,SAAqB;GACjD,IAAI,QAAQ,IAAI,cAAc,IAAI,GAAG;GACrC,QAAQ,IAAI,cAAc,IAAI;GAE9B,MAAM,YAAY,mBAChB,cAAc,IAChB;GACA,IAAI,WAAW;IACb,UAAU,QAAQ,UAAU;IAC5B,UAAU;IACV;GACF;EACF;CACF;CAGA,MAAM,cAA2B,CAAC;CAClC,MAAM,iBAAiC,CAAC;CAExC,KAAK,MAAM,CAAC,KAAK,kBAAkB,OAAO,QAAQ,MAAM,GAItD,IAAI,cAAc,SAAU,SAC1B,eAAe,OAAO;MAEtB,YAAY,OAAO;CAIvB,OAAO;EAAE;EAAa;CAAe;AACvC;AAEA,MAAM,wBAA0C,WAAc;CAE5D,OAAO,cAAc,QAAQ,CAAC,GAAG,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AACjE;AAEA,MAAa,mBACX,SACA,eACG;CACH,MAAM,EAAE,aAAa,mBAAmB,aAAa,SAAS,UAAU;CAExE,OAAO;EACL,aAAa,qBAAqB,WAAW;EAC7C,gBAAgB,qBAAqB,cAAc;CACrD;AACF"}
{"version":3,"file":"splitClients.js","names":[],"sources":["../../src/utils/splitClients.ts"],"sourcesContent":["import { useDerived, type DerivedElement } from \"../Derived\";\nimport type {\n AssistantClient,\n ClientElement,\n ClientNames,\n} from \"../types/client\";\nimport { getTransformScopes } from \"../attachTransformScopes\";\nimport type { useAui } from \"../useAui\";\nimport { useMemo } from \"react\";\n\nexport type RootClients = Partial<\n Record<ClientNames, ClientElement<ClientNames>>\n>;\nexport type DerivedClients = Partial<\n Record<ClientNames, DerivedElement<ClientNames>>\n>;\n\n/**\n * Splits a clients object into root clients and derived clients,\n * applying transformScopes from root client elements.\n */\nfunction splitClients(clients: useAui.Props, baseClient: AssistantClient) {\n // 1. Collect transforms from root elements and run them iteratively\n const scopes = { ...clients } as Record<\n string,\n ClientElement<ClientNames> | DerivedElement<ClientNames>\n >;\n const visited = new Set<(...args: any[]) => any>();\n\n let changed = true;\n while (changed) {\n changed = false;\n for (const clientElement of Object.values(scopes)) {\n if (clientElement.hook === (useDerived as unknown)) continue;\n if (visited.has(clientElement.hook)) continue;\n visited.add(clientElement.hook);\n\n const transform = getTransformScopes(clientElement.hook);\n if (transform) {\n transform(scopes, baseClient);\n changed = true;\n break; // restart iteration since scopes may have new root elements\n }\n }\n }\n\n // 2. Split result into root/derived\n const rootClients: RootClients = {};\n const derivedClients: DerivedClients = {};\n\n for (const [key, clientElement] of Object.entries(scopes) as [\n ClientNames,\n ClientElement<ClientNames> | DerivedElement<ClientNames>,\n ][]) {\n if (clientElement.hook === (useDerived as unknown)) {\n derivedClients[key] = clientElement as DerivedElement<ClientNames>;\n } else {\n rootClients[key] = clientElement as ClientElement<ClientNames>;\n }\n }\n\n return { rootClients, derivedClients };\n}\n\nconst useShallowMemoObject = <T extends object>(object: T) => {\n // oxlint-disable-next-line react/exhaustive-deps -- shallow memo over the object's flattened entries\n return useMemo(() => object, [...Object.entries(object).flat()]);\n};\n\nexport const useSplitClients = (\n clients: useAui.Props,\n baseClient: AssistantClient,\n) => {\n const { rootClients, derivedClients } = splitClients(clients, baseClient);\n\n return {\n rootClients: useShallowMemoObject(rootClients),\n derivedClients: useShallowMemoObject(derivedClients),\n };\n};\n"],"mappings":";;;;;;;;AAqBA,SAAS,aAAa,SAAuB,YAA6B;CAExE,MAAM,SAAS,EAAE,GAAG,QAAQ;CAI5B,MAAM,0BAAU,IAAI,IAA6B;CAEjD,IAAI,UAAU;CACd,OAAO,SAAS;EACd,UAAU;EACV,KAAK,MAAM,iBAAiB,OAAO,OAAO,MAAM,GAAG;GACjD,IAAI,cAAc,SAAU,YAAwB;GACpD,IAAI,QAAQ,IAAI,cAAc,IAAI,GAAG;GACrC,QAAQ,IAAI,cAAc,IAAI;GAE9B,MAAM,YAAY,mBAAmB,cAAc,IAAI;GACvD,IAAI,WAAW;IACb,UAAU,QAAQ,UAAU;IAC5B,UAAU;IACV;GACF;EACF;CACF;CAGA,MAAM,cAA2B,CAAC;CAClC,MAAM,iBAAiC,CAAC;CAExC,KAAK,MAAM,CAAC,KAAK,kBAAkB,OAAO,QAAQ,MAAM,GAItD,IAAI,cAAc,SAAU,YAC1B,eAAe,OAAO;MAEtB,YAAY,OAAO;CAIvB,OAAO;EAAE;EAAa;CAAe;AACvC;AAEA,MAAM,wBAA0C,WAAc;CAE5D,OAAO,cAAc,QAAQ,CAAC,GAAG,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AACjE;AAEA,MAAa,mBACX,SACA,eACG;CACH,MAAM,EAAE,aAAa,mBAAmB,aAAa,SAAS,UAAU;CAExE,OAAO;EACL,aAAa,qBAAqB,WAAW;EAC7C,gBAAgB,qBAAqB,cAAc;CACrD;AACF"}
{
"name": "@assistant-ui/store",
"version": "0.2.14",
"version": "0.2.16",
"description": "Tap-based state management for @assistant-ui",

@@ -33,3 +33,3 @@ "keywords": [

"peerDependencies": {
"@assistant-ui/tap": "^0.6.0",
"@assistant-ui/tap": "^0.7.0",
"@types/react": "*",

@@ -50,4 +50,4 @@ "react": "^18 || ^19"

"vitest": "^4.1.8",
"@assistant-ui/x-buildutils": "0.0.12",
"@assistant-ui/tap": "0.6.0"
"@assistant-ui/tap": "0.7.1",
"@assistant-ui/x-buildutils": "0.0.12"
},

@@ -54,0 +54,0 @@ "publishConfig": {

@@ -39,3 +39,3 @@ # `@assistant-ui/store`

const CounterClient = resource(function CounterClient(): ClientOutput<"counter"> {
const useCounterClient = (): ClientOutput<"counter"> => {
const [state, setState] = useState({ count: 0 });

@@ -46,4 +46,6 @@ return {

};
});
};
const CounterClient = resource(useCounterClient);
function App() {

@@ -50,0 +52,0 @@ const aui = useAui({ counter: CounterClient() });

@@ -1,2 +0,1 @@

import { type ResourceElement } from "@assistant-ui/tap";
import type {

@@ -20,27 +19,28 @@ AssistantClient,

type ResourceWithTransformScopes = {
// Transforms are keyed by the resource's underlying hook (the function passed to
// `resource()`), since that is the identity a `ResourceElement` carries.
type Hook = (...args: any[]) => any;
type HookWithTransformScopes = Hook & {
[TRANSFORM_SCOPES]?: TransformScopesFn;
};
export function attachTransformScopes<
T extends (...args: any[]) => ResourceElement<any>,
>(resource: T, transform: TransformScopesFn): void {
const r = resource as T & ResourceWithTransformScopes;
if (r[TRANSFORM_SCOPES]) {
export function attachTransformScopes(
hook: Hook,
transform: TransformScopesFn,
): void {
const h = hook as HookWithTransformScopes;
if (h[TRANSFORM_SCOPES]) {
throw new Error("transformScopes is already attached to this resource");
}
r[TRANSFORM_SCOPES] = transform;
h[TRANSFORM_SCOPES] = transform;
}
export function forwardTransformScopes<
T extends (...args: any[]) => ResourceElement<any>,
S extends (...args: any[]) => ResourceElement<any>,
>(target: T, source: S): void {
export function forwardTransformScopes(target: Hook, source: Hook): void {
const sourceTransform = getTransformScopes(source);
if (!sourceTransform) return;
const r = target as T & ResourceWithTransformScopes;
const existingTransform = r[TRANSFORM_SCOPES];
const t = target as HookWithTransformScopes;
const existingTransform = t[TRANSFORM_SCOPES];
if (existingTransform) {
r[TRANSFORM_SCOPES] = (scopes, parent) => {
t[TRANSFORM_SCOPES] = (scopes, parent) => {
sourceTransform(scopes, parent);

@@ -50,10 +50,8 @@ existingTransform(scopes, parent);

} else {
r[TRANSFORM_SCOPES] = sourceTransform;
t[TRANSFORM_SCOPES] = sourceTransform;
}
}
export function getTransformScopes<
T extends (...args: any[]) => ResourceElement<any>,
>(resource: T): TransformScopesFn | undefined {
return (resource as T & ResourceWithTransformScopes)[TRANSFORM_SCOPES];
export function getTransformScopes(hook: Hook): TransformScopesFn | undefined {
return (hook as HookWithTransformScopes)[TRANSFORM_SCOPES];
}

@@ -28,11 +28,15 @@ import { resource, type ResourceElement } from "@assistant-ui/tap";

*/
export const Derived = resource(function Derived<K extends ClientNames>(
// Exported so consumers (e.g. splitClients) can identify a derived element by its
// hook: a `Derived(...)` element carries `hook === useDerived`.
export const useDerived = <K extends ClientNames>(
_config: Derived.Props<K>,
): null {
): null => {
return null;
});
};
export const Derived = resource(useDerived);
export type DerivedElement<K extends ClientNames> = ResourceElement<
null,
Derived.Props<K>
[Derived.Props<K>]
>;

@@ -39,0 +43,0 @@

@@ -105,3 +105,3 @@ import { type ResourceElement } from "@assistant-ui/tap";

* ```typescript
* const FooResource = resource(function FooResource(): ClientResourceOutput<"foo"> {
* const useFoo = (): ClientResourceOutput<"foo"> => {
* const [state, setState] = useState({ bar: "hello" });

@@ -112,3 +112,5 @@ * return {

* };
* });
* };
*
* const FooResource = resource(useFoo);
* ```

@@ -115,0 +117,0 @@ */

@@ -6,3 +6,4 @@ "use client";

useResources,
useResourceRoot,
useTapHost,
useTapRoot,
resource,

@@ -25,2 +26,3 @@ withKey,

createRootAssistantClient,
AUI_USE_EFFECTS_SYMBOL,
} from "./utils/react-assistant-context";

@@ -52,5 +54,3 @@ import {

const RootClientResource = resource(function RootClientResource<
K extends ClientNames,
>({
const useRootClientResource = <K extends ClientNames>({
element,

@@ -63,14 +63,13 @@ emit,

clientRef: { parent: AssistantClient; current: AssistantClient | null };
}) {
}) => {
const { methods, state } = withAssistantTapContextProvider(
{ clientRef, emit },
// oxlint-disable-next-line react/rules-of-hooks -- withAssistantTapContextProvider runs this callback synchronously during render, so hook order is preserved
() => useClientResource(element),
function WithTapContext() {
return useClientResource(element);
},
);
return useMemo(() => ({ state, methods }), [methods, state]);
});
};
const RootClientAccessorResource = resource(function RootClientAccessorResource<
K extends ClientNames,
>({
const useRootClientAccessorResource = <K extends ClientNames>({
element,

@@ -85,6 +84,10 @@ notifications,

name: K;
}): AssistantClientAccessor<K> {
const store = useResourceRoot(
RootClientResource({ element, emit: notifications.emit, clientRef }),
);
}): AssistantClientAccessor<K> => {
const store = useTapRoot(function RootClient() {
return useRootClientResource({
element,
emit: notifications.emit,
clientRef,
});
});

@@ -113,142 +116,148 @@ useEffect(() => {

}, [store, name]);
});
};
const RootClientAccessorResource = resource(useRootClientAccessorResource);
const useNoOpRootClientsAccessorsResource = () => {
return useMemo(
() => ({
clients: [] as AssistantClientAccessor<ClientNames>[],
subscribe: undefined,
on: undefined,
}),
[],
);
};
const NoOpRootClientsAccessorsResource = resource(
function NoOpRootClientsAccessorsResource() {
return useMemo(
() => ({
clients: [] as AssistantClientAccessor<ClientNames>[],
subscribe: undefined,
on: undefined,
}),
[],
);
},
useNoOpRootClientsAccessorsResource,
);
const RootClientsAccessorsResource = resource(
function RootClientsAccessorsResource({
clients: inputClients,
clientRef,
}: {
clients: RootClients;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
}) {
const notifications = useResource(NotificationManager());
const useRootClientsAccessorsResource = ({
clients: inputClients,
clientRef,
}: {
clients: RootClients;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
}) => {
const notifications = useResource(NotificationManager());
useEffect(
() => clientRef.parent.subscribe(notifications.notifySubscribers),
[clientRef, notifications],
);
useEffect(
() => clientRef.parent.subscribe(notifications.notifySubscribers),
[clientRef, notifications],
);
const results = useShallowMemoArray(
useResources(
() =>
Object.keys(inputClients).map((key) =>
withKey(
key,
RootClientAccessorResource({
element: inputClients[key as keyof typeof inputClients]!,
notifications,
clientRef,
name: key as keyof typeof inputClients,
}),
),
const results = useShallowMemoArray(
useResources(
() =>
Object.keys(inputClients).map((key) =>
withKey(
key,
RootClientAccessorResource({
element: inputClients[key as keyof typeof inputClients]!,
notifications,
clientRef,
name: key as keyof typeof inputClients,
}),
),
[inputClients, notifications, clientRef],
),
);
),
[inputClients, notifications, clientRef],
),
);
return useMemo(() => {
return {
clients: results,
subscribe: notifications.subscribe,
on: function <TEvent extends AssistantEventName>(
this: AssistantClient,
selector: AssistantEventSelector<TEvent>,
callback: AssistantEventCallback<TEvent>,
) {
if (!this) {
return useMemo(() => {
return {
clients: results,
subscribe: notifications.subscribe,
on: function <TEvent extends AssistantEventName>(
this: AssistantClient,
selector: AssistantEventSelector<TEvent>,
callback: AssistantEventCallback<TEvent>,
) {
if (!this) {
throw new Error(
"const { on } = useAui() is not supported. Use aui.on() instead.",
);
}
const { scope, event } = normalizeEventSelector(selector);
if (scope !== "*") {
const source = this[scope as ClientNames].source;
if (source === null) {
throw new Error(
"const { on } = useAui() is not supported. Use aui.on() instead.",
`Scope "${scope}" is not available. Use { scope: "*", event: "${event}" } to listen globally.`,
);
}
}
const { scope, event } = normalizeEventSelector(selector);
const localUnsub = notifications.on(event, (payload, clientStack) => {
if (scope === "*") {
callback(payload);
return;
}
if (scope !== "*") {
const source = this[scope as ClientNames].source;
if (source === null) {
throw new Error(
`Scope "${scope}" is not available. Use { scope: "*", event: "${event}" } to listen globally.`,
);
}
const scopeClient = this[scope as ClientNames]();
const index = getClientIndex(scopeClient);
if (scopeClient === clientStack[index]) {
callback(payload);
}
});
if (
scope !== "*" &&
clientRef.parent[scope as ClientNames].source === null
)
return localUnsub;
const localUnsub = notifications.on(event, (payload, clientStack) => {
if (scope === "*") {
callback(payload);
return;
}
const parentUnsub = clientRef.parent.on(selector, callback);
const scopeClient = this[scope as ClientNames]();
const index = getClientIndex(scopeClient);
if (scopeClient === clientStack[index]) {
callback(payload);
}
});
if (
scope !== "*" &&
clientRef.parent[scope as ClientNames].source === null
)
return localUnsub;
return () => {
localUnsub();
parentUnsub();
};
},
};
}, [results, notifications, clientRef]);
};
const parentUnsub = clientRef.parent.on(selector, callback);
const RootClientsAccessorsResource = resource(useRootClientsAccessorsResource);
return () => {
localUnsub();
parentUnsub();
};
},
};
}, [results, notifications, clientRef]);
},
);
const useDerivedClientAccessorResource = <K extends ClientNames>({
element,
clientRef,
name,
}: {
element: DerivedElement<K>;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
name: K;
}) => {
// Track the latest props on a ref updated in render. The fiber is
// keyed on the scope's meta by DerivedClientsAccessorsResource, so
// source/query are stable for this fiber's lifetime and the only
// value that can change between renders for the same fiber is the
// identity of the `get` closure. Routing reads through the ref so
// they take effect without a one-commit lag.
const propsRef = useRef(element.args[0]);
propsRef.current = element.args[0];
return useMemo(() => {
const clientFunction = () => propsRef.current.get(clientRef.current!);
Object.defineProperties(clientFunction, {
source: {
value: propsRef.current.source,
},
query: {
value: propsRef.current.query,
},
name: {
value: name,
configurable: true,
},
});
return clientFunction as AssistantClientAccessor<K>;
}, [clientRef, name]);
};
const DerivedClientAccessorResource = resource(
function DerivedClientAccessorResource<K extends ClientNames>({
element,
clientRef,
name,
}: {
element: DerivedElement<K>;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
name: K;
}) {
// Track the latest props on a ref updated in render. The fiber is
// keyed on the scope's meta by DerivedClientsAccessorsResource, so
// source/query are stable for this fiber's lifetime and the only
// value that can change between renders for the same fiber is the
// identity of the `get` closure. Routing reads through the ref so
// they take effect without a one-commit lag.
const propsRef = useRef(element.props);
propsRef.current = element.props;
return useMemo(() => {
const clientFunction = () => propsRef.current.get(clientRef.current!);
Object.defineProperties(clientFunction, {
source: {
value: propsRef.current.source,
},
query: {
value: propsRef.current.query,
},
name: {
value: name,
configurable: true,
},
});
return clientFunction as AssistantClientAccessor<K>;
}, [clientRef, name]);
},
useDerivedClientAccessorResource,
);

@@ -276,30 +285,28 @@

const DerivedClientsAccessorsResource = resource(
function DerivedClientsAccessorsResource({
clients,
clientRef,
}: {
clients: DerivedClients;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
}) {
return useShallowMemoArray(
useResources(
() =>
Object.keys(clients).map((key) => {
const name = key as keyof typeof clients;
const element = clients[name]!;
return withKey(
serializeMeta(name, element.props),
DerivedClientAccessorResource({
element,
clientRef,
name,
}),
);
}),
[clients, clientRef],
),
);
},
);
const useDerivedClientsAccessorsResource = ({
clients,
clientRef,
}: {
clients: DerivedClients;
clientRef: { parent: AssistantClient; current: AssistantClient | null };
}) => {
return useShallowMemoArray(
useResources(
() =>
Object.keys(clients).map((key) => {
const name = key as keyof typeof clients;
const element = clients[name]!;
return withKey(
serializeMeta(name, element.args[0]),
DerivedClientAccessorResource({
element,
clientRef,
name,
}),
);
}),
[clients, clientRef],
),
);
};

@@ -309,63 +316,73 @@ /**

*/
export const AssistantClientResource = resource(
function AssistantClientResource({
parent,
clients,
}: {
parent: AssistantClient;
clients: useAui.Props;
}): AssistantClient {
const { rootClients, derivedClients } = useSplitClients(clients, parent);
const useAssistantClient = ({
parent,
clients,
}: {
parent: AssistantClient;
clients: useAui.Props;
}): AssistantClient => {
const { rootClients, derivedClients } = useSplitClients(clients, parent);
const clientRef = useRef({
parent: parent,
current: null as AssistantClient | null,
}).current;
const clientRef = useRef({
parent: parent,
current: null as AssistantClient | null,
}).current;
useEffect(() => {
clientRef.current = client;
useEffect(() => {
clientRef.current = client;
});
const rootFields = useResource(
Object.keys(rootClients).length > 0
? RootClientsAccessorsResource({ clients: rootClients, clientRef })
: NoOpRootClientsAccessorsResource(),
);
const derivedFields = useDerivedClientsAccessorsResource({
clients: derivedClients,
clientRef,
});
const client = useMemo(() => {
// Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message
const proto =
parent === DefaultAssistantClient ? createRootAssistantClient() : parent;
const client = Object.create(proto) as AssistantClient;
Object.assign(client, {
subscribe: rootFields.subscribe ?? parent.subscribe,
on: rootFields.on ?? parent.on,
[PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),
});
const rootFields = useResource(
Object.keys(rootClients).length > 0
? RootClientsAccessorsResource({ clients: rootClients, clientRef })
: NoOpRootClientsAccessorsResource(),
);
for (const field of rootFields.clients) {
(client as any)[field.name] = field;
}
for (const field of derivedFields) {
(client as any)[field.name] = field;
}
const derivedFields = useResource(
DerivedClientsAccessorsResource({ clients: derivedClients, clientRef }),
);
return client;
}, [parent, rootFields, derivedFields]);
const client = useMemo(() => {
// Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message
const proto =
parent === DefaultAssistantClient
? createRootAssistantClient()
: parent;
if (clientRef.current === null) {
clientRef.current = client;
}
const client = Object.create(proto) as AssistantClient;
Object.assign(client, {
subscribe: rootFields.subscribe ?? parent.subscribe,
on: rootFields.on ?? parent.on,
[PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),
});
return client;
};
for (const field of rootFields.clients) {
(client as any)[field.name] = field;
}
for (const field of derivedFields) {
(client as any)[field.name] = field;
}
const useHostedAssistantClient = (props: {
parent: AssistantClient;
clients: useAui.Props;
}): AssistantClient => {
const { value: client, effects } = useTapHost(function AssistantClientHost() {
return useAssistantClient(props);
});
return client;
}, [parent, rootFields, derivedFields]);
(client as Record<symbol, unknown>)[AUI_USE_EFFECTS_SYMBOL] = effects;
if (clientRef.current === null) {
clientRef.current = client;
}
return client;
};
return client;
},
);
export namespace useAui {

@@ -450,8 +467,6 @@ export type Props = {

if (clients) {
return useResource(
AssistantClientResource({
parent: parent ?? DefaultAssistantClient,
clients,
}),
);
return useHostedAssistantClient({
parent: parent ?? DefaultAssistantClient,
clients,
});
}

@@ -458,0 +473,0 @@ if (parent === null)

@@ -120,4 +120,4 @@ import { useMemo, useState } from "react";

getKey: (data: TData) => string;
resource: ContravariantResource<TMethods, ResourceProps<TData>>;
resource: ContravariantResource<TMethods, [ResourceProps<TData>]>;
};
}
import { useMemo } from "react";
import {
useResource,
useResources,
type ResourceElement,
} from "@assistant-ui/tap";
import { useResources, withKey, type ResourceElement } from "@assistant-ui/tap";
import type { ClientMethods } from "./types/client";
import { ClientResource } from "./useClientResource";
import { wrapperResource } from "./wrapperResource";

@@ -17,14 +12,8 @@ type InferClientState<TMethods> = TMethods extends {

const ClientResourceWithKey = wrapperResource(
<TMethods extends ClientMethods>(el: ResourceElement<TMethods>) => {
if (el.key === undefined) {
throw new Error("useClientResource: Element has no key");
}
return useResource(ClientResource(el)) as {
methods: TMethods;
state: InferClientState<TMethods>;
key: string | number;
};
},
);
const getElementKey = (el: ResourceElement<unknown>) => {
if (el.key === undefined) {
throw new Error("useClientLookup: Element has no key");
}
return el.key;
};

@@ -39,3 +28,4 @@ export function useClientLookup<TMethods extends ClientMethods>(

const resources = useResources(
() => getElements().map((el) => ClientResourceWithKey(el)),
() =>
getElements().map((el) => withKey(getElementKey(el), ClientResource(el))),
// oxlint-disable-next-line react/exhaustive-deps -- caller-supplied deps array

@@ -51,3 +41,3 @@ getElementsDeps,

(acc, resource, index) => {
acc[resource.key] = index;
acc[resource.key!] = index;
return acc;

@@ -54,0 +44,0 @@ },

import { useEffect, useMemo, useRef } from "react";
import { useResource, type ResourceElement } from "@assistant-ui/tap";
import { resource, useResource, type ResourceElement } from "@assistant-ui/tap";
import type { ClientMethods } from "./types/client";

@@ -13,3 +13,2 @@ import {

} from "./utils/BaseProxyHandler";
import { wrapperResource } from "./wrapperResource";

@@ -124,45 +123,2 @@ /**

/**
* Resource that wraps a plain resource element to create a stable client proxy.
*
* Takes a ResourceElement that returns methods (with optional getState()) and
* wraps it to produce a stable client proxy. This adds the client to the
* client stack, enabling event scoping.
*
* @internal
*/
export const ClientResource = wrapperResource(
<TMethods extends ClientMethods>(
element: ResourceElement<TMethods>,
): {
methods: TMethods;
state: unknown;
key: string | number | undefined;
} => {
const valueRef = useRef(null as unknown as TMethods);
const index = useClientStack().length;
const methods = useMemo(
() =>
new Proxy<TMethods>(
{} as TMethods,
new ClientProxyHandler(valueRef, index),
),
[index],
);
const value = useWithClientStack(methods, () => useResource(element));
if (!valueRef.current) {
valueRef.current = value;
}
useEffect(() => {
valueRef.current = value;
});
const state = (value as any).getState?.();
return { methods, state, key: element.key };
},
);
type InferClientState<TMethods> = TMethods extends {

@@ -181,7 +137,30 @@ getState: () => infer S;

} => {
return useResource(ClientResource(element)) as {
state: InferClientState<TMethods>;
methods: TMethods;
key: string | number | undefined;
};
const valueRef = useRef(null as unknown as TMethods);
const index = useClientStack().length;
const methods = useMemo(
() =>
new Proxy<TMethods>(
{} as TMethods,
new ClientProxyHandler(valueRef, index),
),
[index],
);
const value = useWithClientStack(methods, function WithClientStack() {
return useResource(element);
});
if (!valueRef.current) {
valueRef.current = value;
}
useEffect(() => {
valueRef.current = value;
});
const state = (value as any).getState?.();
return { methods, state, key: element.key };
};
export const ClientResource = resource(useClientResource);

@@ -29,92 +29,89 @@ import { useMemo } from "react";

export const NotificationManager = resource(
function NotificationManager(): NotificationManager {
return useMemo(() => {
const listeners = new Map<string, Set<InternalCallback>>();
const wildcardListeners = new Set<InternalCallback>();
const subscribers = new Set<() => void>();
const useNotificationManager = (): NotificationManager => {
return useMemo(() => {
const listeners = new Map<string, Set<InternalCallback>>();
const wildcardListeners = new Set<InternalCallback>();
const subscribers = new Set<() => void>();
return {
on(event, callback) {
const cb = callback as InternalCallback;
if (event === "*") {
wildcardListeners.add(cb);
return () => wildcardListeners.delete(cb);
}
return {
on(event, callback) {
const cb = callback as InternalCallback;
if (event === "*") {
wildcardListeners.add(cb);
return () => wildcardListeners.delete(cb);
}
let set = listeners.get(event);
if (!set) {
set = new Set();
listeners.set(event, set);
}
set.add(cb);
let set = listeners.get(event);
if (!set) {
set = new Set();
listeners.set(event, set);
}
set.add(cb);
return () => {
set!.delete(cb);
if (set!.size === 0) listeners.delete(event);
};
},
return () => {
set!.delete(cb);
if (set!.size === 0) listeners.delete(event);
};
},
emit(event, payload, clientStack) {
const eventListeners = listeners.get(event);
if (!eventListeners && wildcardListeners.size === 0) return;
emit(event, payload, clientStack) {
const eventListeners = listeners.get(event);
if (!eventListeners && wildcardListeners.size === 0) return;
queueMicrotask(() => {
const errors = [];
if (eventListeners) {
for (const cb of eventListeners) {
try {
cb(payload, clientStack);
} catch (e) {
errors.push(e);
}
queueMicrotask(() => {
const errors = [];
if (eventListeners) {
for (const cb of eventListeners) {
try {
cb(payload, clientStack);
} catch (e) {
errors.push(e);
}
}
if (wildcardListeners.size > 0) {
const wrapped = { event, payload };
for (const cb of wildcardListeners) {
try {
cb(wrapped, clientStack);
} catch (e) {
errors.push(e);
}
}
if (wildcardListeners.size > 0) {
const wrapped = { event, payload };
for (const cb of wildcardListeners) {
try {
cb(wrapped, clientStack);
} catch (e) {
errors.push(e);
}
}
}
if (errors.length > 0) {
if (errors.length === 1) {
throw errors[0];
} else {
for (const error of errors) {
console.error(error);
}
throw new AggregateError(
errors,
"Errors occurred during event emission",
);
if (errors.length > 0) {
if (errors.length === 1) {
throw errors[0];
} else {
for (const error of errors) {
console.error(error);
}
throw new AggregateError(
errors,
"Errors occurred during event emission",
);
}
});
},
}
});
},
subscribe(callback) {
subscribers.add(callback);
return () => subscribers.delete(callback);
},
subscribe(callback) {
subscribers.add(callback);
return () => subscribers.delete(callback);
},
notifySubscribers() {
for (const cb of subscribers) {
try {
cb();
} catch (e) {
console.error(
"NotificationManager: subscriber callback error",
e,
);
}
notifySubscribers() {
for (const cb of subscribers) {
try {
cb();
} catch (e) {
console.error("NotificationManager: subscriber callback error", e);
}
},
};
}, []);
},
);
}
},
};
}, []);
};
export const NotificationManager = resource(useNotificationManager);
import type React from "react";
import { createContext, useContext } from "react";
import { createContext, useContext, useEffect } from "react";
import type { AssistantClient, AssistantClientAccessor } from "../types/client";

@@ -83,2 +83,25 @@ import {

/**
* Carries the tap host's effects callback on the client so AuiProvider can
* mount the host's commit ahead of its children's effects.
*/
export const AUI_USE_EFFECTS_SYMBOL = Symbol("assistant-ui.store.useEffects");
const NOOP_EFFECT = () => {};
const getTapEffects = (client: AssistantClient): (() => void) => {
return (
(client as Record<symbol, never>)[AUI_USE_EFFECTS_SYMBOL] ?? NOOP_EFFECT
);
};
const UseTapEffects = () => {
"use no memo";
const aui = useAssistantContextValue();
// oxlint-disable-next-line react-hooks/exhaustive-deps
useEffect(getTapEffects(aui));
return null;
};
export const useAssistantContextValue = (): AssistantClient => {

@@ -118,4 +141,7 @@ return useContext(AssistantContext);

}): React.ReactElement => {
// The <UseTapEffects /> element must be created fresh each render
"use no memo";
return (
<AssistantContext.Provider value={value}>
<UseTapEffects />
{children}

@@ -122,0 +148,0 @@ </AssistantContext.Provider>

@@ -1,2 +0,2 @@

import { Derived, type DerivedElement } from "../Derived";
import { useDerived, type DerivedElement } from "../Derived";
import type {

@@ -10,3 +10,2 @@ AssistantClient,

import { useMemo } from "react";
import { type ResourceElement } from "@assistant-ui/tap";

@@ -36,9 +35,7 @@ export type RootClients = Partial<

for (const clientElement of Object.values(scopes)) {
if (clientElement.type === (Derived as unknown)) continue;
if (visited.has(clientElement.type)) continue;
visited.add(clientElement.type);
if (clientElement.hook === (useDerived as unknown)) continue;
if (visited.has(clientElement.hook)) continue;
visited.add(clientElement.hook);
const transform = getTransformScopes(
clientElement.type as (props: any) => ResourceElement<any>,
);
const transform = getTransformScopes(clientElement.hook);
if (transform) {

@@ -60,3 +57,3 @@ transform(scopes, baseClient);

][]) {
if (clientElement.type === (Derived as unknown)) {
if (clientElement.hook === (useDerived as unknown)) {
derivedClients[key] = clientElement as DerivedElement<ClientNames>;

@@ -63,0 +60,0 @@ } else {

import { Resource, ResourceElement } from "@assistant-ui/tap";
//#region src/wrapperResource.d.ts
declare const wrapperResource: <R, P>(fn: (props: ResourceElement<P>) => R) => Resource<R, ResourceElement<P>>;
//#endregion
export { wrapperResource };
//# sourceMappingURL=wrapperResource.d.ts.map
{"version":3,"file":"wrapperResource.d.ts","names":[],"sources":["../src/wrapperResource.ts"],"mappings":";;;cAOa,eAAA,SACX,EAAA,GAAK,KAAA,EAAO,eAAA,CAAgB,CAAA,MAAO,CAAA,KAClC,QAAA,CAAS,CAAA,EAAG,eAAA,CAAgB,CAAA"}
import { resource, withKey } from "@assistant-ui/tap";
//#region src/wrapperResource.ts
const wrapperResource = (fn) => {
const res = resource(fn);
return (props) => {
const el = res(props);
if (props.key === void 0) return el;
return withKey(props.key, el);
};
};
//#endregion
export { wrapperResource };
//# sourceMappingURL=wrapperResource.js.map
{"version":3,"file":"wrapperResource.js","names":[],"sources":["../src/wrapperResource.ts"],"sourcesContent":["import {\n type ResourceElement,\n type Resource,\n resource,\n withKey,\n} from \"@assistant-ui/tap\";\n\nexport const wrapperResource = <R, P>(\n fn: (props: ResourceElement<P>) => R,\n): Resource<R, ResourceElement<P>> => {\n const res = resource(fn);\n return (props: ResourceElement<P>) => {\n const el = res(props);\n if (props.key === undefined) return el;\n return withKey(props.key, el);\n };\n};\n"],"mappings":";;AAOA,MAAa,mBACX,OACoC;CACpC,MAAM,MAAM,SAAS,EAAE;CACvB,QAAQ,UAA8B;EACpC,MAAM,KAAK,IAAI,KAAK;EACpB,IAAI,MAAM,QAAQ,KAAA,GAAW,OAAO;EACpC,OAAO,QAAQ,MAAM,KAAK,EAAE;CAC9B;AACF"}
import {
type ResourceElement,
type Resource,
resource,
withKey,
} from "@assistant-ui/tap";
export const wrapperResource = <R, P>(
fn: (props: ResourceElement<P>) => R,
): Resource<R, ResourceElement<P>> => {
const res = resource(fn);
return (props: ResourceElement<P>) => {
const el = res(props);
if (props.key === undefined) return el;
return withKey(props.key, el);
};
};