@archie/react-sdk 0.3.1 → 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.
package/README.md CHANGED
@@ -263,6 +263,9 @@ const { data, error, isLoading, isRefetching, refetch } = useQuery<T>(
263
263
  - **Stale-while-revalidate**: Shows cached data immediately, refetches in background
264
264
  - **Deduplication**: Multiple components with the same query+variables share a single network request
265
265
  - **Auto-refetch on auth change**: When the user's token changes, all active queries refetch automatically
266
+ - **Auto-refetch on invalidation**: A mounted query re-runs as soon as its key is invalidated (e.g. by a `useMutation` with `invalidateQueries`); concurrent consumers of the same key still share one request
267
+ - **Latest-response-wins**: A response that was already in flight when its key got invalidated is discarded instead of repainting the view with pre-mutation data
268
+ - **Errors never blank the view**: A failed revalidation sets `error` but keeps the data already on screen
266
269
  - **Variable tracking**: Deep comparison via `JSON.stringify` — refetches when variables change
267
270
  - **SSR safe**: No `window` access when `refetchOnWindowFocus` is disabled
268
271
 
@@ -305,12 +308,12 @@ const { mutate, mutateAsync, data, error, isLoading, reset } = useMutation<T>(
305
308
 
306
309
  **Options:**
307
310
 
308
- | Option | Type | Description |
309
- | ------------------- | ------------------------------ | ------------------------------------------------------- |
310
- | `onSuccess` | `(data: T) => void` | Called after successful mutation |
311
- | `onError` | `(error: ArchieError) => void` | Called on error |
312
- | `onSettled` | `() => void` | Called after success or error |
313
- | `invalidateQueries` | `string[]` | Query substrings to invalidate from cache after success |
311
+ | Option | Type | Description |
312
+ | ------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------- |
313
+ | `onSuccess` | `(data: T) => void` | Called after successful mutation |
314
+ | `onError` | `(error: ArchieError) => void` | Called on error |
315
+ | `onSettled` | `() => void` | Called after success or error |
316
+ | `invalidateQueries` | `string[]` | Query substrings to invalidate after success — every mounted `useQuery` whose key matches refetches |
314
317
 
315
318
  **Return:**
316
319
 
@@ -339,6 +342,12 @@ const handleCreate = () => {
339
342
  };
340
343
  ```
341
344
 
345
+ > **Matching is by substring**, so `invalidateQueries: ['id']` would refetch every
346
+ > mounted query whose text contains `id` — each one a real network request. Prefer
347
+ > patterns distinctive enough to name the entity you mutated. Passing several
348
+ > patterns is cheap: the whole array is applied as one batch, so a query matched by
349
+ > more than one of them still refetches only once.
350
+
342
351
  ---
343
352
 
344
353
  ### useSubscription
package/dist/index.d.ts CHANGED
@@ -3,16 +3,22 @@ import { ArchieClient, Session, User, AuthSignInParams, ArchieError, AuthSignUpP
3
3
  export { ArchieClient, ArchieClientOptions, ArchieError, AuthConfirmParams, AuthError, AuthEvent, AuthEventCallback, AuthRecoverParams, AuthResetPasswordParams, AuthSignInParams, AuthSignUpParams, BrowserLocalStorage, ConnectionState, ConnectionStateCallback, CsvUploadOptions, FileUploadOptions, FileUploadResult, GraphQLError, GraphQLRawRequest, GraphQLRequestOptions, GraphQLResponse, IAuthModule, IFileModule, IGraphQLModule, IHttpClient, IRealtimeModule, IRestModule, Logger, MemoryStorage, NetworkError, RealtimeChannel, RealtimeEvent, RestRequestOptions, Session, StorageAdapter, Subscription, SubscriptionCallbacks, TokenAccessor, User, createClient } from '@archie/js-sdk';
4
4
 
5
5
  /**
6
- * In-memory query cache with in-flight request deduplication and stale-while-revalidate.
6
+ * In-memory query cache with in-flight request deduplication, stale-while-revalidate
7
+ * and per-key invalidation subscriptions.
7
8
  * @internal
8
9
  */
9
10
  interface CacheEntry<T = unknown> {
10
11
  data: T;
11
12
  timestamp: number;
12
13
  }
14
+ /** Called when the entry behind a key is dropped and should be re-fetched. */
15
+ type CacheListener = () => void;
13
16
  declare class QueryCache {
14
17
  private cache;
15
18
  private inflight;
19
+ private subscribers;
20
+ private generations;
21
+ private pending;
16
22
  private staleTime;
17
23
  static key(query: string, variables?: Record<string, unknown>): string;
18
24
  get<T>(key: string): CacheEntry<T> | undefined;
@@ -24,8 +30,80 @@ declare class QueryCache {
24
30
  */
25
31
  dedup<T>(key: string, fetcher: () => Promise<T>): Promise<T>;
26
32
  getInflight<T>(key: string): Promise<T> | undefined;
27
- invalidate(querySubstring: string): void;
33
+ /**
34
+ * Subscribe to invalidations of a single cache key.
35
+ *
36
+ * The listener fires when {@link invalidate} matches this key or {@link clear} runs —
37
+ * never on {@link set}, so a listener that re-fetches (and writes the result back)
38
+ * cannot re-trigger itself.
39
+ *
40
+ * @returns an unsubscribe function; call it on unmount.
41
+ */
42
+ subscribe(key: string, listener: CacheListener): () => void;
43
+ /**
44
+ * Current generation of a key. It increases every time the key is invalidated,
45
+ * so a caller can capture it before an `await` and check {@link isCurrent}
46
+ * afterwards to find out whether its response was superseded meanwhile.
47
+ *
48
+ * Reading is free of side effects: a generation is only ever recorded for a key
49
+ * something can still compare against — see {@link pruneGeneration}.
50
+ */
51
+ generation(key: string): number;
52
+ /** True while `generation` is still the live generation of `key`. */
53
+ isCurrent(key: string, generation: number): boolean;
54
+ /**
55
+ * Drop every cached entry matching `patterns`, then tell the subscribers on
56
+ * those keys to re-fetch. A key matches when it *contains* any of the patterns.
57
+ *
58
+ * Pass the whole batch in one call (`['user', 'users']`) rather than looping:
59
+ * the affected keys are resolved once, so a key matched by several patterns is
60
+ * invalidated and notified exactly once instead of racing itself.
61
+ *
62
+ * In-flight requests for matching keys are unregistered and the generation of
63
+ * each key is bumped: those requests were issued before the write landed, so
64
+ * neither joining them nor applying their result may hand back stale data.
65
+ *
66
+ * Matching is substring-based, which is deliberately loose — a pattern like
67
+ * `'id'` will match unrelated queries and cost them a refetch. Prefer patterns
68
+ * distinctive enough to name the entity you actually mutated.
69
+ */
70
+ invalidate(patterns: string | string[]): void;
71
+ /**
72
+ * Wipe everything and notify **every** subscriber, so all mounted queries
73
+ * revalidate. That is intentional — a full clear means no key can be trusted —
74
+ * but it does mean calling this on sign-out fires a refetch for every mounted
75
+ * query, which is rarely what you want with a dead token.
76
+ */
28
77
  clear(): void;
78
+ private bumpGeneration;
79
+ /**
80
+ * Whether anything can still compare a generation for this key: a mounted
81
+ * consumer that may fetch it, or a request already on its way back.
82
+ */
83
+ private hasHolder;
84
+ /**
85
+ * Forget a key's generation once nothing references it.
86
+ *
87
+ * Pruning is deliberately **not** done when a request settles. A pruned entry
88
+ * reads back as generation 0, which is exactly what a caller that captured 0
89
+ * holds — so a response that was superseded while in flight would be accepted
90
+ * again, and would write pre-mutation data into the cache. The prune therefore
91
+ * happens at the last unsubscribe, and only while nothing is pending.
92
+ *
93
+ * That leaves one bounded remainder, and it is worth naming precisely: if a key
94
+ * has no subscriber left but a request still on its way back, {@link invalidate}
95
+ * or {@link clear} bumps its entry rather than dropping it, and the settle path
96
+ * does not reclaim it. It survives — one entry, holding one key — until some
97
+ * *later* {@link invalidate} matches that key and finds nothing holding it. The
98
+ * two ways in are a consumer that unmounts mid-request and is then invalidated,
99
+ * and a `clear()` (a sign-out, say) fired while requests are in flight, which
100
+ * leaves one entry per key that was still loading. Since patterns match by
101
+ * substring, the next mutation touching that entity reclaims every such remnant
102
+ * at once. Bytes, deliberately traded for the guarantee above.
103
+ */
104
+ private pruneGeneration;
105
+ /** Notify one key's listeners. Iterates a snapshot so listeners may unsubscribe. */
106
+ private notify;
29
107
  }
30
108
 
31
109
  interface ArchieContextValue {
package/dist/index.js CHANGED
@@ -7,6 +7,9 @@ export { ArchieError, AuthError, BrowserLocalStorage, GraphQLError, MemoryStorag
7
7
  var QueryCache = class {
8
8
  cache = /* @__PURE__ */ new Map();
9
9
  inflight = /* @__PURE__ */ new Map();
10
+ subscribers = /* @__PURE__ */ new Map();
11
+ generations = /* @__PURE__ */ new Map();
12
+ pending = /* @__PURE__ */ new Map();
10
13
  staleTime = 0;
11
14
  static key(query, variables) {
12
15
  return `${query}::${variables ? JSON.stringify(variables) : ""}`;
@@ -31,24 +34,172 @@ var QueryCache = class {
31
34
  const existing = this.inflight.get(key);
32
35
  if (existing) return existing;
33
36
  const promise = fetcher().finally(() => {
34
- this.inflight.delete(key);
37
+ const remaining = (this.pending.get(key) ?? 1) - 1;
38
+ if (remaining > 0) {
39
+ this.pending.set(key, remaining);
40
+ } else {
41
+ this.pending.delete(key);
42
+ }
43
+ if (this.inflight.get(key) === promise) {
44
+ this.inflight.delete(key);
45
+ }
35
46
  });
47
+ this.pending.set(key, (this.pending.get(key) ?? 0) + 1);
36
48
  this.inflight.set(key, promise);
37
49
  return promise;
38
50
  }
39
51
  getInflight(key) {
40
52
  return this.inflight.get(key);
41
53
  }
42
- invalidate(querySubstring) {
43
- for (const key of this.cache.keys()) {
44
- if (key.includes(querySubstring)) {
45
- this.cache.delete(key);
54
+ /**
55
+ * Subscribe to invalidations of a single cache key.
56
+ *
57
+ * The listener fires when {@link invalidate} matches this key or {@link clear} runs —
58
+ * never on {@link set}, so a listener that re-fetches (and writes the result back)
59
+ * cannot re-trigger itself.
60
+ *
61
+ * @returns an unsubscribe function; call it on unmount.
62
+ */
63
+ subscribe(key, listener) {
64
+ let listeners = this.subscribers.get(key);
65
+ if (!listeners) {
66
+ listeners = /* @__PURE__ */ new Set();
67
+ this.subscribers.set(key, listeners);
68
+ }
69
+ listeners.add(listener);
70
+ return () => {
71
+ const current = this.subscribers.get(key);
72
+ if (!current) return;
73
+ current.delete(listener);
74
+ if (current.size === 0) {
75
+ this.subscribers.delete(key);
76
+ this.pruneGeneration(key);
46
77
  }
78
+ };
79
+ }
80
+ /**
81
+ * Current generation of a key. It increases every time the key is invalidated,
82
+ * so a caller can capture it before an `await` and check {@link isCurrent}
83
+ * afterwards to find out whether its response was superseded meanwhile.
84
+ *
85
+ * Reading is free of side effects: a generation is only ever recorded for a key
86
+ * something can still compare against — see {@link pruneGeneration}.
87
+ */
88
+ generation(key) {
89
+ return this.generations.get(key) ?? 0;
90
+ }
91
+ /** True while `generation` is still the live generation of `key`. */
92
+ isCurrent(key, generation) {
93
+ return (this.generations.get(key) ?? 0) === generation;
94
+ }
95
+ /**
96
+ * Drop every cached entry matching `patterns`, then tell the subscribers on
97
+ * those keys to re-fetch. A key matches when it *contains* any of the patterns.
98
+ *
99
+ * Pass the whole batch in one call (`['user', 'users']`) rather than looping:
100
+ * the affected keys are resolved once, so a key matched by several patterns is
101
+ * invalidated and notified exactly once instead of racing itself.
102
+ *
103
+ * In-flight requests for matching keys are unregistered and the generation of
104
+ * each key is bumped: those requests were issued before the write landed, so
105
+ * neither joining them nor applying their result may hand back stale data.
106
+ *
107
+ * Matching is substring-based, which is deliberately loose — a pattern like
108
+ * `'id'` will match unrelated queries and cost them a refetch. Prefer patterns
109
+ * distinctive enough to name the entity you actually mutated.
110
+ */
111
+ invalidate(patterns) {
112
+ const list = Array.isArray(patterns) ? patterns : [patterns];
113
+ if (list.length === 0) return;
114
+ const matches = (key) => list.some((pattern) => key.includes(pattern));
115
+ const affected = /* @__PURE__ */ new Set();
116
+ for (const key of this.cache.keys()) if (matches(key)) affected.add(key);
117
+ for (const key of this.inflight.keys()) if (matches(key)) affected.add(key);
118
+ for (const key of this.subscribers.keys()) if (matches(key)) affected.add(key);
119
+ for (const key of this.generations.keys()) if (matches(key)) affected.add(key);
120
+ for (const key of affected) {
121
+ this.cache.delete(key);
122
+ this.inflight.delete(key);
123
+ if (this.hasHolder(key)) {
124
+ this.bumpGeneration(key);
125
+ } else {
126
+ this.generations.delete(key);
127
+ }
128
+ }
129
+ for (const key of affected) {
130
+ this.notify(key);
47
131
  }
48
132
  }
133
+ /**
134
+ * Wipe everything and notify **every** subscriber, so all mounted queries
135
+ * revalidate. That is intentional — a full clear means no key can be trusted —
136
+ * but it does mean calling this on sign-out fires a refetch for every mounted
137
+ * query, which is rarely what you want with a dead token.
138
+ */
49
139
  clear() {
140
+ const known = /* @__PURE__ */ new Set([
141
+ ...this.generations.keys(),
142
+ ...this.pending.keys(),
143
+ ...this.subscribers.keys()
144
+ ]);
145
+ for (const key of known) {
146
+ if (this.hasHolder(key)) {
147
+ this.bumpGeneration(key);
148
+ } else {
149
+ this.generations.delete(key);
150
+ }
151
+ }
50
152
  this.cache.clear();
51
153
  this.inflight.clear();
154
+ for (const key of [...this.subscribers.keys()]) {
155
+ this.notify(key);
156
+ }
157
+ }
158
+ bumpGeneration(key) {
159
+ this.generations.set(key, (this.generations.get(key) ?? 0) + 1);
160
+ }
161
+ /**
162
+ * Whether anything can still compare a generation for this key: a mounted
163
+ * consumer that may fetch it, or a request already on its way back.
164
+ */
165
+ hasHolder(key) {
166
+ return this.subscribers.has(key) || (this.pending.get(key) ?? 0) > 0;
167
+ }
168
+ /**
169
+ * Forget a key's generation once nothing references it.
170
+ *
171
+ * Pruning is deliberately **not** done when a request settles. A pruned entry
172
+ * reads back as generation 0, which is exactly what a caller that captured 0
173
+ * holds — so a response that was superseded while in flight would be accepted
174
+ * again, and would write pre-mutation data into the cache. The prune therefore
175
+ * happens at the last unsubscribe, and only while nothing is pending.
176
+ *
177
+ * That leaves one bounded remainder, and it is worth naming precisely: if a key
178
+ * has no subscriber left but a request still on its way back, {@link invalidate}
179
+ * or {@link clear} bumps its entry rather than dropping it, and the settle path
180
+ * does not reclaim it. It survives — one entry, holding one key — until some
181
+ * *later* {@link invalidate} matches that key and finds nothing holding it. The
182
+ * two ways in are a consumer that unmounts mid-request and is then invalidated,
183
+ * and a `clear()` (a sign-out, say) fired while requests are in flight, which
184
+ * leaves one entry per key that was still loading. Since patterns match by
185
+ * substring, the next mutation touching that entity reclaims every such remnant
186
+ * at once. Bytes, deliberately traded for the guarantee above.
187
+ */
188
+ pruneGeneration(key) {
189
+ if (this.hasHolder(key)) return;
190
+ this.generations.delete(key);
191
+ }
192
+ /** Notify one key's listeners. Iterates a snapshot so listeners may unsubscribe. */
193
+ notify(key) {
194
+ const listeners = this.subscribers.get(key);
195
+ if (!listeners) return;
196
+ for (const listener of [...listeners]) {
197
+ if (!listeners.has(listener)) continue;
198
+ try {
199
+ listener();
200
+ } catch {
201
+ }
202
+ }
52
203
  }
53
204
  };
54
205
 
@@ -198,6 +349,7 @@ function useQuery(gql, variables, options) {
198
349
  const cacheKey = QueryCache.key(gql, variables);
199
350
  const optionsRef = useRef(options);
200
351
  optionsRef.current = options;
352
+ const activeFetches = useRef(0);
201
353
  const fetchData = useCallback(
202
354
  async (isRefetch = false) => {
203
355
  if (!enabled) return;
@@ -206,11 +358,14 @@ function useQuery(gql, variables, options) {
206
358
  } else {
207
359
  setIsLoading(true);
208
360
  }
361
+ activeFetches.current += 1;
362
+ const generation = cache.generation(cacheKey);
209
363
  try {
210
364
  const result = await cache.dedup(cacheKey, () => client.graphql.query(gql, variables));
365
+ if (!cache.isCurrent(cacheKey, generation)) return;
211
366
  if (result.error) {
212
367
  setError(result.error);
213
- setData(null);
368
+ if (!isRefetch) setData(null);
214
369
  optionsRef.current?.onError?.(result.error);
215
370
  } else {
216
371
  setData(result.data);
@@ -219,11 +374,15 @@ function useQuery(gql, variables, options) {
219
374
  optionsRef.current?.onSuccess?.(result.data);
220
375
  }
221
376
  } catch (err) {
377
+ if (!cache.isCurrent(cacheKey, generation)) return;
222
378
  setError(err);
223
- setData(null);
379
+ if (!isRefetch) setData(null);
224
380
  } finally {
225
- setIsLoading(false);
226
- setIsRefetching(false);
381
+ activeFetches.current -= 1;
382
+ if (activeFetches.current === 0) {
383
+ setIsLoading(false);
384
+ setIsRefetching(false);
385
+ }
227
386
  }
228
387
  },
229
388
  [client, gql, variablesKey, enabled, cacheKey, cache]
@@ -242,6 +401,14 @@ function useQuery(gql, variables, options) {
242
401
  fetchData(false);
243
402
  }
244
403
  }, [cacheKey, enabled]);
404
+ const fetchDataRef = useRef(fetchData);
405
+ fetchDataRef.current = fetchData;
406
+ useEffect(() => {
407
+ if (!enabled) return;
408
+ return cache.subscribe(cacheKey, () => {
409
+ fetchDataRef.current(true);
410
+ });
411
+ }, [cacheKey, enabled, cache]);
245
412
  const prevSessionRef = useRef(session?.accessToken);
246
413
  useEffect(() => {
247
414
  if (enabled && prevSessionRef.current !== session?.accessToken && prevSessionRef.current !== void 0) {
@@ -289,10 +456,9 @@ function useMutation(gql, options) {
289
456
  setData(result.data);
290
457
  setError(null);
291
458
  optionsRef.current?.onSuccess?.(result.data);
292
- if (optionsRef.current?.invalidateQueries) {
293
- for (const queryKey of optionsRef.current.invalidateQueries) {
294
- cache.invalidate(queryKey);
295
- }
459
+ const invalidateQueries = optionsRef.current?.invalidateQueries;
460
+ if (invalidateQueries?.length) {
461
+ cache.invalidate(invalidateQueries);
296
462
  }
297
463
  optionsRef.current?.onSettled?.();
298
464
  return result.data;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/query-cache.ts","../src/provider.tsx","../src/hooks/useArchieClient.ts","../src/hooks/useAuth.ts","../src/hooks/useQuery.ts","../src/hooks/useMutation.ts","../src/hooks/useSubscription.ts","../src/hooks/useFileUpload.ts","../src/hooks/useRest.ts","../src/hooks/useNotifications.ts","../src/components/AuthGuard.tsx"],"names":["React","useMemo","useState","useCallback","useEffect","useRef"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * In-memory query cache with in-flight request deduplication and stale-while-revalidate.\n * @internal\n */\n\ninterface CacheEntry<T = unknown> {\n data: T;\n timestamp: number;\n}\n\nexport class QueryCache {\n private cache = new Map<string, CacheEntry>();\n private inflight = new Map<string, Promise<unknown>>();\n private staleTime = 0;\n\n static key(query: string, variables?: Record<string, unknown>): string {\n return `${query}::${variables ? JSON.stringify(variables) : ''}`;\n }\n\n get<T>(key: string): CacheEntry<T> | undefined {\n return this.cache.get(key) as CacheEntry<T> | undefined;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, timestamp: Date.now() });\n }\n\n isFresh(key: string): boolean {\n const entry = this.cache.get(key);\n if (!entry) return false;\n if (this.staleTime === 0) return false;\n return Date.now() - entry.timestamp < this.staleTime;\n }\n\n /**\n * Deduplicate in-flight requests: if an identical fetch is already pending,\n * return the same promise. Otherwise, run `fetcher` and share the promise.\n */\n async dedup<T>(key: string, fetcher: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(key);\n if (existing) return existing as Promise<T>;\n\n const promise = fetcher().finally(() => {\n this.inflight.delete(key);\n });\n\n this.inflight.set(key, promise);\n return promise;\n }\n\n getInflight<T>(key: string): Promise<T> | undefined {\n return this.inflight.get(key) as Promise<T> | undefined;\n }\n\n invalidate(querySubstring: string): void {\n for (const key of this.cache.keys()) {\n if (key.includes(querySubstring)) {\n this.cache.delete(key);\n }\n }\n }\n\n clear(): void {\n this.cache.clear();\n this.inflight.clear();\n }\n}\n","import React, { createContext, useContext, useEffect, useState, useMemo } from 'react';\nimport type { ArchieClient, Session, AuthEvent } from '@archie/js-sdk';\nimport { QueryCache } from './lib/query-cache';\n\n// ─── Context ──────────────────────────────────────────────────\n\ninterface ArchieContextValue {\n client: ArchieClient;\n session: Session | null;\n isLoading: boolean;\n cache: QueryCache;\n}\n\nexport const ArchieContext = createContext<ArchieContextValue | null>(null);\n\n// ─── Provider ─────────────────────────────────────────────────\n\nexport interface ArchieProviderProps {\n client: ArchieClient;\n children: React.ReactNode;\n /** @internal Inject a custom cache (useful for testing). */\n cache?: QueryCache;\n}\n\n/**\n * ArchieProvider — wraps your React app to provide the Archie client and session state.\n *\n * @example\n * ```tsx\n * import { createClient } from '@archie/js-sdk'\n * import { ArchieProvider } from '@archie/react-sdk'\n *\n * const archie = createClient({ projectId: '...' })\n *\n * function App() {\n * return (\n * <ArchieProvider client={archie}>\n * <MyApp />\n * </ArchieProvider>\n * )\n * }\n * ```\n */\nexport function ArchieProvider({ client, children, cache: injectedCache }: ArchieProviderProps) {\n const [session, setSession] = useState<Session | null>(client.auth.getSession());\n const [isLoading, setIsLoading] = useState(true);\n const defaultCache = useMemo(() => new QueryCache(), [client]);\n const cache = injectedCache ?? defaultCache;\n\n useEffect(() => {\n client.auth.waitForInit().then(() => {\n setSession(client.auth.getSession());\n setIsLoading(false);\n });\n\n const unsubscribe = client.auth.onAuthStateChange(\n (_event: AuthEvent, newSession: Session | null) => {\n setSession(newSession);\n },\n );\n\n return unsubscribe;\n }, [client]);\n\n const value = useMemo<ArchieContextValue>(\n () => ({ client, session, isLoading, cache }),\n [client, session, isLoading, cache],\n );\n\n return React.createElement(ArchieContext.Provider, { value }, children);\n}\n\n/**\n * Internal hook to access the Archie context.\n * @throws if used outside ArchieProvider\n * @internal\n */\nexport function useArchieContext(): ArchieContextValue {\n const context = useContext(ArchieContext);\n if (!context) {\n throw new Error(\n 'useArchieClient must be used within an <ArchieProvider>. ' +\n 'Wrap your app with <ArchieProvider client={archieClient}>.',\n );\n }\n return context;\n}\n","import { useArchieContext } from '../provider';\nimport type { ArchieClient } from '@archie/js-sdk';\n\n/**\n * Returns the ArchieClient instance from context.\n * Must be used within an ArchieProvider.\n *\n * @throws Error if used outside ArchieProvider\n */\nexport function useArchieClient(): ArchieClient {\n const { client } = useArchieContext();\n return client;\n}\n","import { useCallback, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport type {\n User,\n Session,\n AuthSignUpParams,\n AuthSignInParams,\n AuthConfirmParams,\n AuthRecoverParams,\n AuthResetPasswordParams,\n ArchieError,\n} from '@archie/js-sdk';\n\ninterface UseAuthReturn {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n signIn: (\n params: AuthSignInParams,\n ) => Promise<{ session: Session | null; error: ArchieError | null }>;\n signUp: (\n params: AuthSignUpParams,\n ) => Promise<{ data: { userId: string; message: string } | null; error: ArchieError | null }>;\n signOut: () => Promise<void>;\n confirmSignUp: (\n params: AuthConfirmParams,\n ) => Promise<{ session: Session | null; error: ArchieError | null }>;\n recoverPassword: (\n params: AuthRecoverParams,\n ) => Promise<{ data: { message: string } | null; error: ArchieError | null }>;\n resetPassword: (\n params: AuthResetPasswordParams,\n ) => Promise<{ data: { message: string } | null; error: ArchieError | null }>;\n refreshSession: () => Promise<{ session: Session | null; error: ArchieError | null }>;\n}\n\n/**\n * Hook for authentication state and operations.\n * All methods return `{ data/session, error }` (never throws).\n */\nexport function useAuth(): UseAuthReturn {\n const { client, session, isLoading } = useArchieContext();\n\n const signIn = useCallback(\n async (params: AuthSignInParams) => {\n try {\n const result = await client.auth.signIn(params);\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const signUp = useCallback(\n async (params: AuthSignUpParams) => {\n try {\n const result = await client.auth.signUp(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const signOut = useCallback(async () => {\n await client.auth.signOut();\n }, [client]);\n\n const confirmSignUp = useCallback(\n async (params: AuthConfirmParams) => {\n try {\n const result = await client.auth.confirmSignUp(params);\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const recoverPassword = useCallback(\n async (params: AuthRecoverParams) => {\n try {\n const result = await client.auth.recoverPassword(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const resetPassword = useCallback(\n async (params: AuthResetPasswordParams) => {\n try {\n const result = await client.auth.resetPassword(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const refreshSession = useCallback(async () => {\n try {\n const result = await client.auth.refreshSession();\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n }, [client]);\n\n return useMemo(\n () => ({\n user: session?.user ?? null,\n session,\n isLoading,\n isAuthenticated: session !== null,\n signIn,\n signUp,\n signOut,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n }),\n [\n session,\n isLoading,\n signIn,\n signUp,\n signOut,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n ],\n );\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport { QueryCache } from '../lib/query-cache';\nimport type { ArchieError } from '@archie/js-sdk';\n\ninterface UseQueryOptions<T> {\n enabled?: boolean;\n refetchInterval?: number;\n refetchOnWindowFocus?: boolean;\n onSuccess?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n}\n\ninterface UseQueryReturn<T> {\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n isRefetching: boolean;\n refetch: () => Promise<void>;\n}\n\n/**\n * Declarative GraphQL query hook with caching and stale-while-revalidate.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuery<{ users: User[] }>(\n * 'query { users { id email name } }',\n * { limit: 10 }\n * )\n * ```\n */\nexport function useQuery<T = unknown>(\n gql: string,\n variables?: Record<string, unknown>,\n options?: UseQueryOptions<T>,\n): UseQueryReturn<T> {\n const { client, session, cache } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefetching, setIsRefetching] = useState(false);\n\n const enabled = options?.enabled !== false;\n\n const variablesKey = variables ? JSON.stringify(variables) : '';\n const cacheKey = QueryCache.key(gql, variables);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const fetchData = useCallback(\n async (isRefetch = false) => {\n if (!enabled) return;\n\n if (isRefetch) {\n setIsRefetching(true);\n } else {\n setIsLoading(true);\n }\n\n try {\n const result = await cache.dedup(cacheKey, () => client.graphql.query<T>(gql, variables));\n if (result.error) {\n setError(result.error);\n setData(null);\n optionsRef.current?.onError?.(result.error);\n } else {\n setData(result.data);\n setError(null);\n cache.set(cacheKey, result.data);\n optionsRef.current?.onSuccess?.(result.data as T);\n }\n } catch (err) {\n setError(err as ArchieError);\n setData(null);\n } finally {\n setIsLoading(false);\n setIsRefetching(false);\n }\n },\n [client, gql, variablesKey, enabled, cacheKey, cache],\n );\n\n // Initial fetch & refetch on variable change\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n\n const cached = cache.get<T>(cacheKey);\n if (cached) {\n setData(cached.data);\n setIsLoading(false);\n fetchData(true);\n } else {\n fetchData(false);\n }\n }, [cacheKey, enabled]);\n\n // Refetch on auth state change (new token)\n const prevSessionRef = useRef(session?.accessToken);\n useEffect(() => {\n if (\n enabled &&\n prevSessionRef.current !== session?.accessToken &&\n prevSessionRef.current !== undefined\n ) {\n fetchData(true);\n }\n prevSessionRef.current = session?.accessToken;\n }, [session?.accessToken, enabled]);\n\n // Polling (refetchInterval)\n useEffect(() => {\n if (!enabled || !options?.refetchInterval) return;\n\n const interval = setInterval(() => {\n fetchData(true);\n }, options.refetchInterval);\n\n return () => clearInterval(interval);\n }, [enabled, options?.refetchInterval]);\n\n // Refetch on window focus\n useEffect(() => {\n if (!enabled || !options?.refetchOnWindowFocus) return;\n if (typeof window === 'undefined') return;\n\n const handleFocus = () => fetchData(true);\n window.addEventListener('focus', handleFocus);\n return () => window.removeEventListener('focus', handleFocus);\n }, [enabled, options?.refetchOnWindowFocus]);\n\n const refetch = useCallback(() => fetchData(true), [fetchData]);\n\n return { data, error, isLoading, isRefetching, refetch };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError } from '@archie/js-sdk';\n\ninterface UseMutationOptions<T> {\n onSuccess?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n onSettled?: () => void;\n /** Query substrings to invalidate (forcing refetch) after a successful mutation. */\n invalidateQueries?: string[];\n}\n\ninterface UseMutationReturn<T> {\n mutate: (variables?: Record<string, unknown>) => void;\n mutateAsync: (variables?: Record<string, unknown>) => Promise<T | null>;\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n reset: () => void;\n}\n\n/**\n * Hook for GraphQL mutations.\n *\n * @example\n * ```tsx\n * const { mutate, isLoading } = useMutation<{ createUser: User }>(\n * 'mutation($data: CreateUserInput!) { createUser(data: $data) { id email } }',\n * { invalidateQueries: ['users'] }\n * )\n *\n * mutate({ data: { email: 'new@user.com', name: 'John' } })\n * ```\n */\nexport function useMutation<T = unknown>(\n gql: string,\n options?: UseMutationOptions<T>,\n): UseMutationReturn<T> {\n const { client, cache } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const execute = useCallback(\n async (variables?: Record<string, unknown>): Promise<T | null> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await client.graphql.mutate<T>(gql, variables);\n\n if (result.error) {\n setError(result.error);\n setData(null);\n optionsRef.current?.onError?.(result.error);\n optionsRef.current?.onSettled?.();\n return null;\n }\n\n setData(result.data);\n setError(null);\n optionsRef.current?.onSuccess?.(result.data as T);\n\n if (optionsRef.current?.invalidateQueries) {\n for (const queryKey of optionsRef.current.invalidateQueries) {\n cache.invalidate(queryKey);\n }\n }\n\n optionsRef.current?.onSettled?.();\n return result.data;\n } catch (err) {\n const archieErr = err as ArchieError;\n setError(archieErr);\n setData(null);\n optionsRef.current?.onError?.(archieErr);\n optionsRef.current?.onSettled?.();\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client, gql, cache],\n );\n\n const mutate = useCallback(\n (variables?: Record<string, unknown>) => {\n execute(variables);\n },\n [execute],\n );\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return { mutate, mutateAsync: execute, data, error, isLoading, reset };\n}\n","import { useState, useEffect, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, ConnectionState } from '@archie/js-sdk';\n\ninterface UseSubscriptionOptions<T> {\n enabled?: boolean;\n onData?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n}\n\ninterface UseSubscriptionReturn<T> {\n data: T | null;\n error: ArchieError | null;\n connectionState: ConnectionState;\n}\n\n/**\n * Hook for real-time GraphQL subscriptions.\n * Subscribes on mount, unsubscribes on unmount.\n *\n * @example\n * ```tsx\n * const { data } = useSubscription<{ orderUpdated: Order }>(\n * 'subscription { orderUpdated { id status total } }'\n * )\n * ```\n */\nexport function useSubscription<T = unknown>(\n gql: string,\n variables?: Record<string, unknown>,\n options?: UseSubscriptionOptions<T>,\n): UseSubscriptionReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>('DISCONNECTED');\n\n const enabled = options?.enabled !== false;\n const variablesKey = variables ? JSON.stringify(variables) : '';\n\n // Track latest callbacks to avoid stale closures\n const callbacksRef = useRef(options);\n callbacksRef.current = options;\n\n useEffect(() => {\n if (!enabled) return;\n\n const unsub = client.realtime.onConnectionStateChange(setConnectionState);\n\n const subscription = client.realtime.subscribe<T>(gql, variables, {\n onData: (newData: T) => {\n setData(newData);\n setError(null);\n callbacksRef.current?.onData?.(newData);\n },\n onError: (err) => {\n setError(err);\n callbacksRef.current?.onError?.(err);\n },\n onComplete: () => {\n // Subscription completed server-side\n },\n });\n\n return () => {\n subscription.unsubscribe();\n unsub();\n };\n }, [client, gql, variablesKey, enabled]);\n\n return { data, error, connectionState };\n}\n","import { useState, useCallback } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, FileUploadOptions, FileUploadResult } from '@archie/js-sdk';\n\ninterface UseFileUploadReturn {\n upload: (file: File | Blob, options?: FileUploadOptions) => Promise<void>;\n progress: number;\n isUploading: boolean;\n data: FileUploadResult | null;\n error: ArchieError | null;\n reset: () => void;\n}\n\n/**\n * Hook for file uploads.\n *\n * @example\n * ```tsx\n * const { upload, isUploading, data } = useFileUpload()\n *\n * <input type=\"file\" onChange={(e) => upload(e.target.files[0])} />\n * {isUploading && <Spinner />}\n * ```\n */\nexport function useFileUpload(): UseFileUploadReturn {\n const { client } = useArchieContext();\n const [progress, setProgress] = useState(0);\n const [isUploading, setIsUploading] = useState(false);\n const [data, setData] = useState<FileUploadResult | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n\n const upload = useCallback(\n async (file: File | Blob, options?: FileUploadOptions) => {\n setIsUploading(true);\n setProgress(0);\n setError(null);\n setData(null);\n\n try {\n const result = await client.files.upload(file, options);\n\n setData(result);\n setProgress(100);\n } catch (err) {\n setError(err as ArchieError);\n } finally {\n setIsUploading(false);\n }\n },\n [client],\n );\n\n const reset = useCallback(() => {\n setProgress(0);\n setIsUploading(false);\n setData(null);\n setError(null);\n }, []);\n\n return { upload, progress, isUploading, data, error, reset };\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, RestRequestOptions, IRestModule } from '@archie/js-sdk';\n\n// ─── useRest (base) ──────────────────────────────────────────\n\n/**\n * Returns the REST module from the Archie client.\n * Provides direct access to `get`, `post`, `put`, `patch`, `delete`.\n *\n * @example\n * ```tsx\n * const rest = useRest()\n * const data = await rest.get('/api/products')\n * await rest.post('/api/products', { name: 'Widget' })\n * ```\n */\nexport function useRest(): IRestModule {\n const { client } = useArchieContext();\n return useMemo(() => client.rest, [client]);\n}\n\n// ─── useRestQuery ─────────────────────────────────────────────\n\ninterface UseRestQueryReturn<T> {\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n refetch: () => Promise<void>;\n}\n\n/**\n * Declarative hook for GET requests to custom REST APIs.\n */\nexport function useRestQuery<T = unknown>(\n path: string,\n options?: RestRequestOptions & { enabled?: boolean },\n): UseRestQueryReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n const enabled = options?.enabled !== false;\n\n const fetchData = useCallback(async () => {\n if (!enabled) return;\n setIsLoading(true);\n\n try {\n const result = await client.rest.get<T>(path, options);\n setData(result);\n setError(null);\n } catch (err) {\n setError(err as ArchieError);\n setData(null);\n } finally {\n setIsLoading(false);\n }\n }, [client, path, enabled]);\n\n useEffect(() => {\n if (enabled) {\n fetchData();\n } else {\n setIsLoading(false);\n }\n }, [fetchData, enabled]);\n\n return { data, error, isLoading, refetch: fetchData };\n}\n\n// ─── useRestMutation ──────────────────────────────────────────\n\ninterface UseRestMutationReturn<T> {\n execute: (body?: unknown, overrideOptions?: RestRequestOptions) => Promise<T | null>;\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n reset: () => void;\n}\n\n/**\n * Imperative hook for POST/PUT/PATCH/DELETE requests to custom REST APIs.\n */\nexport function useRestMutation<T = unknown>(\n path: string,\n method: 'POST' | 'PUT' | 'PATCH' | 'DELETE' = 'POST',\n): UseRestMutationReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const execute = useCallback(\n async (body?: unknown, overrideOptions?: RestRequestOptions): Promise<T | null> => {\n setIsLoading(true);\n setError(null);\n\n try {\n let result: T;\n switch (method) {\n case 'POST':\n result = await client.rest.post<T>(path, body, overrideOptions);\n break;\n case 'PUT':\n result = await client.rest.put<T>(path, body, overrideOptions);\n break;\n case 'PATCH':\n result = await client.rest.patch<T>(path, body, overrideOptions);\n break;\n case 'DELETE':\n result = await client.rest.delete<T>(path, overrideOptions);\n break;\n }\n\n setData(result);\n setError(null);\n return result;\n } catch (err) {\n const archieErr = err as ArchieError;\n setError(archieErr);\n setData(null);\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client, path, method],\n );\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return { execute, data, error, isLoading, reset };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, ConnectionState, Notification } from '@archie/js-sdk';\n\nexport interface UseNotificationsOptions {\n enabled?: boolean;\n unreadOnly?: boolean;\n /**\n * Page size. Applies to `fetchMore()` (older pages); when omitted, `fetchMore` uses 20.\n * It also caps the initial load (`first: limit`) — so omitting it lets the backend choose the\n * initial page size, meaning the first page and subsequent `fetchMore` pages may differ in size.\n */\n limit?: number;\n onNotification?: (notification: Notification) => void;\n}\n\nexport interface UseNotificationsReturn {\n notifications: Notification[];\n latest: Notification | null;\n unreadCount: number;\n isLoading: boolean;\n error: ArchieError | null;\n connectionState: ConnectionState;\n markAsRead: (id: string) => Promise<void>;\n markAllAsRead: () => Promise<void>;\n refetch: () => Promise<void>;\n /**\n * Load the next older page of history. No-op if `!hasMore`, a fetch is already in flight,\n * disabled, or a previous `fetchMore` errored (call `refetch()` or change the filter to retry).\n */\n fetchMore: () => Promise<void>;\n /** True while more older history exists for the active filter (the last page did not exhaust it). */\n hasMore: boolean;\n /** True while a fetchMore() call is in flight (drives a \"loading older\" indicator). */\n isFetchingMore: boolean;\n}\n\n/** Default page size for fetchMore() when no `limit` is provided. Initial load is unaffected. */\nconst DEFAULT_PAGE_SIZE = 20;\n\n/** Ids of the items whose `createdAt` equals `ts` — the tie-group at a keyset boundary. */\nfunction idsAt(items: Notification[], ts: string | null): string[] {\n if (ts == null) return [];\n return items.filter((n) => n.createdAt === ts).map((n) => n.id);\n}\n\n/**\n * Subscribe to a user's in-app notifications: loads the existing list,\n * then streams new ones live, and pages backward through history via fetchMore().\n * Returns idiomatic React state.\n *\n * @example\n * ```tsx\n * const { notifications, unreadCount, fetchMore, hasMore, isFetchingMore } =\n * useNotifications(user.id, { limit: 20 });\n * ```\n */\nexport function useNotifications(\n receiverId: string,\n options?: UseNotificationsOptions,\n): UseNotificationsReturn {\n const { client } = useArchieContext();\n const [notifications, setNotifications] = useState<Notification[]>([]);\n const [latest, setLatest] = useState<Notification | null>(null);\n const [unreadCount, setUnreadCount] = useState(0);\n const [isLoading, setIsLoading] = useState(options?.enabled !== false);\n const [error, setError] = useState<ArchieError | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>(\n () => client.realtime.currentState,\n );\n const [hasMore, setHasMore] = useState(false);\n const [isFetchingMore, setIsFetchingMore] = useState(false);\n\n const enabled = options?.enabled !== false;\n const unreadOnly = options?.unreadOnly ?? false;\n const limit = options?.limit;\n const pageSize = limit ?? DEFAULT_PAGE_SIZE;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const notificationsRef = useRef<Notification[]>([]);\n notificationsRef.current = notifications;\n\n const seenIdsRef = useRef<Set<string>>(new Set());\n\n // Pagination bookkeeping (in refs so callbacks read fresh values without re-creating).\n const oldestCreatedAtRef = useRef<string | null>(null); // keyset cursor: oldest loaded createdAt\n const boundaryIdsRef = useRef<string[]>([]); // ids already loaded at the cursor timestamp (tie-safe keyset)\n const isFetchingMoreRef = useRef(false); // synchronous guard against overlapping fetchMore calls\n const paginationErroredRef = useRef(false); // set on a fetchMore error; suppresses further fetchMore until a reseed\n const hasMoreRef = useRef(false); // mirror of hasMore for the fetchMore closure\n hasMoreRef.current = hasMore;\n const loadTokenRef = useRef(0); // bumped on every (re)seed; drops stale in-flight fetchMore results\n\n // Invalidate any in-flight fetchMore and clear its transient flags. Called on every (re)seed\n // (receiver/filter change, load effect, refetch) so a stale page never lands and the error gate resets.\n const invalidateInFlightPagination = useCallback(() => {\n loadTokenRef.current += 1;\n isFetchingMoreRef.current = false;\n paginationErroredRef.current = false;\n setIsFetchingMore(false);\n }, []);\n\n // Seed pagination bookkeeping from a fresh first-page list result.\n const seedFromList = useCallback((items: Notification[], totalCount: number) => {\n const oldest = items.length > 0 ? items[items.length - 1].createdAt : null;\n oldestCreatedAtRef.current = oldest;\n boundaryIdsRef.current = idsAt(items, oldest);\n // Initial page has no cursor, so totalCount is the grand total for the filter.\n setHasMore(items.length < totalCount);\n }, []);\n\n // Apply a fresh first-page result: merge any live events that arrived during the load window\n // (present in state but not in the server snapshot) at the head so they aren't dropped, refresh\n // the seen-set, and seed pagination bookkeeping.\n const mergeAndSeed = useCallback(\n (items: Notification[], totalCount: number) => {\n const serverIds = new Set(items.map((n) => n.id));\n // Keep only items strictly NEWER than the snapshot's newest row (and not already in it):\n // those are live events pushed during the load window. Restricting to \"newer than newest\"\n // (not merely \"absent from the snapshot\") is what makes this safe on refetch()/limit change —\n // otherwise the already-loaded OLDER paginated rows would be re-hoisted above the first page.\n // ISO `createdAt` strings sort chronologically, so string `>` is the correct comparison.\n const newestSnapshot = items.length > 0 ? items[0].createdAt : null;\n const liveOnly = notificationsRef.current.filter(\n (n) => !serverIds.has(n.id) && (newestSnapshot === null || n.createdAt > newestSnapshot),\n );\n setNotifications([...liveOnly, ...items]);\n seenIdsRef.current = new Set([...liveOnly.map((n) => n.id), ...items.map((n) => n.id)]);\n seedFromList(items, totalCount);\n },\n [seedFromList],\n );\n\n // Reset local state when the receiver or filter changes (never show the prior query's data)\n useEffect(() => {\n setNotifications([]);\n setLatest(null);\n setUnreadCount(0);\n seenIdsRef.current = new Set();\n oldestCreatedAtRef.current = null;\n boundaryIdsRef.current = [];\n setHasMore(false);\n invalidateInFlightPagination();\n }, [receiverId, unreadOnly, invalidateInFlightPagination]);\n\n const load = useCallback(async () => {\n const [listResult, unread] = await Promise.all([\n client.notifications.list(receiverId, { unreadOnly, first: limit }),\n client.notifications.getUnreadCount(receiverId),\n ]);\n return { listResult, unread };\n }, [client, receiverId, unreadOnly, limit]);\n\n // Data load — re-runs on list params; cancellable so stale results never win\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let active = true;\n // A (re)seed invalidates any in-flight fetchMore.\n invalidateInFlightPagination();\n setIsLoading(true);\n load()\n .then(({ listResult, unread }) => {\n if (!active) return;\n mergeAndSeed(listResult.items, listResult.totalCount);\n setUnreadCount(unread);\n setError(null);\n })\n .catch((err) => {\n if (active) setError(err as ArchieError);\n })\n .finally(() => {\n if (active) setIsLoading(false);\n });\n return () => {\n active = false;\n };\n }, [enabled, load, mergeAndSeed, invalidateInFlightPagination]);\n\n // Live subscription — only re-runs on client/receiverId/enabled, NOT on list params\n useEffect(() => {\n if (!enabled) return;\n const unsubConnection = client.realtime.onConnectionStateChange(setConnectionState);\n setConnectionState(client.realtime.currentState);\n\n const channel = client.notifications.subscribe(receiverId, {\n onError: (err) => setError(err),\n });\n channel.on('*', (notification: Notification) => {\n if (seenIdsRef.current.has(notification.id)) return; // ignore duplicates entirely\n seenIdsRef.current.add(notification.id);\n setNotifications((prev) => [notification, ...prev]);\n setLatest(notification);\n if (!notification.isRead) setUnreadCount((c) => c + 1);\n optionsRef.current?.onNotification?.(notification);\n });\n\n return () => {\n channel.unsubscribe();\n unsubConnection();\n };\n }, [client, receiverId, enabled]);\n\n const markAsRead = useCallback(\n async (id: string) => {\n const wasUnread = notificationsRef.current.find((n) => n.id === id)?.isRead === false;\n try {\n await client.notifications.markAsRead(id);\n setNotifications((prev) =>\n prev.map((n) => (n.id === id && !n.isRead ? { ...n, isRead: true } : n)),\n );\n if (wasUnread) setUnreadCount((c) => Math.max(0, c - 1));\n } catch (err) {\n setError(err as ArchieError);\n throw err;\n }\n },\n [client],\n );\n\n const markAllAsRead = useCallback(async () => {\n try {\n await client.notifications.markAllAsRead(receiverId);\n setNotifications((prev) => prev.map((n) => (n.isRead ? n : { ...n, isRead: true })));\n // Reconcile against the authoritative server count rather than assuming 0\n const count = await client.notifications.getUnreadCount(receiverId);\n setUnreadCount(count);\n } catch (err) {\n setError(err as ArchieError);\n throw err;\n }\n }, [client, receiverId]);\n\n const refetch = useCallback(async () => {\n invalidateInFlightPagination();\n setIsLoading(true);\n try {\n const { listResult, unread } = await load();\n mergeAndSeed(listResult.items, listResult.totalCount);\n setUnreadCount(unread);\n setError(null);\n } catch (err) {\n setError(err as ArchieError);\n } finally {\n setIsLoading(false);\n }\n }, [load, mergeAndSeed, invalidateInFlightPagination]);\n\n const fetchMore = useCallback(async () => {\n if (\n !enabled ||\n !hasMoreRef.current ||\n isFetchingMoreRef.current ||\n paginationErroredRef.current // a prior page errored — wait for refetch()/filter change\n ) {\n return;\n }\n const cursor = oldestCreatedAtRef.current;\n if (cursor == null) return;\n\n const token = loadTokenRef.current;\n isFetchingMoreRef.current = true;\n setIsFetchingMore(true);\n try {\n const page = await client.notifications.list(receiverId, {\n unreadOnly,\n first: pageSize,\n orderBy: { createdAt: 'DESC' },\n createdBefore: cursor,\n // Tie-safe keyset: don't skip rows sharing the cursor timestamp that we haven't loaded yet.\n excludeIds: boundaryIdsRef.current,\n // Page-fill drives hasMore below, so skip the (potentially O(N)) COUNT on deep pages.\n includeTotal: false,\n });\n if (loadTokenRef.current !== token) return; // reseeded mid-flight — drop this page\n if (page.items.length === 0) {\n // Server has no older rows — end of history. Also guards against a no-progress fetch loop.\n setHasMore(false);\n return;\n }\n const fresh = page.items.filter((n) => !seenIdsRef.current.has(n.id));\n fresh.forEach((n) => seenIdsRef.current.add(n.id));\n if (fresh.length > 0) {\n setNotifications((prev) => [...prev, ...fresh]);\n }\n // Advance the keyset cursor to the oldest row in this page, and track the ids at that exact\n // timestamp so the next page's excludeIds skips only what we've loaded — never a tie sibling.\n const newOldest = page.items[page.items.length - 1].createdAt;\n const idsAtNewOldest = idsAt(page.items, newOldest);\n boundaryIdsRef.current =\n newOldest === cursor\n ? Array.from(new Set([...boundaryIdsRef.current, ...idsAtNewOldest]))\n : idsAtNewOldest;\n oldestCreatedAtRef.current = newOldest;\n // Page-fill termination: a full page means more may remain; a short page is the tail.\n setHasMore(page.items.length === pageSize);\n setError(null);\n } catch (err) {\n if (loadTokenRef.current === token) {\n // Gate further fetchMore so a consumer's auto-load effect can't hammer the backend\n // in a tight retry loop; a reseed (refetch/receiver/filter change) clears the gate.\n paginationErroredRef.current = true;\n setError(err as ArchieError);\n }\n } finally {\n if (loadTokenRef.current === token) {\n isFetchingMoreRef.current = false;\n setIsFetchingMore(false);\n }\n }\n }, [client, receiverId, unreadOnly, pageSize, enabled]);\n\n return {\n notifications,\n latest,\n unreadCount,\n isLoading,\n error,\n connectionState,\n markAsRead,\n markAllAsRead,\n refetch,\n fetchMore,\n hasMore,\n isFetchingMore,\n };\n}\n","import React from 'react';\nimport { useAuth } from '../hooks/useAuth';\n\nexport interface AuthGuardProps {\n /** Content to show when authenticated (and authorized if roles specified). */\n children: React.ReactNode;\n /** Content to show when NOT authenticated. */\n fallback?: React.ReactNode;\n /** Content to show while session is loading. */\n loadingComponent?: React.ReactNode;\n /** If specified, user must have at least one of these roles. */\n requiredRoles?: string[];\n}\n\n/**\n * AuthGuard component — conditionally renders children based on auth state.\n *\n * @example\n * ```tsx\n * <AuthGuard fallback={<LoginPage />} requiredRoles={['admin']}>\n * <AdminPanel />\n * </AuthGuard>\n * ```\n */\nexport function AuthGuard({\n children,\n fallback = null,\n loadingComponent = null,\n requiredRoles,\n}: AuthGuardProps) {\n const { user, isLoading, isAuthenticated } = useAuth();\n\n if (isLoading) {\n return React.createElement(React.Fragment, null, loadingComponent);\n }\n\n if (!isAuthenticated || !user) {\n return React.createElement(React.Fragment, null, fallback);\n }\n\n // Check roles if required\n if (requiredRoles && requiredRoles.length > 0) {\n const hasRequiredRole = requiredRoles.some((role) => user.roles.includes(role));\n if (!hasRequiredRole) {\n return React.createElement(React.Fragment, null, fallback);\n }\n }\n\n return React.createElement(React.Fragment, null, children);\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/query-cache.ts","../src/provider.tsx","../src/hooks/useArchieClient.ts","../src/hooks/useAuth.ts","../src/hooks/useQuery.ts","../src/hooks/useMutation.ts","../src/hooks/useSubscription.ts","../src/hooks/useFileUpload.ts","../src/hooks/useRest.ts","../src/hooks/useNotifications.ts","../src/components/AuthGuard.tsx"],"names":["React","useMemo","useState","useCallback","useEffect","useRef"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * In-memory query cache with in-flight request deduplication, stale-while-revalidate\n * and per-key invalidation subscriptions.\n * @internal\n */\n\ninterface CacheEntry<T = unknown> {\n data: T;\n timestamp: number;\n}\n\n/** Called when the entry behind a key is dropped and should be re-fetched. */\nexport type CacheListener = () => void;\n\nexport class QueryCache {\n private cache = new Map<string, CacheEntry>();\n private inflight = new Map<string, Promise<unknown>>();\n private subscribers = new Map<string, Set<CacheListener>>();\n private generations = new Map<string, number>();\n private pending = new Map<string, number>();\n private staleTime = 0;\n\n static key(query: string, variables?: Record<string, unknown>): string {\n return `${query}::${variables ? JSON.stringify(variables) : ''}`;\n }\n\n get<T>(key: string): CacheEntry<T> | undefined {\n return this.cache.get(key) as CacheEntry<T> | undefined;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, timestamp: Date.now() });\n }\n\n isFresh(key: string): boolean {\n const entry = this.cache.get(key);\n if (!entry) return false;\n if (this.staleTime === 0) return false;\n return Date.now() - entry.timestamp < this.staleTime;\n }\n\n /**\n * Deduplicate in-flight requests: if an identical fetch is already pending,\n * return the same promise. Otherwise, run `fetcher` and share the promise.\n */\n async dedup<T>(key: string, fetcher: () => Promise<T>): Promise<T> {\n const existing = this.inflight.get(key);\n if (existing) return existing as Promise<T>;\n\n const promise: Promise<T> = fetcher().finally(() => {\n const remaining = (this.pending.get(key) ?? 1) - 1;\n if (remaining > 0) {\n this.pending.set(key, remaining);\n } else {\n this.pending.delete(key);\n }\n\n // Identity check: an invalidation may have dropped this promise and a newer\n // request may already own the slot — a blind delete would evict the newer one\n // and break deduplication for everyone waiting on it.\n if (this.inflight.get(key) === promise) {\n this.inflight.delete(key);\n }\n });\n\n // Counted separately from the in-flight slot: an invalidation unregisters the\n // slot, but the request it dropped is still on its way back and its result\n // still has to be recognised as stale when it lands.\n this.pending.set(key, (this.pending.get(key) ?? 0) + 1);\n this.inflight.set(key, promise);\n return promise;\n }\n\n getInflight<T>(key: string): Promise<T> | undefined {\n return this.inflight.get(key) as Promise<T> | undefined;\n }\n\n /**\n * Subscribe to invalidations of a single cache key.\n *\n * The listener fires when {@link invalidate} matches this key or {@link clear} runs —\n * never on {@link set}, so a listener that re-fetches (and writes the result back)\n * cannot re-trigger itself.\n *\n * @returns an unsubscribe function; call it on unmount.\n */\n subscribe(key: string, listener: CacheListener): () => void {\n let listeners = this.subscribers.get(key);\n if (!listeners) {\n listeners = new Set();\n this.subscribers.set(key, listeners);\n }\n listeners.add(listener);\n\n return () => {\n const current = this.subscribers.get(key);\n if (!current) return;\n current.delete(listener);\n if (current.size === 0) {\n this.subscribers.delete(key);\n this.pruneGeneration(key);\n }\n };\n }\n\n /**\n * Current generation of a key. It increases every time the key is invalidated,\n * so a caller can capture it before an `await` and check {@link isCurrent}\n * afterwards to find out whether its response was superseded meanwhile.\n *\n * Reading is free of side effects: a generation is only ever recorded for a key\n * something can still compare against — see {@link pruneGeneration}.\n */\n generation(key: string): number {\n return this.generations.get(key) ?? 0;\n }\n\n /** True while `generation` is still the live generation of `key`. */\n isCurrent(key: string, generation: number): boolean {\n return (this.generations.get(key) ?? 0) === generation;\n }\n\n /**\n * Drop every cached entry matching `patterns`, then tell the subscribers on\n * those keys to re-fetch. A key matches when it *contains* any of the patterns.\n *\n * Pass the whole batch in one call (`['user', 'users']`) rather than looping:\n * the affected keys are resolved once, so a key matched by several patterns is\n * invalidated and notified exactly once instead of racing itself.\n *\n * In-flight requests for matching keys are unregistered and the generation of\n * each key is bumped: those requests were issued before the write landed, so\n * neither joining them nor applying their result may hand back stale data.\n *\n * Matching is substring-based, which is deliberately loose — a pattern like\n * `'id'` will match unrelated queries and cost them a refetch. Prefer patterns\n * distinctive enough to name the entity you actually mutated.\n */\n invalidate(patterns: string | string[]): void {\n const list = Array.isArray(patterns) ? patterns : [patterns];\n if (list.length === 0) return;\n\n const matches = (key: string): boolean => list.some((pattern) => key.includes(pattern));\n\n // Resolve the affected keys once, across the maps, so every key is handled a\n // single time no matter how many patterns hit it. Sweeping `generations` costs\n // nothing asymptotically — reading a generation does not record one, so the map\n // only holds live keys plus the odd orphan left by a consumer that unmounted\n // mid-request, and this sweep is exactly where those orphans are dropped.\n const affected = new Set<string>();\n for (const key of this.cache.keys()) if (matches(key)) affected.add(key);\n for (const key of this.inflight.keys()) if (matches(key)) affected.add(key);\n for (const key of this.subscribers.keys()) if (matches(key)) affected.add(key);\n for (const key of this.generations.keys()) if (matches(key)) affected.add(key);\n\n for (const key of affected) {\n this.cache.delete(key);\n this.inflight.delete(key);\n\n // A generation is only worth recording while something can still compare it.\n // For a merely-cached key the entry itself was the whole state, and deleting\n // it is enough — this is also where a key left behind by a consumer that\n // unmounted mid-request is reclaimed.\n if (this.hasHolder(key)) {\n this.bumpGeneration(key);\n } else {\n this.generations.delete(key);\n }\n }\n\n for (const key of affected) {\n this.notify(key);\n }\n }\n\n /**\n * Wipe everything and notify **every** subscriber, so all mounted queries\n * revalidate. That is intentional — a full clear means no key can be trusted —\n * but it does mean calling this on sign-out fires a refetch for every mounted\n * query, which is rarely what you want with a dead token.\n */\n clear(): void {\n // Same rule as invalidate(), and for the same reason: a generation may never\n // move backwards while something can still compare it. Rebuilding the map from\n // scratch would put every pending key back on 1 — precisely what a caller that\n // has lived through one mutation is holding — and its pre-clear response would\n // read as current.\n //\n // Keeping the entry for anything with a holder *narrows* the window where a\n // response that has already settled, but not yet been applied, could still be\n // accepted; it does not close it. A caller whose consumer is already gone and\n // whose pending count has drained takes the delete branch, and a capture of 0\n // then matches the `?? 0` reading. Unreachable through the hooks — useQuery\n // compares immediately after its await, so getting there means chaining onto\n // the internal promise by hand — but the limit is real, and only per-request\n // capture tracking (see pruneGeneration) would remove it.\n const known = new Set([\n ...this.generations.keys(),\n ...this.pending.keys(),\n ...this.subscribers.keys(),\n ]);\n for (const key of known) {\n if (this.hasHolder(key)) {\n this.bumpGeneration(key);\n } else {\n this.generations.delete(key);\n }\n }\n\n this.cache.clear();\n this.inflight.clear();\n\n // Snapshot: a listener may (un)subscribe while being notified.\n for (const key of [...this.subscribers.keys()]) {\n this.notify(key);\n }\n }\n\n private bumpGeneration(key: string): void {\n this.generations.set(key, (this.generations.get(key) ?? 0) + 1);\n }\n\n /**\n * Whether anything can still compare a generation for this key: a mounted\n * consumer that may fetch it, or a request already on its way back.\n */\n private hasHolder(key: string): boolean {\n return this.subscribers.has(key) || (this.pending.get(key) ?? 0) > 0;\n }\n\n /**\n * Forget a key's generation once nothing references it.\n *\n * Pruning is deliberately **not** done when a request settles. A pruned entry\n * reads back as generation 0, which is exactly what a caller that captured 0\n * holds — so a response that was superseded while in flight would be accepted\n * again, and would write pre-mutation data into the cache. The prune therefore\n * happens at the last unsubscribe, and only while nothing is pending.\n *\n * That leaves one bounded remainder, and it is worth naming precisely: if a key\n * has no subscriber left but a request still on its way back, {@link invalidate}\n * or {@link clear} bumps its entry rather than dropping it, and the settle path\n * does not reclaim it. It survives — one entry, holding one key — until some\n * *later* {@link invalidate} matches that key and finds nothing holding it. The\n * two ways in are a consumer that unmounts mid-request and is then invalidated,\n * and a `clear()` (a sign-out, say) fired while requests are in flight, which\n * leaves one entry per key that was still loading. Since patterns match by\n * substring, the next mutation touching that entity reclaims every such remnant\n * at once. Bytes, deliberately traded for the guarantee above.\n */\n private pruneGeneration(key: string): void {\n if (this.hasHolder(key)) return;\n\n this.generations.delete(key);\n }\n\n /** Notify one key's listeners. Iterates a snapshot so listeners may unsubscribe. */\n private notify(key: string): void {\n const listeners = this.subscribers.get(key);\n if (!listeners) return;\n\n for (const listener of [...listeners]) {\n // An earlier listener in this same batch may have unmounted the component\n // this one belongs to; firing it would refetch for a dead subscriber.\n if (!listeners.has(listener)) continue;\n\n try {\n listener();\n } catch {\n // A broken subscriber must not stop the others from revalidating.\n }\n }\n }\n}\n","import React, { createContext, useContext, useEffect, useState, useMemo } from 'react';\nimport type { ArchieClient, Session, AuthEvent } from '@archie/js-sdk';\nimport { QueryCache } from './lib/query-cache';\n\n// ─── Context ──────────────────────────────────────────────────\n\ninterface ArchieContextValue {\n client: ArchieClient;\n session: Session | null;\n isLoading: boolean;\n cache: QueryCache;\n}\n\nexport const ArchieContext = createContext<ArchieContextValue | null>(null);\n\n// ─── Provider ─────────────────────────────────────────────────\n\nexport interface ArchieProviderProps {\n client: ArchieClient;\n children: React.ReactNode;\n /** @internal Inject a custom cache (useful for testing). */\n cache?: QueryCache;\n}\n\n/**\n * ArchieProvider — wraps your React app to provide the Archie client and session state.\n *\n * @example\n * ```tsx\n * import { createClient } from '@archie/js-sdk'\n * import { ArchieProvider } from '@archie/react-sdk'\n *\n * const archie = createClient({ projectId: '...' })\n *\n * function App() {\n * return (\n * <ArchieProvider client={archie}>\n * <MyApp />\n * </ArchieProvider>\n * )\n * }\n * ```\n */\nexport function ArchieProvider({ client, children, cache: injectedCache }: ArchieProviderProps) {\n const [session, setSession] = useState<Session | null>(client.auth.getSession());\n const [isLoading, setIsLoading] = useState(true);\n const defaultCache = useMemo(() => new QueryCache(), [client]);\n const cache = injectedCache ?? defaultCache;\n\n useEffect(() => {\n client.auth.waitForInit().then(() => {\n setSession(client.auth.getSession());\n setIsLoading(false);\n });\n\n const unsubscribe = client.auth.onAuthStateChange(\n (_event: AuthEvent, newSession: Session | null) => {\n setSession(newSession);\n },\n );\n\n return unsubscribe;\n }, [client]);\n\n const value = useMemo<ArchieContextValue>(\n () => ({ client, session, isLoading, cache }),\n [client, session, isLoading, cache],\n );\n\n return React.createElement(ArchieContext.Provider, { value }, children);\n}\n\n/**\n * Internal hook to access the Archie context.\n * @throws if used outside ArchieProvider\n * @internal\n */\nexport function useArchieContext(): ArchieContextValue {\n const context = useContext(ArchieContext);\n if (!context) {\n throw new Error(\n 'useArchieClient must be used within an <ArchieProvider>. ' +\n 'Wrap your app with <ArchieProvider client={archieClient}>.',\n );\n }\n return context;\n}\n","import { useArchieContext } from '../provider';\nimport type { ArchieClient } from '@archie/js-sdk';\n\n/**\n * Returns the ArchieClient instance from context.\n * Must be used within an ArchieProvider.\n *\n * @throws Error if used outside ArchieProvider\n */\nexport function useArchieClient(): ArchieClient {\n const { client } = useArchieContext();\n return client;\n}\n","import { useCallback, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport type {\n User,\n Session,\n AuthSignUpParams,\n AuthSignInParams,\n AuthConfirmParams,\n AuthRecoverParams,\n AuthResetPasswordParams,\n ArchieError,\n} from '@archie/js-sdk';\n\ninterface UseAuthReturn {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n signIn: (\n params: AuthSignInParams,\n ) => Promise<{ session: Session | null; error: ArchieError | null }>;\n signUp: (\n params: AuthSignUpParams,\n ) => Promise<{ data: { userId: string; message: string } | null; error: ArchieError | null }>;\n signOut: () => Promise<void>;\n confirmSignUp: (\n params: AuthConfirmParams,\n ) => Promise<{ session: Session | null; error: ArchieError | null }>;\n recoverPassword: (\n params: AuthRecoverParams,\n ) => Promise<{ data: { message: string } | null; error: ArchieError | null }>;\n resetPassword: (\n params: AuthResetPasswordParams,\n ) => Promise<{ data: { message: string } | null; error: ArchieError | null }>;\n refreshSession: () => Promise<{ session: Session | null; error: ArchieError | null }>;\n}\n\n/**\n * Hook for authentication state and operations.\n * All methods return `{ data/session, error }` (never throws).\n */\nexport function useAuth(): UseAuthReturn {\n const { client, session, isLoading } = useArchieContext();\n\n const signIn = useCallback(\n async (params: AuthSignInParams) => {\n try {\n const result = await client.auth.signIn(params);\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const signUp = useCallback(\n async (params: AuthSignUpParams) => {\n try {\n const result = await client.auth.signUp(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const signOut = useCallback(async () => {\n await client.auth.signOut();\n }, [client]);\n\n const confirmSignUp = useCallback(\n async (params: AuthConfirmParams) => {\n try {\n const result = await client.auth.confirmSignUp(params);\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const recoverPassword = useCallback(\n async (params: AuthRecoverParams) => {\n try {\n const result = await client.auth.recoverPassword(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const resetPassword = useCallback(\n async (params: AuthResetPasswordParams) => {\n try {\n const result = await client.auth.resetPassword(params);\n return { data: result, error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n },\n [client],\n );\n\n const refreshSession = useCallback(async () => {\n try {\n const result = await client.auth.refreshSession();\n return { session: result.session, error: null };\n } catch (err) {\n return { session: null, error: err as ArchieError };\n }\n }, [client]);\n\n return useMemo(\n () => ({\n user: session?.user ?? null,\n session,\n isLoading,\n isAuthenticated: session !== null,\n signIn,\n signUp,\n signOut,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n }),\n [\n session,\n isLoading,\n signIn,\n signUp,\n signOut,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n ],\n );\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport { QueryCache } from '../lib/query-cache';\nimport type { ArchieError } from '@archie/js-sdk';\n\ninterface UseQueryOptions<T> {\n enabled?: boolean;\n refetchInterval?: number;\n refetchOnWindowFocus?: boolean;\n onSuccess?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n}\n\ninterface UseQueryReturn<T> {\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n isRefetching: boolean;\n refetch: () => Promise<void>;\n}\n\n/**\n * Declarative GraphQL query hook with caching and stale-while-revalidate.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuery<{ users: User[] }>(\n * 'query { users { id email name } }',\n * { limit: 10 }\n * )\n * ```\n */\nexport function useQuery<T = unknown>(\n gql: string,\n variables?: Record<string, unknown>,\n options?: UseQueryOptions<T>,\n): UseQueryReturn<T> {\n const { client, session, cache } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefetching, setIsRefetching] = useState(false);\n\n const enabled = options?.enabled !== false;\n\n const variablesKey = variables ? JSON.stringify(variables) : '';\n const cacheKey = QueryCache.key(gql, variables);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n /** How many fetches this hook currently has in flight. */\n const activeFetches = useRef(0);\n\n const fetchData = useCallback(\n async (isRefetch = false) => {\n if (!enabled) return;\n\n if (isRefetch) {\n setIsRefetching(true);\n } else {\n setIsLoading(true);\n }\n activeFetches.current += 1;\n\n // Captured before the await: if this key is invalidated while the request is\n // in flight, the response predates the write that invalidated it. Applying it\n // would repaint the UI — and poison the cache — with pre-mutation data, which\n // is the very bug this hook is supposed to fix.\n const generation = cache.generation(cacheKey);\n\n try {\n const result = await cache.dedup(cacheKey, () => client.graphql.query<T>(gql, variables));\n if (!cache.isCurrent(cacheKey, generation)) return;\n\n if (result.error) {\n setError(result.error);\n // On a revalidation, keep whatever is on screen: a transient failure\n // after a successful mutation must not blank the view.\n if (!isRefetch) setData(null);\n optionsRef.current?.onError?.(result.error);\n } else {\n setData(result.data);\n setError(null);\n cache.set(cacheKey, result.data);\n optionsRef.current?.onSuccess?.(result.data as T);\n }\n } catch (err) {\n if (!cache.isCurrent(cacheKey, generation)) return;\n setError(err as ArchieError);\n if (!isRefetch) setData(null);\n } finally {\n // The flags are this hook's own state, not the key's, so what releases them\n // has to be hook-local too. Counting this hook's own fetches gets both ends\n // right: a superseded response whose replacement is already running leaves\n // the spinner alone (the replacement owns it), while one with no\n // replacement — the consumer was gated off before the invalidation, so the\n // notification reached nobody — still releases it instead of stranding it.\n activeFetches.current -= 1;\n if (activeFetches.current === 0) {\n setIsLoading(false);\n setIsRefetching(false);\n }\n }\n },\n [client, gql, variablesKey, enabled, cacheKey, cache],\n );\n\n // Initial fetch & refetch on variable change\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n\n const cached = cache.get<T>(cacheKey);\n if (cached) {\n setData(cached.data);\n setIsLoading(false);\n fetchData(true);\n } else {\n fetchData(false);\n }\n }, [cacheKey, enabled]);\n\n // Revalidate when this key is invalidated (e.g. by useMutation's invalidateQueries).\n // `fetchData` is read through a ref so option changes never re-subscribe, and the\n // refetch itself goes through `cache.dedup`, so N mounted consumers of the same key\n // collapse into a single request instead of a refetch storm.\n const fetchDataRef = useRef(fetchData);\n fetchDataRef.current = fetchData;\n\n useEffect(() => {\n if (!enabled) return;\n return cache.subscribe(cacheKey, () => {\n fetchDataRef.current(true);\n });\n }, [cacheKey, enabled, cache]);\n\n // Refetch on auth state change (new token)\n const prevSessionRef = useRef(session?.accessToken);\n useEffect(() => {\n if (\n enabled &&\n prevSessionRef.current !== session?.accessToken &&\n prevSessionRef.current !== undefined\n ) {\n fetchData(true);\n }\n prevSessionRef.current = session?.accessToken;\n }, [session?.accessToken, enabled]);\n\n // Polling (refetchInterval)\n useEffect(() => {\n if (!enabled || !options?.refetchInterval) return;\n\n const interval = setInterval(() => {\n fetchData(true);\n }, options.refetchInterval);\n\n return () => clearInterval(interval);\n }, [enabled, options?.refetchInterval]);\n\n // Refetch on window focus\n useEffect(() => {\n if (!enabled || !options?.refetchOnWindowFocus) return;\n if (typeof window === 'undefined') return;\n\n const handleFocus = () => fetchData(true);\n window.addEventListener('focus', handleFocus);\n return () => window.removeEventListener('focus', handleFocus);\n }, [enabled, options?.refetchOnWindowFocus]);\n\n const refetch = useCallback(() => fetchData(true), [fetchData]);\n\n return { data, error, isLoading, isRefetching, refetch };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError } from '@archie/js-sdk';\n\ninterface UseMutationOptions<T> {\n onSuccess?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n onSettled?: () => void;\n /** Query substrings to invalidate (forcing refetch) after a successful mutation. */\n invalidateQueries?: string[];\n}\n\ninterface UseMutationReturn<T> {\n mutate: (variables?: Record<string, unknown>) => void;\n mutateAsync: (variables?: Record<string, unknown>) => Promise<T | null>;\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n reset: () => void;\n}\n\n/**\n * Hook for GraphQL mutations.\n *\n * @example\n * ```tsx\n * const { mutate, isLoading } = useMutation<{ createUser: User }>(\n * 'mutation($data: CreateUserInput!) { createUser(data: $data) { id email } }',\n * { invalidateQueries: ['users'] }\n * )\n *\n * mutate({ data: { email: 'new@user.com', name: 'John' } })\n * ```\n */\nexport function useMutation<T = unknown>(\n gql: string,\n options?: UseMutationOptions<T>,\n): UseMutationReturn<T> {\n const { client, cache } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const execute = useCallback(\n async (variables?: Record<string, unknown>): Promise<T | null> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await client.graphql.mutate<T>(gql, variables);\n\n if (result.error) {\n setError(result.error);\n setData(null);\n optionsRef.current?.onError?.(result.error);\n optionsRef.current?.onSettled?.();\n return null;\n }\n\n setData(result.data);\n setError(null);\n optionsRef.current?.onSuccess?.(result.data as T);\n\n const invalidateQueries = optionsRef.current?.invalidateQueries;\n if (invalidateQueries?.length) {\n // One batched call, not one per entry: overlapping substrings such as\n // ['user', 'users'] hit the same key, and invalidating them separately\n // would kill the first refetch's in-flight request and issue a second.\n cache.invalidate(invalidateQueries);\n }\n\n optionsRef.current?.onSettled?.();\n return result.data;\n } catch (err) {\n const archieErr = err as ArchieError;\n setError(archieErr);\n setData(null);\n optionsRef.current?.onError?.(archieErr);\n optionsRef.current?.onSettled?.();\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client, gql, cache],\n );\n\n const mutate = useCallback(\n (variables?: Record<string, unknown>) => {\n execute(variables);\n },\n [execute],\n );\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return { mutate, mutateAsync: execute, data, error, isLoading, reset };\n}\n","import { useState, useEffect, useRef } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, ConnectionState } from '@archie/js-sdk';\n\ninterface UseSubscriptionOptions<T> {\n enabled?: boolean;\n onData?: (data: T) => void;\n onError?: (error: ArchieError) => void;\n}\n\ninterface UseSubscriptionReturn<T> {\n data: T | null;\n error: ArchieError | null;\n connectionState: ConnectionState;\n}\n\n/**\n * Hook for real-time GraphQL subscriptions.\n * Subscribes on mount, unsubscribes on unmount.\n *\n * @example\n * ```tsx\n * const { data } = useSubscription<{ orderUpdated: Order }>(\n * 'subscription { orderUpdated { id status total } }'\n * )\n * ```\n */\nexport function useSubscription<T = unknown>(\n gql: string,\n variables?: Record<string, unknown>,\n options?: UseSubscriptionOptions<T>,\n): UseSubscriptionReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>('DISCONNECTED');\n\n const enabled = options?.enabled !== false;\n const variablesKey = variables ? JSON.stringify(variables) : '';\n\n // Track latest callbacks to avoid stale closures\n const callbacksRef = useRef(options);\n callbacksRef.current = options;\n\n useEffect(() => {\n if (!enabled) return;\n\n const unsub = client.realtime.onConnectionStateChange(setConnectionState);\n\n const subscription = client.realtime.subscribe<T>(gql, variables, {\n onData: (newData: T) => {\n setData(newData);\n setError(null);\n callbacksRef.current?.onData?.(newData);\n },\n onError: (err) => {\n setError(err);\n callbacksRef.current?.onError?.(err);\n },\n onComplete: () => {\n // Subscription completed server-side\n },\n });\n\n return () => {\n subscription.unsubscribe();\n unsub();\n };\n }, [client, gql, variablesKey, enabled]);\n\n return { data, error, connectionState };\n}\n","import { useState, useCallback } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, FileUploadOptions, FileUploadResult } from '@archie/js-sdk';\n\ninterface UseFileUploadReturn {\n upload: (file: File | Blob, options?: FileUploadOptions) => Promise<void>;\n progress: number;\n isUploading: boolean;\n data: FileUploadResult | null;\n error: ArchieError | null;\n reset: () => void;\n}\n\n/**\n * Hook for file uploads.\n *\n * @example\n * ```tsx\n * const { upload, isUploading, data } = useFileUpload()\n *\n * <input type=\"file\" onChange={(e) => upload(e.target.files[0])} />\n * {isUploading && <Spinner />}\n * ```\n */\nexport function useFileUpload(): UseFileUploadReturn {\n const { client } = useArchieContext();\n const [progress, setProgress] = useState(0);\n const [isUploading, setIsUploading] = useState(false);\n const [data, setData] = useState<FileUploadResult | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n\n const upload = useCallback(\n async (file: File | Blob, options?: FileUploadOptions) => {\n setIsUploading(true);\n setProgress(0);\n setError(null);\n setData(null);\n\n try {\n const result = await client.files.upload(file, options);\n\n setData(result);\n setProgress(100);\n } catch (err) {\n setError(err as ArchieError);\n } finally {\n setIsUploading(false);\n }\n },\n [client],\n );\n\n const reset = useCallback(() => {\n setProgress(0);\n setIsUploading(false);\n setData(null);\n setError(null);\n }, []);\n\n return { upload, progress, isUploading, data, error, reset };\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, RestRequestOptions, IRestModule } from '@archie/js-sdk';\n\n// ─── useRest (base) ──────────────────────────────────────────\n\n/**\n * Returns the REST module from the Archie client.\n * Provides direct access to `get`, `post`, `put`, `patch`, `delete`.\n *\n * @example\n * ```tsx\n * const rest = useRest()\n * const data = await rest.get('/api/products')\n * await rest.post('/api/products', { name: 'Widget' })\n * ```\n */\nexport function useRest(): IRestModule {\n const { client } = useArchieContext();\n return useMemo(() => client.rest, [client]);\n}\n\n// ─── useRestQuery ─────────────────────────────────────────────\n\ninterface UseRestQueryReturn<T> {\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n refetch: () => Promise<void>;\n}\n\n/**\n * Declarative hook for GET requests to custom REST APIs.\n */\nexport function useRestQuery<T = unknown>(\n path: string,\n options?: RestRequestOptions & { enabled?: boolean },\n): UseRestQueryReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n const enabled = options?.enabled !== false;\n\n const fetchData = useCallback(async () => {\n if (!enabled) return;\n setIsLoading(true);\n\n try {\n const result = await client.rest.get<T>(path, options);\n setData(result);\n setError(null);\n } catch (err) {\n setError(err as ArchieError);\n setData(null);\n } finally {\n setIsLoading(false);\n }\n }, [client, path, enabled]);\n\n useEffect(() => {\n if (enabled) {\n fetchData();\n } else {\n setIsLoading(false);\n }\n }, [fetchData, enabled]);\n\n return { data, error, isLoading, refetch: fetchData };\n}\n\n// ─── useRestMutation ──────────────────────────────────────────\n\ninterface UseRestMutationReturn<T> {\n execute: (body?: unknown, overrideOptions?: RestRequestOptions) => Promise<T | null>;\n data: T | null;\n error: ArchieError | null;\n isLoading: boolean;\n reset: () => void;\n}\n\n/**\n * Imperative hook for POST/PUT/PATCH/DELETE requests to custom REST APIs.\n */\nexport function useRestMutation<T = unknown>(\n path: string,\n method: 'POST' | 'PUT' | 'PATCH' | 'DELETE' = 'POST',\n): UseRestMutationReturn<T> {\n const { client } = useArchieContext();\n const [data, setData] = useState<T | null>(null);\n const [error, setError] = useState<ArchieError | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const execute = useCallback(\n async (body?: unknown, overrideOptions?: RestRequestOptions): Promise<T | null> => {\n setIsLoading(true);\n setError(null);\n\n try {\n let result: T;\n switch (method) {\n case 'POST':\n result = await client.rest.post<T>(path, body, overrideOptions);\n break;\n case 'PUT':\n result = await client.rest.put<T>(path, body, overrideOptions);\n break;\n case 'PATCH':\n result = await client.rest.patch<T>(path, body, overrideOptions);\n break;\n case 'DELETE':\n result = await client.rest.delete<T>(path, overrideOptions);\n break;\n }\n\n setData(result);\n setError(null);\n return result;\n } catch (err) {\n const archieErr = err as ArchieError;\n setError(archieErr);\n setData(null);\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client, path, method],\n );\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return { execute, data, error, isLoading, reset };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { useArchieContext } from '../provider';\nimport type { ArchieError, ConnectionState, Notification } from '@archie/js-sdk';\n\nexport interface UseNotificationsOptions {\n enabled?: boolean;\n unreadOnly?: boolean;\n /**\n * Page size. Applies to `fetchMore()` (older pages); when omitted, `fetchMore` uses 20.\n * It also caps the initial load (`first: limit`) — so omitting it lets the backend choose the\n * initial page size, meaning the first page and subsequent `fetchMore` pages may differ in size.\n */\n limit?: number;\n onNotification?: (notification: Notification) => void;\n}\n\nexport interface UseNotificationsReturn {\n notifications: Notification[];\n latest: Notification | null;\n unreadCount: number;\n isLoading: boolean;\n error: ArchieError | null;\n connectionState: ConnectionState;\n markAsRead: (id: string) => Promise<void>;\n markAllAsRead: () => Promise<void>;\n refetch: () => Promise<void>;\n /**\n * Load the next older page of history. No-op if `!hasMore`, a fetch is already in flight,\n * disabled, or a previous `fetchMore` errored (call `refetch()` or change the filter to retry).\n */\n fetchMore: () => Promise<void>;\n /** True while more older history exists for the active filter (the last page did not exhaust it). */\n hasMore: boolean;\n /** True while a fetchMore() call is in flight (drives a \"loading older\" indicator). */\n isFetchingMore: boolean;\n}\n\n/** Default page size for fetchMore() when no `limit` is provided. Initial load is unaffected. */\nconst DEFAULT_PAGE_SIZE = 20;\n\n/** Ids of the items whose `createdAt` equals `ts` — the tie-group at a keyset boundary. */\nfunction idsAt(items: Notification[], ts: string | null): string[] {\n if (ts == null) return [];\n return items.filter((n) => n.createdAt === ts).map((n) => n.id);\n}\n\n/**\n * Subscribe to a user's in-app notifications: loads the existing list,\n * then streams new ones live, and pages backward through history via fetchMore().\n * Returns idiomatic React state.\n *\n * @example\n * ```tsx\n * const { notifications, unreadCount, fetchMore, hasMore, isFetchingMore } =\n * useNotifications(user.id, { limit: 20 });\n * ```\n */\nexport function useNotifications(\n receiverId: string,\n options?: UseNotificationsOptions,\n): UseNotificationsReturn {\n const { client } = useArchieContext();\n const [notifications, setNotifications] = useState<Notification[]>([]);\n const [latest, setLatest] = useState<Notification | null>(null);\n const [unreadCount, setUnreadCount] = useState(0);\n const [isLoading, setIsLoading] = useState(options?.enabled !== false);\n const [error, setError] = useState<ArchieError | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>(\n () => client.realtime.currentState,\n );\n const [hasMore, setHasMore] = useState(false);\n const [isFetchingMore, setIsFetchingMore] = useState(false);\n\n const enabled = options?.enabled !== false;\n const unreadOnly = options?.unreadOnly ?? false;\n const limit = options?.limit;\n const pageSize = limit ?? DEFAULT_PAGE_SIZE;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const notificationsRef = useRef<Notification[]>([]);\n notificationsRef.current = notifications;\n\n const seenIdsRef = useRef<Set<string>>(new Set());\n\n // Pagination bookkeeping (in refs so callbacks read fresh values without re-creating).\n const oldestCreatedAtRef = useRef<string | null>(null); // keyset cursor: oldest loaded createdAt\n const boundaryIdsRef = useRef<string[]>([]); // ids already loaded at the cursor timestamp (tie-safe keyset)\n const isFetchingMoreRef = useRef(false); // synchronous guard against overlapping fetchMore calls\n const paginationErroredRef = useRef(false); // set on a fetchMore error; suppresses further fetchMore until a reseed\n const hasMoreRef = useRef(false); // mirror of hasMore for the fetchMore closure\n hasMoreRef.current = hasMore;\n const loadTokenRef = useRef(0); // bumped on every (re)seed; drops stale in-flight fetchMore results\n\n // Invalidate any in-flight fetchMore and clear its transient flags. Called on every (re)seed\n // (receiver/filter change, load effect, refetch) so a stale page never lands and the error gate resets.\n const invalidateInFlightPagination = useCallback(() => {\n loadTokenRef.current += 1;\n isFetchingMoreRef.current = false;\n paginationErroredRef.current = false;\n setIsFetchingMore(false);\n }, []);\n\n // Seed pagination bookkeeping from a fresh first-page list result.\n const seedFromList = useCallback((items: Notification[], totalCount: number) => {\n const oldest = items.length > 0 ? items[items.length - 1].createdAt : null;\n oldestCreatedAtRef.current = oldest;\n boundaryIdsRef.current = idsAt(items, oldest);\n // Initial page has no cursor, so totalCount is the grand total for the filter.\n setHasMore(items.length < totalCount);\n }, []);\n\n // Apply a fresh first-page result: merge any live events that arrived during the load window\n // (present in state but not in the server snapshot) at the head so they aren't dropped, refresh\n // the seen-set, and seed pagination bookkeeping.\n const mergeAndSeed = useCallback(\n (items: Notification[], totalCount: number) => {\n const serverIds = new Set(items.map((n) => n.id));\n // Keep only items strictly NEWER than the snapshot's newest row (and not already in it):\n // those are live events pushed during the load window. Restricting to \"newer than newest\"\n // (not merely \"absent from the snapshot\") is what makes this safe on refetch()/limit change —\n // otherwise the already-loaded OLDER paginated rows would be re-hoisted above the first page.\n // ISO `createdAt` strings sort chronologically, so string `>` is the correct comparison.\n const newestSnapshot = items.length > 0 ? items[0].createdAt : null;\n const liveOnly = notificationsRef.current.filter(\n (n) => !serverIds.has(n.id) && (newestSnapshot === null || n.createdAt > newestSnapshot),\n );\n setNotifications([...liveOnly, ...items]);\n seenIdsRef.current = new Set([...liveOnly.map((n) => n.id), ...items.map((n) => n.id)]);\n seedFromList(items, totalCount);\n },\n [seedFromList],\n );\n\n // Reset local state when the receiver or filter changes (never show the prior query's data)\n useEffect(() => {\n setNotifications([]);\n setLatest(null);\n setUnreadCount(0);\n seenIdsRef.current = new Set();\n oldestCreatedAtRef.current = null;\n boundaryIdsRef.current = [];\n setHasMore(false);\n invalidateInFlightPagination();\n }, [receiverId, unreadOnly, invalidateInFlightPagination]);\n\n const load = useCallback(async () => {\n const [listResult, unread] = await Promise.all([\n client.notifications.list(receiverId, { unreadOnly, first: limit }),\n client.notifications.getUnreadCount(receiverId),\n ]);\n return { listResult, unread };\n }, [client, receiverId, unreadOnly, limit]);\n\n // Data load — re-runs on list params; cancellable so stale results never win\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let active = true;\n // A (re)seed invalidates any in-flight fetchMore.\n invalidateInFlightPagination();\n setIsLoading(true);\n load()\n .then(({ listResult, unread }) => {\n if (!active) return;\n mergeAndSeed(listResult.items, listResult.totalCount);\n setUnreadCount(unread);\n setError(null);\n })\n .catch((err) => {\n if (active) setError(err as ArchieError);\n })\n .finally(() => {\n if (active) setIsLoading(false);\n });\n return () => {\n active = false;\n };\n }, [enabled, load, mergeAndSeed, invalidateInFlightPagination]);\n\n // Live subscription — only re-runs on client/receiverId/enabled, NOT on list params\n useEffect(() => {\n if (!enabled) return;\n const unsubConnection = client.realtime.onConnectionStateChange(setConnectionState);\n setConnectionState(client.realtime.currentState);\n\n const channel = client.notifications.subscribe(receiverId, {\n onError: (err) => setError(err),\n });\n channel.on('*', (notification: Notification) => {\n if (seenIdsRef.current.has(notification.id)) return; // ignore duplicates entirely\n seenIdsRef.current.add(notification.id);\n setNotifications((prev) => [notification, ...prev]);\n setLatest(notification);\n if (!notification.isRead) setUnreadCount((c) => c + 1);\n optionsRef.current?.onNotification?.(notification);\n });\n\n return () => {\n channel.unsubscribe();\n unsubConnection();\n };\n }, [client, receiverId, enabled]);\n\n const markAsRead = useCallback(\n async (id: string) => {\n const wasUnread = notificationsRef.current.find((n) => n.id === id)?.isRead === false;\n try {\n await client.notifications.markAsRead(id);\n setNotifications((prev) =>\n prev.map((n) => (n.id === id && !n.isRead ? { ...n, isRead: true } : n)),\n );\n if (wasUnread) setUnreadCount((c) => Math.max(0, c - 1));\n } catch (err) {\n setError(err as ArchieError);\n throw err;\n }\n },\n [client],\n );\n\n const markAllAsRead = useCallback(async () => {\n try {\n await client.notifications.markAllAsRead(receiverId);\n setNotifications((prev) => prev.map((n) => (n.isRead ? n : { ...n, isRead: true })));\n // Reconcile against the authoritative server count rather than assuming 0\n const count = await client.notifications.getUnreadCount(receiverId);\n setUnreadCount(count);\n } catch (err) {\n setError(err as ArchieError);\n throw err;\n }\n }, [client, receiverId]);\n\n const refetch = useCallback(async () => {\n invalidateInFlightPagination();\n setIsLoading(true);\n try {\n const { listResult, unread } = await load();\n mergeAndSeed(listResult.items, listResult.totalCount);\n setUnreadCount(unread);\n setError(null);\n } catch (err) {\n setError(err as ArchieError);\n } finally {\n setIsLoading(false);\n }\n }, [load, mergeAndSeed, invalidateInFlightPagination]);\n\n const fetchMore = useCallback(async () => {\n if (\n !enabled ||\n !hasMoreRef.current ||\n isFetchingMoreRef.current ||\n paginationErroredRef.current // a prior page errored — wait for refetch()/filter change\n ) {\n return;\n }\n const cursor = oldestCreatedAtRef.current;\n if (cursor == null) return;\n\n const token = loadTokenRef.current;\n isFetchingMoreRef.current = true;\n setIsFetchingMore(true);\n try {\n const page = await client.notifications.list(receiverId, {\n unreadOnly,\n first: pageSize,\n orderBy: { createdAt: 'DESC' },\n createdBefore: cursor,\n // Tie-safe keyset: don't skip rows sharing the cursor timestamp that we haven't loaded yet.\n excludeIds: boundaryIdsRef.current,\n // Page-fill drives hasMore below, so skip the (potentially O(N)) COUNT on deep pages.\n includeTotal: false,\n });\n if (loadTokenRef.current !== token) return; // reseeded mid-flight — drop this page\n if (page.items.length === 0) {\n // Server has no older rows — end of history. Also guards against a no-progress fetch loop.\n setHasMore(false);\n return;\n }\n const fresh = page.items.filter((n) => !seenIdsRef.current.has(n.id));\n fresh.forEach((n) => seenIdsRef.current.add(n.id));\n if (fresh.length > 0) {\n setNotifications((prev) => [...prev, ...fresh]);\n }\n // Advance the keyset cursor to the oldest row in this page, and track the ids at that exact\n // timestamp so the next page's excludeIds skips only what we've loaded — never a tie sibling.\n const newOldest = page.items[page.items.length - 1].createdAt;\n const idsAtNewOldest = idsAt(page.items, newOldest);\n boundaryIdsRef.current =\n newOldest === cursor\n ? Array.from(new Set([...boundaryIdsRef.current, ...idsAtNewOldest]))\n : idsAtNewOldest;\n oldestCreatedAtRef.current = newOldest;\n // Page-fill termination: a full page means more may remain; a short page is the tail.\n setHasMore(page.items.length === pageSize);\n setError(null);\n } catch (err) {\n if (loadTokenRef.current === token) {\n // Gate further fetchMore so a consumer's auto-load effect can't hammer the backend\n // in a tight retry loop; a reseed (refetch/receiver/filter change) clears the gate.\n paginationErroredRef.current = true;\n setError(err as ArchieError);\n }\n } finally {\n if (loadTokenRef.current === token) {\n isFetchingMoreRef.current = false;\n setIsFetchingMore(false);\n }\n }\n }, [client, receiverId, unreadOnly, pageSize, enabled]);\n\n return {\n notifications,\n latest,\n unreadCount,\n isLoading,\n error,\n connectionState,\n markAsRead,\n markAllAsRead,\n refetch,\n fetchMore,\n hasMore,\n isFetchingMore,\n };\n}\n","import React from 'react';\nimport { useAuth } from '../hooks/useAuth';\n\nexport interface AuthGuardProps {\n /** Content to show when authenticated (and authorized if roles specified). */\n children: React.ReactNode;\n /** Content to show when NOT authenticated. */\n fallback?: React.ReactNode;\n /** Content to show while session is loading. */\n loadingComponent?: React.ReactNode;\n /** If specified, user must have at least one of these roles. */\n requiredRoles?: string[];\n}\n\n/**\n * AuthGuard component — conditionally renders children based on auth state.\n *\n * @example\n * ```tsx\n * <AuthGuard fallback={<LoginPage />} requiredRoles={['admin']}>\n * <AdminPanel />\n * </AuthGuard>\n * ```\n */\nexport function AuthGuard({\n children,\n fallback = null,\n loadingComponent = null,\n requiredRoles,\n}: AuthGuardProps) {\n const { user, isLoading, isAuthenticated } = useAuth();\n\n if (isLoading) {\n return React.createElement(React.Fragment, null, loadingComponent);\n }\n\n if (!isAuthenticated || !user) {\n return React.createElement(React.Fragment, null, fallback);\n }\n\n // Check roles if required\n if (requiredRoles && requiredRoles.length > 0) {\n const hasRequiredRole = requiredRoles.some((role) => user.roles.includes(role));\n if (!hasRequiredRole) {\n return React.createElement(React.Fragment, null, fallback);\n }\n }\n\n return React.createElement(React.Fragment, null, children);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/react-sdk",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Archie BAAS - React hooks, provider & components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "peerDependencies": {
22
22
  "react": ">=18.0.0",
23
- "@archie/js-sdk": "0.3.1"
23
+ "@archie/js-sdk": "0.3.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "react": "^19.0.0",
@@ -32,7 +32,7 @@
32
32
  "@testing-library/react": "^16.0.0",
33
33
  "@testing-library/jest-dom": "^6.0.0",
34
34
  "jsdom": "^25.0.0",
35
- "@archie/js-sdk": "0.3.1"
35
+ "@archie/js-sdk": "0.3.2"
36
36
  },
37
37
  "sideEffects": false,
38
38
  "keywords": [