@parlor/client 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAC;AAC3C,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,QAAQ,EACR,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3E,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,KAAK,eAAe,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EACL,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,eAAe,EACf,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAC;AAC3C,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,QAAQ,EACR,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3E,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,KAAK,eAAe,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EACL,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,eAAe,EACf,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export * as Chat from "./agent-ui/chat.js";
2
2
  export { useChat } from "./chat/use-chat.js";
3
+ export { useStreamingText } from "./chat/use-streaming-text.js";
3
4
  export { useDeviceSetup } from "./chat/use-device-setup.js";
4
5
  export { useDevices } from "./use-devices.js";
5
6
  export { useLinkDevice } from "./use-link-device.js";
@@ -7,6 +8,7 @@ export { useAgentActivity } from "./agent-ui/use-agent-activity.js";
7
8
  export { useAgentConfirmations } from "./agent-ui/use-agent-confirmations.js";
8
9
  export { useAgentView } from "./agent-ui/use-agent-view.js";
9
10
  export { actionQueryOptions, ensureActionQueryData, } from "./action-query.js";
11
+ export { callAndRefresh } from "./write-refresh.js";
10
12
  export { useActionMutation, useActionQuery, useActionSuspenseQuery, } from "./hooks.js";
11
13
  export { FrameworkProvider, useActionClient, useSession, } from "./provider.js";
12
14
  export { useCapability } from "./use-capability.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAC;AAqB3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAA0B,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAwB,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAwB,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAEL,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EAEjB,eAAe,EACf,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAwB,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC","sourcesContent":["export type {\n AgentActivity,\n AgentActivityKind,\n AgentOutcome,\n AgentConfirmation,\n} from \"@parlor/agent-ui/client\";\nexport type { AgentActivityState } from \"./agent-ui/activity-state.js\";\nexport * as Chat from \"./agent-ui/chat.js\";\nexport type {\n ChatAskChoiceProps,\n ChatAskFormProps,\n ChatAskProps,\n} from \"./chat/chat-ask.js\";\nexport type { ChatRootProps } from \"./chat/chat-root.js\";\nexport type { ChatThreadProps } from \"./chat/chat-thread.js\";\nexport type {\n AgentChoice,\n AgentChoiceOption,\n ChatCommands,\n ChatState,\n ChatStatus,\n ChatUnavailable,\n ChatWait,\n ConnectOption,\n DeviceSetup,\n DeviceSetupCommands,\n LinkState,\n} from \"./chat/runtime.js\";\nexport { useChat } from \"./chat/use-chat.js\";\nexport { useDeviceSetup } from \"./chat/use-device-setup.js\";\nexport { type RemoveDeviceState, useDevices } from \"./use-devices.js\";\nexport { type LinkDeviceState, useLinkDevice } from \"./use-link-device.js\";\nexport type { ChatItem } from \"@parlor/chat\";\nexport { useAgentActivity } from \"./agent-ui/use-agent-activity.js\";\nexport { useAgentConfirmations } from \"./agent-ui/use-agent-confirmations.js\";\nexport { type AgentViewHandle, useAgentView } from \"./agent-ui/use-agent-view.js\";\nexport {\n type ActionQueryContext,\n actionQueryOptions,\n ensureActionQueryData,\n} from \"./action-query.js\";\nexport {\n type ActionMutationOptions,\n type ActionQueryOptions,\n type ActionSuspenseQueryOptions,\n useActionMutation,\n useActionQuery,\n useActionSuspenseQuery,\n} from \"./hooks.js\";\nexport {\n FrameworkProvider,\n type FrameworkProviderProps,\n useActionClient,\n useSession,\n} from \"./provider.js\";\nexport { type CapabilityState, useCapability } from \"./use-capability.js\";\nexport { invalidateForEvents, ReadTagRegistry } from \"./sync.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAC;AAsB3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAA0B,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAwB,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAwB,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAEL,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAIL,iBAAiB,EACjB,cAAc,EACd,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EAEjB,eAAe,EACf,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAwB,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC","sourcesContent":["export type {\n AgentActivity,\n AgentActivityKind,\n AgentOutcome,\n AgentConfirmation,\n} from \"@parlor/agent-ui/client\";\nexport type { AgentActivityState } from \"./agent-ui/activity-state.js\";\nexport * as Chat from \"./agent-ui/chat.js\";\nexport type {\n ChatAskChoiceProps,\n ChatAskFormProps,\n ChatAskProps,\n} from \"./chat/chat-ask.js\";\nexport type { ChatRootProps } from \"./chat/chat-root.js\";\nexport type { ChatThreadProps } from \"./chat/chat-thread.js\";\nexport type {\n AgentChoice,\n AgentChoiceOption,\n AgentsCheck,\n ChatCommands,\n ChatState,\n ChatStatus,\n ChatUnavailable,\n ChatWait,\n ConnectOption,\n DeviceSetup,\n DeviceSetupCommands,\n LinkState,\n} from \"./chat/runtime.js\";\nexport { useChat } from \"./chat/use-chat.js\";\nexport { useStreamingText } from \"./chat/use-streaming-text.js\";\nexport { useDeviceSetup } from \"./chat/use-device-setup.js\";\nexport { type RemoveDeviceState, useDevices } from \"./use-devices.js\";\nexport { type LinkDeviceState, useLinkDevice } from \"./use-link-device.js\";\nexport type { ChatItem } from \"@parlor/chat\";\nexport { useAgentActivity } from \"./agent-ui/use-agent-activity.js\";\nexport { useAgentConfirmations } from \"./agent-ui/use-agent-confirmations.js\";\nexport { type AgentViewHandle, useAgentView } from \"./agent-ui/use-agent-view.js\";\nexport {\n type ActionQueryContext,\n actionQueryOptions,\n ensureActionQueryData,\n} from \"./action-query.js\";\nexport { callAndRefresh } from \"./write-refresh.js\";\nexport {\n type ActionMutationOptions,\n type ActionQueryOptions,\n type ActionSuspenseQueryOptions,\n useActionMutation,\n useActionQuery,\n useActionSuspenseQuery,\n} from \"./hooks.js\";\nexport {\n FrameworkProvider,\n type FrameworkProviderProps,\n useActionClient,\n useSession,\n} from \"./provider.js\";\nexport { type CapabilityState, useCapability } from \"./use-capability.js\";\nexport { invalidateForEvents, ReadTagRegistry } from \"./sync.js\";\n"]}
