@archie/react-sdk 0.4.2 → 0.5.1

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
@@ -411,16 +411,16 @@ const { upload, progress, isUploading, data, error, reset } = useFileUpload();
411
411
 
412
412
  **Return:**
413
413
 
414
- | Field | Type | Description |
415
- | ------------- | ----------------------------------------------------------------- | ---------------------------- |
416
- | `upload` | `(file: File \| Blob, opts?: FileUploadOptions) => Promise<void>` | Start upload |
417
- | `progress` | `number` | 0–100 |
418
- | `isUploading` | `boolean` | True while uploading |
419
- | `data` | `FileUploadResult \| null` | `{ url, fileId }` on success |
420
- | `error` | `ArchieError \| null` | Error if failed |
421
- | `reset` | `() => void` | Clear all state |
414
+ | Field | Type | Description |
415
+ | ------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
416
+ | `upload` | `(file: File \| Blob, opts?: FileUploadOptions) => Promise<void>` | Start upload |
417
+ | `progress` | `number` | 0–100 |
418
+ | `isUploading` | `boolean` | True while uploading |
419
+ | `data` | `FileUploadResult \| null` | `{ fileId, url, filename, mimetype, size }` on success (`url` is `null` if the lookup failed) |
420
+ | `error` | `ArchieError \| null` | Error if failed |
421
+ | `reset` | `() => void` | Clear all state |
422
422
 
423
- `FileUploadOptions`: `{ filename?, contentType?, providerType?, onProgress? }`
423
+ `FileUploadOptions`: `{ filename?, contentType?, providerType? }` (filename and contentType default to the `File`'s; a plain `Blob` without a type needs `contentType`). Progress is coarse (0 then 100) until the XHR transport lands in 0.4.4.
424
424
 
425
425
  **Example:**
426
426
 
@@ -438,7 +438,7 @@ function FileUploader() {
438
438
  }}
439
439
  />
440
440
  {isUploading && <ProgressBar value={progress} />}
441
- {data && <p>Uploaded: {data.url}</p>}
441
+ {data && <p>Uploaded: {data.url ?? data.fileId}</p>}
442
442
  {error && <p className="error">{error.message}</p>}
443
443
  {data && <button onClick={reset}>Upload Another</button>}
444
444
  </div>
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { ArchieClient, Session, User, AuthSignInParams, ArchieError, AuthSignUpParams, AuthExchangeCodeParams, AuthConfirmParams, AuthRecoverParams, AuthResetPasswordParams, ConnectionState, FileUploadOptions, FileUploadResult, IRestModule, RestRequestOptions, Notification } from '@archie/js-sdk';
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, safeActionUrl } from '@archie/js-sdk';
2
+ import { ArchieClient, Session, User, AuthSignInParams, ArchieError, AuthSignUpParams, AuthExchangeCodeParams, ActiveSession, AuthConfirmParams, AuthRecoverParams, AuthResetPasswordParams, ConnectionState, FileUploadOptions, FileUploadResult, IRestModule, RestRequestOptions, Notification } from '@archie/js-sdk';
3
+ export { ActiveSession, 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, safeActionUrl } from '@archie/js-sdk';
4
4
 
5
5
  /**
6
6
  * In-memory query cache with in-flight request deduplication, stale-while-revalidate
@@ -171,7 +171,21 @@ interface UseAuthReturn {
171
171
  session: Session | null;
172
172
  error: ArchieError | null;
173
173
  }>;
174
+ /** Sign out of this device only. Never throws. */
174
175
  signOut: () => Promise<void>;
