@parcae/sdk 0.3.1 → 0.3.3

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.
@@ -39,7 +39,6 @@ interface QueryChain<T> {
39
39
  __adapter?: any;
40
40
  }
41
41
  interface UseQueryOptions {
42
- /** Wait for auth before firing. Default: true. */
43
42
  waitForAuth?: boolean;
44
43
  }
45
44
  interface UseQueryResult<T> {
@@ -77,17 +77,10 @@ var ParcaeProvider = ({
77
77
  var cache = /* @__PURE__ */ new Map();
78
78
  var GC_DELAY = 6e4;
79
79
  var EMPTY = [];
80
- var EMPTY_RESULT = {
81
- items: EMPTY,
82
- loading: true,
83
- error: null,
84
- refetch: () => {
85
- }
86
- };
87
80
  function getOrCreate(key) {
88
- let entry = cache.get(key);
89
- if (!entry) {
90
- entry = {
81
+ let e = cache.get(key);
82
+ if (!e) {
83
+ e = {
91
84
  items: EMPTY,
92
85
  loading: true,
93
86
  error: null,
@@ -96,14 +89,14 @@ function getOrCreate(key) {
96
89
  dispose: null,
97
90
  gcTimer: null
98
91
  };
99
- cache.set(key, entry);
92
+ cache.set(key, e);
100
93
  }
101
- return entry;
94
+ return e;
102
95
  }
103
- function notify(entry) {
104
- for (const fn of entry.listeners) fn();
96
+ function notify(e) {
97
+ for (const fn of e.listeners) fn();
105
98
  }
106
- function fetchAndSubscribe(key, entry, chain, client) {
99
+ function doFetch(key, entry, chain, client) {
107
100
  entry.loading = true;
108
101
  entry.error = null;
109
102
  notify(entry);
@@ -117,40 +110,23 @@ function fetchAndSubscribe(key, entry, chain, client) {
117
110
  notify(entry);
118
111
  });
119
112
  if (!entry.dispose && chain.__modelType) {
120
- const event = `query:${key}`;
121
- client.send("subscribe:query", {
122
- hash: key,
123
- modelType: chain.__modelType,
124
- steps: chain.__steps ?? []
125
- });
126
- const unsub = client.subscribe(event, (ops) => {
113
+ const diffEvent = `query:diff:${key}`;
114
+ const unsub = client.subscribe(diffEvent, (ops) => {
127
115
  if (!ops?.length) return;
128
- const map = new Map(entry.items.map((item) => [item.id, item]));
116
+ const map = new Map(entry.items.map((i) => [i.id, i]));
129
117
  let changed = false;
130
118
  for (const op of ops) {
131
- switch (op.op) {
132
- case "add":
133
- if (!map.has(op.id) && op.data && chain.__modelClass) {
134
- map.set(op.id, new chain.__modelClass(chain.__adapter, op.data));
135
- changed = true;
136
- }
137
- break;
138
- case "remove":
139
- if (map.has(op.id)) {
140
- map.delete(op.id);
141
- changed = true;
142
- }
143
- break;
144
- case "update": {
145
- const existing = map.get(op.id);
146
- if (existing && op.data) {
147
- for (const [k, v] of Object.entries(op.data)) {
148
- existing[k] = v;
149
- }
150
- changed = true;
151
- }
152
- break;
153
- }
119
+ if (op.op === "add" && !map.has(op.id) && op.data && chain.__modelClass) {
120
+ map.set(op.id, new chain.__modelClass(chain.__adapter, op.data));
121
+ changed = true;
122
+ } else if (op.op === "remove" && map.has(op.id)) {
123
+ map.delete(op.id);
124
+ changed = true;
125
+ } else if (op.op === "update" && map.has(op.id) && op.data) {
126
+ const existing = map.get(op.id);
127
+ for (const [k, v] of Object.entries(op.data))
128
+ existing[k] = v;
129
+ changed = true;
154
130
  }
155
131
  }
156
132
  if (changed) {
@@ -160,7 +136,6 @@ function fetchAndSubscribe(key, entry, chain, client) {
160
136
  });
161
137
  entry.dispose = () => {
162
138
  unsub();
163
- client.send("unsubscribe:query", { hash: key });
164
139
  entry.dispose = null;
165
140
  };
166
141
  }
@@ -172,23 +147,23 @@ function useQuery(chain, options = {}) {
172
147
  const key = chain && authReady ? `${chain.__modelType}:${authVersion}:${JSON.stringify(chain.__steps ?? [])}` : null;
173
148
  const keyRef = useRef(key);
174
149
  keyRef.current = key;
175
- const subscribe = (onStoreChange) => {
150
+ const subscribe = (onChange) => {
176
151
  const k = keyRef.current;
177
152
  if (!k) return () => {
178
153
  };
179
- const entry2 = getOrCreate(k);
180
- entry2.refs++;
181
- entry2.listeners.add(onStoreChange);
182
- if (entry2.gcTimer) {
183
- clearTimeout(entry2.gcTimer);
184
- entry2.gcTimer = null;
154
+ const e = getOrCreate(k);
155
+ e.refs++;
156
+ e.listeners.add(onChange);
157
+ if (e.gcTimer) {
158
+ clearTimeout(e.gcTimer);
159
+ e.gcTimer = null;
185
160
  }
186
161
  return () => {
187
- entry2.listeners.delete(onStoreChange);
188
- entry2.refs--;
189
- if (entry2.refs <= 0) {
190
- entry2.gcTimer = setTimeout(() => {
191
- entry2.dispose?.();
162
+ e.listeners.delete(onChange);
163
+ e.refs--;
164
+ if (e.refs <= 0) {
165
+ e.gcTimer = setTimeout(() => {
166
+ e.dispose?.();
192
167
  cache.delete(k);
193
168
  }, GC_DELAY);
194
169
  }
@@ -207,16 +182,22 @@ function useQuery(chain, options = {}) {
207
182
  useEffect(() => {
208
183
  if (!key || !chain) return;
209
184
  const entry2 = getOrCreate(key);
210
- if (entry2.items === EMPTY || entry2.items.length === 0) {
211
- fetchAndSubscribe(key, entry2, chain, client);
185
+ if (entry2.items === EMPTY) {
186
+ doFetch(key, entry2, chain, client);
212
187
  }
213
188
  }, [key]);
214
189
  const refetch = () => {
215
190
  if (!key || !chain) return;
216
- const entry2 = getOrCreate(key);
217
- fetchAndSubscribe(key, entry2, chain, client);
191
+ doFetch(key, getOrCreate(key), chain, client);
218
192
  };
219
- if (!key) return EMPTY_RESULT;
193
+ if (!key)
194
+ return {
195
+ items: EMPTY,
196
+ loading: !authReady,
197
+ error: null,
198
+ refetch: () => {
199
+ }
200
+ };
220
201
  const entry = cache.get(key);
221
202
  return {
222
203
  items,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/context.ts","../../src/react/Provider.tsx","../../src/react/useQuery.ts","../../src/react/useApi.ts","../../src/react/useSetting.ts"],"names":["useRef","entry","useEffect","useMemo","useState","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ParcaeClient } from \"../client\";\n\nexport type AuthState = \"loading\" | \"authenticated\" | \"unauthenticated\";\n\nexport interface ParcaeContextValue {\n client: ParcaeClient;\n authState: AuthState;\n authVersion: number;\n}\n\nexport const ParcaeContext = createContext<ParcaeContextValue | null>(null);\n\nexport function useParcae(): ParcaeContextValue {\n const ctx = useContext(ParcaeContext);\n if (!ctx) {\n throw new Error(\"useParcae must be used within a <ParcaeProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport React, {\n useEffect,\n useMemo,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { createClient } from \"../client\";\nimport type { ParcaeClient, ClientConfig } from \"../client\";\nimport { ParcaeContext } from \"./context\";\nimport type { ParcaeContextValue, AuthState } from \"./context\";\n\nexport interface ParcaeProviderProps {\n /** Pre-created client instance. If provided, url/key/transport are ignored. */\n client?: ParcaeClient;\n /** API base URL (required if no client provided). */\n url?: string;\n /** Bearer token, null (no session), or undefined (still loading). */\n apiKey?: string | null | undefined;\n /** Stable user ID — triggers re-auth when it changes. */\n userId?: string | null;\n /** API version. Default: \"v1\" */\n version?: string;\n /** Transport type. Default: \"socket\" */\n transport?: ClientConfig[\"transport\"];\n children: React.ReactNode;\n onReady?: (client: ParcaeClient) => void;\n onError?: (error: Error) => void;\n}\n\nexport const ParcaeProvider: React.FC<ParcaeProviderProps> = ({\n client: externalClient,\n url,\n apiKey,\n userId,\n version = \"v1\",\n transport = \"socket\",\n children,\n onReady,\n onError,\n}) => {\n const [authState, setAuthState] = useState<AuthState>(\n // If apiKey is undefined, the frontend auth provider is still loading.\n // If apiKey is null, the user is not logged in.\n // If apiKey is a string, we have a token but haven't verified it yet.\n apiKey === undefined\n ? \"loading\"\n : apiKey === null\n ? \"unauthenticated\"\n : \"loading\",\n );\n const [authVersion, setAuthVersion] = useState(0);\n\n const client = useMemo(() => {\n if (externalClient) return externalClient;\n if (!url)\n throw new Error(\n \"ParcaeProvider requires either a `client` prop or a `url` prop\",\n );\n return createClient({ url, version, transport, key: null });\n }, [externalClient, url, version, transport]);\n\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n // Authenticate when apiKey changes\n useEffect(() => {\n // apiKey is undefined → frontend auth still loading, do nothing\n if (apiKey === undefined) {\n setAuthState(\"loading\");\n return;\n }\n\n // apiKey is null → user is not logged in\n if (apiKey === null) {\n setAuthState(\"unauthenticated\");\n setAuthVersion((v) => v + 1);\n return;\n }\n\n // apiKey is a string → send to backend for verification\n setAuthState(\"loading\");\n client\n .setKey(apiKey)\n .then(() => {\n setAuthState(\"authenticated\");\n setAuthVersion((v) => v + 1);\n onReadyRef.current?.(client);\n })\n .catch((err) => {\n setAuthState(\"unauthenticated\");\n setAuthVersion((v) => v + 1);\n onErrorRef.current?.(err);\n });\n }, [apiKey, userId, client]);\n\n useEffect(() => {\n const onErr = (err: Error) => onErrorRef.current?.(err);\n client.on(\"error\", onErr);\n return () => {\n client.off(\"error\", onErr);\n };\n }, [client]);\n\n const contextValue = useMemo<ParcaeContextValue>(\n () => ({ client, authState, authVersion }),\n [client, authState, authVersion],\n );\n\n return (\n <ParcaeContext.Provider value={contextValue}>\n {children}\n </ParcaeContext.Provider>\n );\n};\n\nexport default ParcaeProvider;\n","\"use client\";\n\n/**\n * useQuery — efficient reactive data fetching.\n *\n * - Deduplicates: same query from multiple components = one fetch\n * - Caches: unmount/remount doesn't re-fetch if data is fresh\n * - Realtime: subscribes to server-pushed diffs (add/remove/update)\n * - Auth-aware: waits for auth before firing scoped queries\n * - Efficient: React only re-renders when the items array reference changes\n */\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport { useParcae } from \"./context\";\nimport type { ParcaeClient } from \"../client\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ninterface QueryChain<T> {\n find(): Promise<T[]>;\n __steps?: any[];\n __modelType?: string;\n __modelClass?: any;\n __adapter?: any;\n}\n\ninterface UseQueryOptions {\n /** Wait for auth before firing. Default: true. */\n waitForAuth?: boolean;\n}\n\ninterface UseQueryResult<T> {\n items: T[];\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n// ─── External Cache ──────────────────────────────────────────────────────────\n\ninterface CacheEntry {\n items: any[];\n loading: boolean;\n error: Error | null;\n refs: number;\n listeners: Set<() => void>;\n dispose: (() => void) | null;\n gcTimer: ReturnType<typeof setTimeout> | null;\n}\n\nconst cache = new Map<string, CacheEntry>();\nconst GC_DELAY = 60_000;\n\nconst EMPTY: any[] = [];\nconst EMPTY_RESULT: UseQueryResult<any> = {\n items: EMPTY,\n loading: true,\n error: null,\n refetch: () => {},\n};\n\nfunction getOrCreate(key: string): CacheEntry {\n let entry = cache.get(key);\n if (!entry) {\n entry = {\n items: EMPTY,\n loading: true,\n error: null,\n refs: 0,\n listeners: new Set(),\n dispose: null,\n gcTimer: null,\n };\n cache.set(key, entry);\n }\n return entry;\n}\n\nfunction notify(entry: CacheEntry): void {\n for (const fn of entry.listeners) fn();\n}\n\n// ─── Fetch + Subscribe ───────────────────────────────────────────────────────\n\nfunction fetchAndSubscribe(\n key: string,\n entry: CacheEntry,\n chain: QueryChain<any>,\n client: ParcaeClient,\n): void {\n // Fetch\n entry.loading = true;\n entry.error = null;\n notify(entry);\n\n chain\n .find()\n .then((result: any[]) => {\n entry.items = result;\n entry.loading = false;\n notify(entry);\n })\n .catch((err: Error) => {\n entry.error = err;\n entry.loading = false;\n notify(entry);\n });\n\n // Subscribe to realtime diffs\n if (!entry.dispose && chain.__modelType) {\n const event = `query:${key}`;\n\n client.send(\"subscribe:query\", {\n hash: key,\n modelType: chain.__modelType,\n steps: chain.__steps ?? [],\n });\n\n const unsub = client.subscribe(event, (ops: any[]) => {\n if (!ops?.length) return;\n\n const map = new Map(entry.items.map((item: any) => [item.id, item]));\n let changed = false;\n\n for (const op of ops) {\n switch (op.op) {\n case \"add\":\n if (!map.has(op.id) && op.data && chain.__modelClass) {\n map.set(op.id, new chain.__modelClass(chain.__adapter, op.data));\n changed = true;\n }\n break;\n case \"remove\":\n if (map.has(op.id)) {\n map.delete(op.id);\n changed = true;\n }\n break;\n case \"update\": {\n const existing = map.get(op.id);\n if (existing && op.data) {\n for (const [k, v] of Object.entries(op.data)) {\n (existing as any)[k] = v;\n }\n changed = true;\n }\n break;\n }\n }\n }\n\n if (changed) {\n entry.items = [...map.values()];\n notify(entry);\n }\n });\n\n entry.dispose = () => {\n unsub();\n client.send(\"unsubscribe:query\", { hash: key });\n entry.dispose = null;\n };\n }\n}\n\n// ─── useQuery ────────────────────────────────────────────────────────────────\n\nexport function useQuery<T>(\n chain: QueryChain<T> | null | undefined,\n options: UseQueryOptions = {},\n): UseQueryResult<T> {\n const { client, authState, authVersion } = useParcae();\n const waitForAuth = options.waitForAuth ?? true;\n const authReady = !waitForAuth || authState !== \"loading\";\n\n const key =\n chain && authReady\n ? `${chain.__modelType}:${authVersion}:${JSON.stringify(chain.__steps ?? [])}`\n : null;\n\n // Ref to track the current key (for cleanup)\n const keyRef = useRef(key);\n keyRef.current = key;\n\n // ── useSyncExternalStore ──────────────────────────────────────────\n\n const subscribe = (onStoreChange: () => void) => {\n const k = keyRef.current;\n if (!k) return () => {};\n\n const entry = getOrCreate(k);\n entry.refs++;\n entry.listeners.add(onStoreChange);\n\n // Cancel GC\n if (entry.gcTimer) {\n clearTimeout(entry.gcTimer);\n entry.gcTimer = null;\n }\n\n return () => {\n entry.listeners.delete(onStoreChange);\n entry.refs--;\n\n if (entry.refs <= 0) {\n entry.gcTimer = setTimeout(() => {\n entry.dispose?.();\n cache.delete(k);\n }, GC_DELAY);\n }\n };\n };\n\n const getSnapshot = (): any[] => {\n const k = keyRef.current;\n if (!k) return EMPTY;\n return cache.get(k)?.items ?? EMPTY;\n };\n\n const items = useSyncExternalStore(\n subscribe,\n getSnapshot,\n getSnapshot,\n ) as T[];\n\n // ── Trigger fetch when key changes ────────────────────────────────\n\n useEffect(() => {\n if (!key || !chain) return;\n\n const entry = getOrCreate(key);\n\n // Only fetch if this is the first subscriber or items are empty\n if (entry.items === EMPTY || entry.items.length === 0) {\n fetchAndSubscribe(key, entry, chain, client);\n }\n }, [key]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Refetch ───────────────────────────────────────────────────────\n\n const refetch = () => {\n if (!key || !chain) return;\n const entry = getOrCreate(key);\n fetchAndSubscribe(key, entry, chain, client);\n };\n\n // ── Return ────────────────────────────────────────────────────────\n\n if (!key) return EMPTY_RESULT;\n\n const entry = cache.get(key);\n return {\n items,\n loading: entry?.loading ?? true,\n error: entry?.error ?? null,\n refetch,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { useParcae } from \"./context\";\n\nexport function useApi() {\n const { client } = useParcae();\n\n return useMemo(\n () => ({\n get: client.get.bind(client),\n post: client.post.bind(client),\n put: client.put.bind(client),\n patch: client.patch.bind(client),\n delete: client.delete.bind(client),\n }),\n [client],\n );\n}\n\n/**\n * useSDK — raw client instance.\n */\nexport function useSDK() {\n return useParcae().client;\n}\n\n/**\n * useConnectionStatus — connection + auth state.\n */\nexport function useConnectionStatus() {\n const { client, authState } = useParcae();\n return {\n isConnected: client.isConnected,\n isLoading: client.isLoading,\n authState,\n };\n}\n\n/**\n * useAuthState — just the auth state.\n */\nexport function useAuthState() {\n return useParcae().authState;\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useParcae } from \"./context\";\n\nexport function useSetting<T = string>(\n key: string,\n defaultValue: T,\n): [T, (value: T) => Promise<void>, { isLoading: boolean }] {\n const { client, authState } = useParcae();\n const [value, setValue] = useState<T>(defaultValue);\n const [isLoading, setIsLoading] = useState(true);\n\n // Wait for auth before fetching settings (they're user-scoped)\n useEffect(() => {\n if (authState === \"loading\") return;\n if (authState === \"unauthenticated\") {\n setIsLoading(false);\n return;\n }\n\n let cancelled = false;\n\n client\n .get(`/settings/${encodeURIComponent(key)}`)\n .then((result) => {\n if (!cancelled && result?.value !== undefined) {\n setValue(result.value);\n }\n })\n .catch(() => {})\n .finally(() => {\n if (!cancelled) setIsLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [key, client, authState]);\n\n const update = useCallback(\n async (newValue: T) => {\n setValue(newValue);\n await client.put(`/settings/${encodeURIComponent(key)}`, {\n value: newValue,\n });\n },\n [key, client],\n );\n\n return [value, update, { isLoading }];\n}\n"]}
1
+ {"version":3,"sources":["../../src/react/context.ts","../../src/react/Provider.tsx","../../src/react/useQuery.ts","../../src/react/useApi.ts","../../src/react/useSetting.ts"],"names":["useRef","useEffect","entry","useMemo","useState","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ParcaeClient } from \"../client\";\n\nexport type AuthState = \"loading\" | \"authenticated\" | \"unauthenticated\";\n\nexport interface ParcaeContextValue {\n client: ParcaeClient;\n authState: AuthState;\n authVersion: number;\n}\n\nexport const ParcaeContext = createContext<ParcaeContextValue | null>(null);\n\nexport function useParcae(): ParcaeContextValue {\n const ctx = useContext(ParcaeContext);\n if (!ctx) {\n throw new Error(\"useParcae must be used within a <ParcaeProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport React, {\n useEffect,\n useMemo,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { createClient } from \"../client\";\nimport type { ParcaeClient, ClientConfig } from \"../client\";\nimport { ParcaeContext } from \"./context\";\nimport type { ParcaeContextValue, AuthState } from \"./context\";\n\nexport interface ParcaeProviderProps {\n /** Pre-created client instance. If provided, url/key/transport are ignored. */\n client?: ParcaeClient;\n /** API base URL (required if no client provided). */\n url?: string;\n /** Bearer token, null (no session), or undefined (still loading). */\n apiKey?: string | null | undefined;\n /** Stable user ID — triggers re-auth when it changes. */\n userId?: string | null;\n /** API version. Default: \"v1\" */\n version?: string;\n /** Transport type. Default: \"socket\" */\n transport?: ClientConfig[\"transport\"];\n children: React.ReactNode;\n onReady?: (client: ParcaeClient) => void;\n onError?: (error: Error) => void;\n}\n\nexport const ParcaeProvider: React.FC<ParcaeProviderProps> = ({\n client: externalClient,\n url,\n apiKey,\n userId,\n version = \"v1\",\n transport = \"socket\",\n children,\n onReady,\n onError,\n}) => {\n const [authState, setAuthState] = useState<AuthState>(\n // If apiKey is undefined, the frontend auth provider is still loading.\n // If apiKey is null, the user is not logged in.\n // If apiKey is a string, we have a token but haven't verified it yet.\n apiKey === undefined\n ? \"loading\"\n : apiKey === null\n ? \"unauthenticated\"\n : \"loading\",\n );\n const [authVersion, setAuthVersion] = useState(0);\n\n const client = useMemo(() => {\n if (externalClient) return externalClient;\n if (!url)\n throw new Error(\n \"ParcaeProvider requires either a `client` prop or a `url` prop\",\n );\n return createClient({ url, version, transport, key: null });\n }, [externalClient, url, version, transport]);\n\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n // Authenticate when apiKey changes\n useEffect(() => {\n // apiKey is undefined → frontend auth still loading, do nothing\n if (apiKey === undefined) {\n setAuthState(\"loading\");\n return;\n }\n\n // apiKey is null → user is not logged in\n if (apiKey === null) {\n setAuthState(\"unauthenticated\");\n setAuthVersion((v) => v + 1);\n return;\n }\n\n // apiKey is a string → send to backend for verification\n setAuthState(\"loading\");\n client\n .setKey(apiKey)\n .then(() => {\n setAuthState(\"authenticated\");\n setAuthVersion((v) => v + 1);\n onReadyRef.current?.(client);\n })\n .catch((err) => {\n setAuthState(\"unauthenticated\");\n setAuthVersion((v) => v + 1);\n onErrorRef.current?.(err);\n });\n }, [apiKey, userId, client]);\n\n useEffect(() => {\n const onErr = (err: Error) => onErrorRef.current?.(err);\n client.on(\"error\", onErr);\n return () => {\n client.off(\"error\", onErr);\n };\n }, [client]);\n\n const contextValue = useMemo<ParcaeContextValue>(\n () => ({ client, authState, authVersion }),\n [client, authState, authVersion],\n );\n\n return (\n <ParcaeContext.Provider value={contextValue}>\n {children}\n </ParcaeContext.Provider>\n );\n};\n\nexport default ParcaeProvider;\n","\"use client\";\n\n/**\n * useQuery — calls chain.find() via socket RPC, subscribes to diffs automatically.\n *\n * No separate subscribe:query event. The server auto-subscribes when you\n * query a list endpoint. Diffs arrive on the same query key.\n */\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport { useParcae } from \"./context\";\nimport type { ParcaeClient } from \"../client\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ninterface QueryChain<T> {\n find(): Promise<T[]>;\n __steps?: any[];\n __modelType?: string;\n __modelClass?: any;\n __adapter?: any;\n}\n\ninterface UseQueryOptions {\n waitForAuth?: boolean;\n}\n\ninterface UseQueryResult<T> {\n items: T[];\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n// ─── External Cache ──────────────────────────────────────────────────────────\n\ninterface CacheEntry {\n items: any[];\n loading: boolean;\n error: Error | null;\n refs: number;\n listeners: Set<() => void>;\n dispose: (() => void) | null;\n gcTimer: ReturnType<typeof setTimeout> | null;\n}\n\nconst cache = new Map<string, CacheEntry>();\nconst GC_DELAY = 60_000;\nconst EMPTY: any[] = [];\n\nfunction getOrCreate(key: string): CacheEntry {\n let e = cache.get(key);\n if (!e) {\n e = {\n items: EMPTY,\n loading: true,\n error: null,\n refs: 0,\n listeners: new Set(),\n dispose: null,\n gcTimer: null,\n };\n cache.set(key, e);\n }\n return e;\n}\n\nfunction notify(e: CacheEntry): void {\n for (const fn of e.listeners) fn();\n}\n\n// ─── Fetch via chain.find() ──────────────────────────────────────────────────\n\nfunction doFetch(\n key: string,\n entry: CacheEntry,\n chain: QueryChain<any>,\n client: ParcaeClient,\n): void {\n entry.loading = true;\n entry.error = null;\n notify(entry);\n\n chain\n .find()\n .then((result: any[]) => {\n entry.items = result;\n entry.loading = false;\n notify(entry);\n })\n .catch((err: Error) => {\n entry.error = err;\n entry.loading = false;\n notify(entry);\n });\n\n // Listen for realtime diffs (server auto-subscribes on the call)\n if (!entry.dispose && chain.__modelType) {\n const diffEvent = `query:diff:${key}`;\n\n const unsub = client.subscribe(diffEvent, (ops: any[]) => {\n if (!ops?.length) return;\n\n const map = new Map(entry.items.map((i: any) => [i.id, i]));\n let changed = false;\n\n for (const op of ops) {\n if (\n op.op === \"add\" &&\n !map.has(op.id) &&\n op.data &&\n chain.__modelClass\n ) {\n map.set(op.id, new chain.__modelClass(chain.__adapter, op.data));\n changed = true;\n } else if (op.op === \"remove\" && map.has(op.id)) {\n map.delete(op.id);\n changed = true;\n } else if (op.op === \"update\" && map.has(op.id) && op.data) {\n const existing = map.get(op.id);\n for (const [k, v] of Object.entries(op.data))\n (existing as any)[k] = v;\n changed = true;\n }\n }\n\n if (changed) {\n entry.items = [...map.values()];\n notify(entry);\n }\n });\n\n entry.dispose = () => {\n unsub();\n entry.dispose = null;\n };\n }\n}\n\n// ─── useQuery ────────────────────────────────────────────────────────────────\n\nexport function useQuery<T>(\n chain: QueryChain<T> | null | undefined,\n options: UseQueryOptions = {},\n): UseQueryResult<T> {\n const { client, authState, authVersion } = useParcae();\n const waitForAuth = options.waitForAuth ?? true;\n const authReady = !waitForAuth || authState !== \"loading\";\n\n const key =\n chain && authReady\n ? `${chain.__modelType}:${authVersion}:${JSON.stringify(chain.__steps ?? [])}`\n : null;\n\n const keyRef = useRef(key);\n keyRef.current = key;\n\n const subscribe = (onChange: () => void) => {\n const k = keyRef.current;\n if (!k) return () => {};\n const e = getOrCreate(k);\n e.refs++;\n e.listeners.add(onChange);\n if (e.gcTimer) {\n clearTimeout(e.gcTimer);\n e.gcTimer = null;\n }\n return () => {\n e.listeners.delete(onChange);\n e.refs--;\n if (e.refs <= 0) {\n e.gcTimer = setTimeout(() => {\n e.dispose?.();\n cache.delete(k);\n }, GC_DELAY);\n }\n };\n };\n\n const getSnapshot = (): any[] => {\n const k = keyRef.current;\n if (!k) return EMPTY;\n return cache.get(k)?.items ?? EMPTY;\n };\n\n const items = useSyncExternalStore(\n subscribe,\n getSnapshot,\n getSnapshot,\n ) as T[];\n\n useEffect(() => {\n if (!key || !chain) return;\n const entry = getOrCreate(key);\n if (entry.items === EMPTY) {\n doFetch(key, entry, chain, client);\n }\n }, [key]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const refetch = () => {\n if (!key || !chain) return;\n doFetch(key, getOrCreate(key), chain, client);\n };\n\n if (!key)\n return {\n items: EMPTY as T[],\n loading: !authReady,\n error: null,\n refetch: () => {},\n };\n\n const entry = cache.get(key);\n return {\n items,\n loading: entry?.loading ?? true,\n error: entry?.error ?? null,\n refetch,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { useParcae } from \"./context\";\n\nexport function useApi() {\n const { client } = useParcae();\n\n return useMemo(\n () => ({\n get: client.get.bind(client),\n post: client.post.bind(client),\n put: client.put.bind(client),\n patch: client.patch.bind(client),\n delete: client.delete.bind(client),\n }),\n [client],\n );\n}\n\n/**\n * useSDK — raw client instance.\n */\nexport function useSDK() {\n return useParcae().client;\n}\n\n/**\n * useConnectionStatus — connection + auth state.\n */\nexport function useConnectionStatus() {\n const { client, authState } = useParcae();\n return {\n isConnected: client.isConnected,\n isLoading: client.isLoading,\n authState,\n };\n}\n\n/**\n * useAuthState — just the auth state.\n */\nexport function useAuthState() {\n return useParcae().authState;\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { useParcae } from \"./context\";\n\nexport function useSetting<T = string>(\n key: string,\n defaultValue: T,\n): [T, (value: T) => Promise<void>, { isLoading: boolean }] {\n const { client, authState } = useParcae();\n const [value, setValue] = useState<T>(defaultValue);\n const [isLoading, setIsLoading] = useState(true);\n\n // Wait for auth before fetching settings (they're user-scoped)\n useEffect(() => {\n if (authState === \"loading\") return;\n if (authState === \"unauthenticated\") {\n setIsLoading(false);\n return;\n }\n\n let cancelled = false;\n\n client\n .get(`/settings/${encodeURIComponent(key)}`)\n .then((result) => {\n if (!cancelled && result?.value !== undefined) {\n setValue(result.value);\n }\n })\n .catch(() => {})\n .finally(() => {\n if (!cancelled) setIsLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [key, client, authState]);\n\n const update = useCallback(\n async (newValue: T) => {\n setValue(newValue);\n await client.put(`/settings/${encodeURIComponent(key)}`, {\n value: newValue,\n });\n },\n [key, client],\n );\n\n return [value, update, { isLoading }];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcae/sdk",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Parcae SDK — client transport and React hooks for Parcae backends",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,7 +25,9 @@
25
25
  "build": "tsup",
26
26
  "dev": "tsup --watch",
27
27
  "typecheck": "tsc --noEmit",
28
- "clean": "rm -rf dist"
28
+ "clean": "rm -rf dist",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest"
29
31
  },
30
32
  "dependencies": {
31
33
  "@parcae/model": ">=0.1.0",
@@ -40,7 +42,8 @@
40
42
  "@types/react": "^19.0.0",
41
43
  "react": "^19.0.0",
42
44
  "tsup": "^8.5.0",
43
- "typescript": "^5.8.0"
45
+ "typescript": "^5.8.0",
46
+ "vitest": "^4.0.18"
44
47
  },
45
48
  "peerDependencies": {
46
49
  "react": ">=18.0.0"