@@ -0,0 +1,27 @@
1
+ import { type ActionInput, type ActionOutput, type ReadRequest } from "@parlor/core";
2
+ import type { Query, QueryClient } from "@tanstack/react-query";
3
+ import type { ActionEnvelope, CallOptions } from "../action-client.js";
4
+ import type { RegisteredActions } from "../register.js";
5
+ import type { ActionQueryContext } from "./action-query.js";
6
+ export interface ShownRead {
7
+ readonly query: Query;
8
+ readonly request: ReadRequest;
9
+ }
10
+ /** The action queries the page shows, to name on a write so it answers with them fresh. */
11
+ export declare function shownReads(queryClient: QueryClient): ShownRead[];
12
+ /**
13
+ * Brings the cache up to date after a write. The reads the server ran again go straight in;
14
+ * a shown read it could not run, or one whose reads are unknown here, is fetched again, and
15
+ * this waits for it; data nothing shows that the write changed is marked out of date. A
16
+ * server that did not say what the write changed gets every action query fetched again.
17
+ */
18
+ export declare function applyWrite(queryClient: QueryClient, shown: readonly ShownRead[], envelope: ActionEnvelope<unknown>): Promise<void>;
19
+ type Name = keyof RegisteredActions & string;
20
+ /**
21
+ * Calls an action and brings the page up to date with what it changed, in the same round
22
+ * trip: the write answers with the reads the page shows that it touched. What
23
+ * `useActionMutation` runs; for a flow of several calls behind one button, call each with it.
24
+ */
25
+ export declare function callAndRefresh<K extends Name>({ client, queryClient }: ActionQueryContext, name: K, input: ActionInput<RegisteredActions[K]>, options?: Omit<CallOptions, "refresh">): Promise<ActionOutput<RegisteredActions[K]>>;
26
+ export {};
27
+ //# sourceMappingURL=write-refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-refresh.d.ts","sourceRoot":"","sources":["../../src/react/write-refresh.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAEjB,KAAK,WAAW,EAEjB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,2FAA2F;AAC3F,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,EAAE,CAMhE;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAsDf;AAED,KAAK,IAAI,GAAG,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAE7C;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,CAAC,SAAS,IAAI,EACjD,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,kBAAkB,EAC3C,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EACxC,OAAO,GAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAM,GACzC,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAU7C"}
@@ -0,0 +1,80 @@
1
+ import { MAX_REFRESHED_READS, tagsOverlap, } from "@parlor/core";
2
+ import { ACTION_QUERY_PREFIX } from "../query-keys.js";
3
+ import { readTagsOf } from "./sync.js";
4
+ /** The action queries the page shows, to name on a write so it answers with them fresh. */
5
+ export function shownReads(queryClient) {
6
+ return queryClient
7
+ .getQueryCache()
8
+ .findAll({ queryKey: ACTION_QUERY_PREFIX, type: "active" })
9
+ .slice(0, MAX_REFRESHED_READS)
10
+ .map((query) => ({ query, request: [String(query.queryKey[2]), query.queryKey[3]] }));
11
+ }
12
+ /**
13
+ * Brings the cache up to date after a write. The reads the server ran again go straight in;
14
+ * a shown read it could not run, or one whose reads are unknown here, is fetched again, and
15
+ * this waits for it; data nothing shows that the write changed is marked out of date. A
16
+ * server that did not say what the write changed gets every action query fetched again.
17
+ */
18
+ export async function applyWrite(queryClient, shown, envelope) {
19
+ const { writes, refreshed } = envelope;
20
+ if (!writes || !refreshed) {
21
+ await queryClient.invalidateQueries({ queryKey: ACTION_QUERY_PREFIX });
22
+ return;
23
+ }
24
+ const registry = readTagsOf(queryClient);
25
+ const changed = (query) => {
26
+ const tags = registry.tagsFor(query.queryHash);
27
+ return (tags === undefined ||
28
+ tags.some((read) => writes.some((write) => tagsOverlap(read, write))));
29
+ };
30
+ const refetch = [];
31
+ await Promise.all(shown.map(async ({ query }, index) => {
32
+ const fresh = refreshed[index];
33
+ // The server judged it untouched by the write.
34
+ if (fresh === null)
35
+ return;
36
+ if (fresh === undefined) {
37
+ if (changed(query))
38
+ refetch.push(query);
39
+ return;
40
+ }
41
+ if ("error" in fresh) {
42
+ refetch.push(query);
43
+ return;
44
+ }
45
+ // A fetch that started before the write would land older data over it.
46
+ if (query.state.fetchStatus === "fetching") {
47
+ await queryClient.cancelQueries({ queryKey: query.queryKey, exact: true });
48
+ }
49
+ registry.record(query.queryHash, fresh.tags, fresh.cursor);
50
+ queryClient.setQueryData(query.queryKey, fresh.data);
51
+ }));
52
+ const named = new Set(shown.map(({ query }) => query.queryHash));
53
+ for (const query of queryClient
54
+ .getQueryCache()
55
+ .findAll({ queryKey: ACTION_QUERY_PREFIX })) {
56
+ if (named.has(query.queryHash) || !changed(query))
57
+ continue;
58
+ void queryClient.invalidateQueries({
59
+ queryKey: query.queryKey,
60
+ exact: true,
61
+ refetchType: "none",
62
+ });
63
+ }
64
+ await Promise.all(refetch.map((query) => queryClient.invalidateQueries({ queryKey: query.queryKey, exact: true })));
65
+ }
66
+ /**
67
+ * Calls an action and brings the page up to date with what it changed, in the same round
68
+ * trip: the write answers with the reads the page shows that it touched. What
69
+ * `useActionMutation` runs; for a flow of several calls behind one button, call each with it.
70
+ */
71
+ export async function callAndRefresh({ client, queryClient }, name, input, options = {}) {
72
+ const shown = shownReads(queryClient);
73
+ const envelope = await client.invoke(name, input, {
74
+ ...options,
75
+ refresh: shown.map(({ request }) => request),
76
+ });
77
+ await applyWrite(queryClient, shown, envelope).catch(() => queryClient.invalidateQueries({ queryKey: ACTION_QUERY_PREFIX }));
78
+ return envelope.data;
79
+ }
80
+ //# sourceMappingURL=write-refresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-refresh.js","sourceRoot":"","sources":["../../src/react/write-refresh.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ActionInput,\n type ActionOutput,\n MAX_REFRESHED_READS,\n type ReadRequest,\n tagsOverlap,\n} from \"@parlor/core\";\nimport type { Query, QueryClient } from \"@tanstack/react-query\";\n\nimport type { ActionEnvelope, CallOptions } from \"../action-client.js\";\nimport { ACTION_QUERY_PREFIX } from \"../query-keys.js\";\nimport type { RegisteredActions } from \"../register.js\";\nimport type { ActionQueryContext } from \"./action-query.js\";\nimport { readTagsOf } from \"./sync.js\";\n\nexport interface ShownRead {\n readonly query: Query;\n readonly request: ReadRequest;\n}\n\n/** The action queries the page shows, to name on a write so it answers with them fresh. */\nexport function shownReads(queryClient: QueryClient): ShownRead[] {\n return queryClient\n .getQueryCache()\n .findAll({ queryKey: ACTION_QUERY_PREFIX, type: \"active\" })\n .slice(0, MAX_REFRESHED_READS)\n .map((query) => ({ query, request: [String(query.queryKey[2]), query.queryKey[3]] }));\n}\n\n/**\n * Brings the cache up to date after a write. The reads the server ran again go straight in;\n * a shown read it could not run, or one whose reads are unknown here, is fetched again, and\n * this waits for it; data nothing shows that the write changed is marked out of date. A\n * server that did not say what the write changed gets every action query fetched again.\n */\nexport async function applyWrite(\n queryClient: QueryClient,\n shown: readonly ShownRead[],\n envelope: ActionEnvelope<unknown>,\n): Promise<void> {\n const { writes, refreshed } = envelope;\n if (!writes || !refreshed) {\n await queryClient.invalidateQueries({ queryKey: ACTION_QUERY_PREFIX });\n return;\n }\n const registry = readTagsOf(queryClient);\n const changed = (query: Query) => {\n const tags = registry.tagsFor(query.queryHash);\n return (\n tags === undefined ||\n tags.some((read) => writes.some((write) => tagsOverlap(read, write)))\n );\n };\n\n const refetch: Query[] = [];\n await Promise.all(\n shown.map(async ({ query }, index) => {\n const fresh = refreshed[index];\n // The server judged it untouched by the write.\n if (fresh === null) return;\n if (fresh === undefined) {\n if (changed(query)) refetch.push(query);\n return;\n }\n if (\"error\" in fresh) {\n refetch.push(query);\n return;\n }\n // A fetch that started before the write would land older data over it.\n if (query.state.fetchStatus === \"fetching\") {\n await queryClient.cancelQueries({ queryKey: query.queryKey, exact: true });\n }\n registry.record(query.queryHash, fresh.tags, fresh.cursor);\n queryClient.setQueryData(query.queryKey, fresh.data);\n }),\n );\n\n const named = new Set(shown.map(({ query }) => query.queryHash));\n for (const query of queryClient\n .getQueryCache()\n .findAll({ queryKey: ACTION_QUERY_PREFIX })) {\n if (named.has(query.queryHash) || !changed(query)) continue;\n void queryClient.invalidateQueries({\n queryKey: query.queryKey,\n exact: true,\n refetchType: \"none\",\n });\n }\n await Promise.all(\n refetch.map((query) =>\n queryClient.invalidateQueries({ queryKey: query.queryKey, exact: true }),\n ),\n );\n}\n\ntype Name = keyof RegisteredActions & string;\n\n/**\n * Calls an action and brings the page up to date with what it changed, in the same round\n * trip: the write answers with the reads the page shows that it touched. What\n * `useActionMutation` runs; for a flow of several calls behind one button, call each with it.\n */\nexport async function callAndRefresh<K extends Name>(\n { client, queryClient }: ActionQueryContext,\n name: K,\n input: ActionInput<RegisteredActions[K]>,\n options: Omit<CallOptions, \"refresh\"> = {},\n): Promise<ActionOutput<RegisteredActions[K]>> {\n const shown = shownReads(queryClient);\n const envelope = await client.invoke(name, input, {\n ...options,\n refresh: shown.map(({ request }) => request),\n });\n await applyWrite(queryClient, shown, envelope).catch(() =>\n queryClient.invalidateQueries({ queryKey: ACTION_QUERY_PREFIX }),\n );\n return envelope.data;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parlor/client",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "homepage": "https://cychien.github.io/parlor",
5
5
  "bugs": "https://github.com/cychien/parlor/issues",
6
6
  "license": "MIT",
@@ -33,11 +33,11 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@parlor/agent-ui": "0.3.0",
37
- "@parlor/core": "0.3.0",
38
- "@parlor/chat": "0.3.0",
39
- "@parlor/sync": "0.3.0",
40
- "@parlor/capabilities": "0.3.0"
36
+ "@parlor/agent-ui": "0.3.2",
37
+ "@parlor/capabilities": "0.3.2",
38
+ "@parlor/core": "0.3.2",
39
+ "@parlor/sync": "0.3.2",
40
+ "@parlor/chat": "0.3.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@tanstack/react-query": "^5.104.1",