176
+ /** Sign out of every device; the local session is always cleared. */
177
+ signOutEverywhere: () => Promise<{
178
+ revoked: boolean;
179
+ }>;
180
+ /** Active sessions (devices); `error.code === 'SESSIONS_UNSUPPORTED'` on older identity. */
181
+ listSessions: () => Promise<{
182
+ data: ActiveSession[] | null;
183
+ error: ArchieError | null;
184
+ }>;
185
+ /** End one session by id. */
186
+ revokeSession: (sessionId: string) => Promise<{
187
+ error: ArchieError | null;
188
+ }>;
175
189
  confirmSignUp: (params: AuthConfirmParams) => Promise<{
176
190
  session: Session | null;
177
191
  error: ArchieError | null;
package/dist/index.js CHANGED
@@ -282,6 +282,25 @@ function useAuth() {
282
282
  const signOut = useCallback(async () => {
283
283
  await client.auth.signOut();
284
284
  }, [client]);
285
+ const signOutEverywhere = useCallback(() => client.auth.signOutEverywhere(), [client]);
286
+ const listSessions = useCallback(async () => {
287
+ try {
288
+ return { data: await client.auth.listSessions(), error: null };
289
+ } catch (err) {
290
+ return { data: null, error: err };
291
+ }
292
+ }, [client]);
293
+ const revokeSession = useCallback(
294
+ async (sessionId) => {
295
+ try {
296
+ await client.auth.revokeSession(sessionId);
297
+ return { error: null };
298
+ } catch (err) {
299
+ return { error: err };
300
+ }
301
+ },
302
+ [client]
303
+ );
285
304
  const confirmSignUp = useCallback(
286
305
  async (params) => {
287
306
  try {
@@ -333,6 +352,9 @@ function useAuth() {
333
352
  signUp,
334
353
  exchangeCode,
335
354
  signOut,
355
+ signOutEverywhere,
356
+ listSessions,
357
+ revokeSession,
336
358
  confirmSignUp,
337
359
  recoverPassword,
338
360
  resetPassword,
@@ -345,6 +367,9 @@ function useAuth() {
345
367
  signUp,
346
368
  exchangeCode,
347
369
  signOut,
370
+ signOutEverywhere,
371
+ listSessions,
372
+ revokeSession,
348
373
  confirmSignUp,
349
374
  recoverPassword,
350
375
  resetPassword,
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","../src/components/NotificationAction.tsx"],"names":["React","useMemo","useState","useCallback","useEffect","useRef","safeActionUrl"],"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 AuthExchangeCodeParams,\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 /**\n * Redeem a single-use exchange code (issued server-side by Archie) for a session as\n * that user. The session cannot be refreshed; see `AuthModule.exchangeCode`.\n */\n exchangeCode: (\n params: AuthExchangeCodeParams,\n ) => Promise<{ session: Session | 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 exchangeCode = useCallback(\n async (params: AuthExchangeCodeParams) => {\n try {\n const result = await client.auth.exchangeCode(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 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 exchangeCode,\n signOut,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n }),\n [\n session,\n isLoading,\n signIn,\n signUp,\n exchangeCode,\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, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport { safeActionUrl } from '@archie/js-sdk';\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: NotificationWithSafeUrl) => void;\n}\n\n/**\n * A notification row plus `safeActionUrl`: `actionUrl` after `safeActionUrl()` validation\n * (`https://` or same-origin path), or `null` when absent/unsafe. Render links from this field,\n * never from the raw `actionUrl`.\n */\nexport type NotificationWithSafeUrl = Notification & { safeActionUrl: string | null };\n\nexport interface UseNotificationsReturn {\n notifications: NotificationWithSafeUrl[];\n latest: NotificationWithSafeUrl | 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// Per-row cache so a row keeps a stable identity across renders (React.memo friendly). Keyed by the\n// source Notification reference: tests/fixtures that share one object by reference share the entry.\nconst decorated = new WeakMap<Notification, NotificationWithSafeUrl>();\nfunction withSafeUrl(n: Notification): NotificationWithSafeUrl {\n let d = decorated.get(n);\n if (!d) {\n d = { ...n, safeActionUrl: safeActionUrl(n) };\n decorated.set(n, d);\n }\n return d;\n}\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?.(withSafeUrl(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 const safeNotifications = useMemo(() => notifications.map(withSafeUrl), [notifications]);\n const safeLatest = useMemo(() => (latest ? withSafeUrl(latest) : null), [latest]);\n\n return {\n notifications: safeNotifications,\n latest: safeLatest,\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","import React from 'react';\nimport { safeActionUrl } from '@archie/js-sdk';\nimport type { Notification } from '@archie/js-sdk';\n\nexport interface NotificationActionProps {\n /** The notification whose `actionText` / `actionUrl` to render. */\n notification: Pick<Notification, 'actionText' | 'actionUrl'>;\n className?: string;\n /** Overrides the label. Defaults to `notification.actionText`. Rendered as React children. */\n children?: React.ReactNode;\n}\n\n/**\n * Renders a notification's call-to-action defensively.\n *\n * - The link target goes through `safeActionUrl` (https or same-origin path only).\n * - `actionText` is rendered as a plain React text child — escaped, never as HTML.\n * - When the URL is unsafe the label is rendered WITHOUT a link; with no label it renders nothing.\n *\n * @example\n * ```tsx\n * {notifications.map((n) => <NotificationAction key={n.id} notification={n} />)}\n * ```\n */\nexport function NotificationAction({ notification, className, children }: NotificationActionProps) {\n // `false`/`null`/empty-array children (e.g. `{cond && 'View'}`, `{[].map(...)}`) are \"no label\":\n // fall back to actionText. `0` is kept and renders; `''` renders nothing.\n const hasChildren =\n children != null && children !== false && !(Array.isArray(children) && children.length === 0);\n const label: React.ReactNode = hasChildren ? children : notification.actionText;\n if (label == null || label === '') return null;\n\n const href = safeActionUrl(notification);\n if (href === null) {\n return React.createElement('span', { className }, label);\n }\n return React.createElement('a', { href, rel: 'noopener noreferrer', className }, label);\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","../src/components/NotificationAction.tsx"],"names":["React","useMemo","useState","useCallback","useEffect","useRef","safeActionUrl"],"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 ActiveSession,\n AuthSignUpParams,\n AuthSignInParams,\n AuthExchangeCodeParams,\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 /**\n * Redeem a single-use exchange code (issued server-side by Archie) for a session as\n * that user. The session cannot be refreshed; see `AuthModule.exchangeCode`.\n */\n exchangeCode: (\n params: AuthExchangeCodeParams,\n ) => Promise<{ session: Session | null; error: ArchieError | null }>;\n /** Sign out of this device only. Never throws. */\n signOut: () => Promise<void>;\n /** Sign out of every device; the local session is always cleared. */\n signOutEverywhere: () => Promise<{ revoked: boolean }>;\n /** Active sessions (devices); `error.code === 'SESSIONS_UNSUPPORTED'` on older identity. */\n listSessions: () => Promise<{ data: ActiveSession[] | null; error: ArchieError | null }>;\n /** End one session by id. */\n revokeSession: (sessionId: string) => Promise<{ error: ArchieError | null }>;\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 exchangeCode = useCallback(\n async (params: AuthExchangeCodeParams) => {\n try {\n const result = await client.auth.exchangeCode(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 signOut = useCallback(async () => {\n await client.auth.signOut();\n }, [client]);\n\n const signOutEverywhere = useCallback(() => client.auth.signOutEverywhere(), [client]);\n\n const listSessions = useCallback(async () => {\n try {\n return { data: await client.auth.listSessions(), error: null };\n } catch (err) {\n return { data: null, error: err as ArchieError };\n }\n }, [client]);\n\n const revokeSession = useCallback(\n async (sessionId: string) => {\n try {\n await client.auth.revokeSession(sessionId);\n return { error: null };\n } catch (err) {\n return { error: err as ArchieError };\n }\n },\n [client],\n );\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 exchangeCode,\n signOut,\n signOutEverywhere,\n listSessions,\n revokeSession,\n confirmSignUp,\n recoverPassword,\n resetPassword,\n refreshSession,\n }),\n [\n session,\n isLoading,\n signIn,\n signUp,\n exchangeCode,\n signOut,\n signOutEverywhere,\n listSessions,\n revokeSession,\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, useMemo } from 'react';\nimport { useArchieContext } from '../provider';\nimport { safeActionUrl } from '@archie/js-sdk';\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: NotificationWithSafeUrl) => void;\n}\n\n/**\n * A notification row plus `safeActionUrl`: `actionUrl` after `safeActionUrl()` validation\n * (`https://` or same-origin path), or `null` when absent/unsafe. Render links from this field,\n * never from the raw `actionUrl`.\n */\nexport type NotificationWithSafeUrl = Notification & { safeActionUrl: string | null };\n\nexport interface UseNotificationsReturn {\n notifications: NotificationWithSafeUrl[];\n latest: NotificationWithSafeUrl | 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// Per-row cache so a row keeps a stable identity across renders (React.memo friendly). Keyed by the\n// source Notification reference: tests/fixtures that share one object by reference share the entry.\nconst decorated = new WeakMap<Notification, NotificationWithSafeUrl>();\nfunction withSafeUrl(n: Notification): NotificationWithSafeUrl {\n let d = decorated.get(n);\n if (!d) {\n d = { ...n, safeActionUrl: safeActionUrl(n) };\n decorated.set(n, d);\n }\n return d;\n}\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?.(withSafeUrl(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 const safeNotifications = useMemo(() => notifications.map(withSafeUrl), [notifications]);\n const safeLatest = useMemo(() => (latest ? withSafeUrl(latest) : null), [latest]);\n\n return {\n notifications: safeNotifications,\n latest: safeLatest,\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","import React from 'react';\nimport { safeActionUrl } from '@archie/js-sdk';\nimport type { Notification } from '@archie/js-sdk';\n\nexport interface NotificationActionProps {\n /** The notification whose `actionText` / `actionUrl` to render. */\n notification: Pick<Notification, 'actionText' | 'actionUrl'>;\n className?: string;\n /** Overrides the label. Defaults to `notification.actionText`. Rendered as React children. */\n children?: React.ReactNode;\n}\n\n/**\n * Renders a notification's call-to-action defensively.\n *\n * - The link target goes through `safeActionUrl` (https or same-origin path only).\n * - `actionText` is rendered as a plain React text child — escaped, never as HTML.\n * - When the URL is unsafe the label is rendered WITHOUT a link; with no label it renders nothing.\n *\n * @example\n * ```tsx\n * {notifications.map((n) => <NotificationAction key={n.id} notification={n} />)}\n * ```\n */\nexport function NotificationAction({ notification, className, children }: NotificationActionProps) {\n // `false`/`null`/empty-array children (e.g. `{cond && 'View'}`, `{[].map(...)}`) are \"no label\":\n // fall back to actionText. `0` is kept and renders; `''` renders nothing.\n const hasChildren =\n children != null && children !== false && !(Array.isArray(children) && children.length === 0);\n const label: React.ReactNode = hasChildren ? children : notification.actionText;\n if (label == null || label === '') return null;\n\n const href = safeActionUrl(notification);\n if (href === null) {\n return React.createElement('span', { className }, label);\n }\n return React.createElement('a', { href, rel: 'noopener noreferrer', className }, label);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/react-sdk",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
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.4.2"
23
+ "@archie/js-sdk": ">=0.5.0 <1.0.0"
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.4.2"
35
+ "@archie/js-sdk": "0.5.1"
36
36
  },
37
37
  "sideEffects": false,
38
38
  "keywords": [