@fanapps/react-native 0.6.0 → 0.8.0

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
@@ -15,11 +15,12 @@ pnpm add @fanapps/react-native \
15
15
 
16
16
  Optional (install only if you import the matching subpath):
17
17
 
18
- | Feature | Subpath | Peer dependency |
19
- | ------------------------------ | ------------------------------ | -------------------------------------------------------------------------------- |
20
- | Push registration / FCM topics | `@fanapps/react-native/push` | `@react-native-firebase/messaging` + `@react-native-async-storage/async-storage` |
21
- | Google sign-in | `@fanapps/react-native/google` | `@react-native-google-signin/google-signin` |
22
- | Apple sign-in (iOS) | `@fanapps/react-native/apple` | `@invertase/react-native-apple-authentication` |
18
+ | Feature | Subpath | Peer dependency |
19
+ | ------------------------------------------------ | ------------------------------ | -------------------------------------------------------------------------------- |
20
+ | Push registration (device tokens) | `@fanapps/react-native/push` | `@react-native-firebase/messaging` + `@react-native-async-storage/async-storage` |
21
+ | Topic subscriptions (server-side, no Firebase needed) | `@fanapps/react-native/push` | none — `useTopicSubscription` talks to the Fanapps API directly |
22
+ | Google sign-in | `@fanapps/react-native/google` | `@react-native-google-signin/google-signin` |
23
+ | Apple sign-in (iOS) | `@fanapps/react-native/apple` | `@invertase/react-native-apple-authentication` |
23
24
 
24
25
  iOS:
25
26
 
@@ -88,6 +89,7 @@ function Screen() {
88
89
  user, // AuthUser | null — Firebase user shape
89
90
  status, // 'loading' | 'signed-in' | 'signed-out'
90
91
  signInWithEmail,
92
+ signInAnonymously,
91
93
  signUpWithEmail,
92
94
  sendPasswordResetEmail,
93
95
  sendEmailVerification,
@@ -101,7 +103,7 @@ function Screen() {
101
103
  ### Email / password
102
104
 
103
105
  ```tsx
104
- const { signInWithEmail, signUpWithEmail, sendPasswordResetEmail, sendEmailVerification, signOut } = useAuth();
106
+ const { signInAnonymously, signInWithEmail, signUpWithEmail, sendPasswordResetEmail, sendEmailVerification, signOut } = useAuth();
105
107
 
106
108
  // Sign in
107
109
  const user = await signInWithEmail('a@b.com', 's3cret');
@@ -177,17 +179,27 @@ function PushSetup() {
177
179
 
178
180
  ### Subscribe to topics
179
181
 
180
- FCM topics are the cheapest way to broadcast no backend round-trip, no storage needed.
182
+ Topics are server-side segments managed in the Fanapps backend — not FCM-native topics. `subscribe`/`unsubscribe` call the Fanapps API, which records the subscription against the signed-in `AppUser` and resolves it when a message targets that topic.
181
183
 
182
184
  ```tsx
183
185
  import { useTopicSubscription } from '@fanapps/react-native/push';
184
186
 
185
- const topics = useTopicSubscription();
186
- await topics.subscribe('news');
187
- await topics.unsubscribe('news');
187
+ function TopicSettings() {
188
+ const { topics, isLoading, error, subscribe, unsubscribe, refresh } =
189
+ useTopicSubscription();
190
+
191
+ // topics: string[] — names the signed-in user is currently subscribed to
192
+
193
+ const onToggle = (name: string) =>
194
+ topics.includes(name) ? unsubscribe(name) : subscribe(name);
195
+
196
+ return null;
197
+ }
188
198
  ```
189
199
 
190
- The backend has no visibility into who subscribed to which topic that's FCM's job. Your dashboard just sends a message to the topic name.
200
+ `subscribe`/`unsubscribe` require an authenticated user (the request carries `X-Firebase-Token`) and throw `FanappsError` if the topic name doesn't exist on the backend. `refresh()` re-fetches the current subscription list; it also runs automatically on mount.
201
+
202
+ **Breaking change (0.8.0):** topics moved from FCM-native pub/sub to server-side segments resolved by the backend. Any FCM topic subscriptions made by clients on pre-0.8.0 versions of this SDK no longer have any effect — call `subscribe()` again after upgrading to re-register them through the API.
191
203
 
192
204
  ### Displaying notifications
193
205
 
@@ -220,12 +232,12 @@ Top-level filters: `blueprint`, `collection`, `slug`, `published`, `sort` (e.g.
220
232
 
221
233
  Nested `filter` (Spatie-style bracket syntax serialized by the SDK):
222
234
 
223
- | Key | Type | Notes |
224
- | ------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
225
- | `filter.blueprint` | `string` | Exact match on blueprint handle. |
226
- | `filter.collection` | `string` | Exact match on collection. |
227
- | `filter.slug` | `string` | Exact match on slug. |
228
- | `filter.field.{handle}` | `string \| number \| boolean` | Exact match on a blueprint field value. Translatable handles match the active locale (with fallback to the default locale). |
235
+ | Key | Type | Notes |
236
+ | ----------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
237
+ | `filter.blueprint` | `string` | Exact match on blueprint handle. |
238
+ | `filter.collection` | `string` | Exact match on collection. |
239
+ | `filter.slug` | `string` | Exact match on slug. |
240
+ | `filter.field.{handle}` | `string \| number \| boolean` | Exact match on a blueprint field value. Translatable handles match the active locale (with fallback to the default locale). |
229
241
 
230
242
  When `filter.field` is set, the request **must** also include `blueprint` (or `filter.blueprint`) so the API can validate that each handle exists on that blueprint. Unknown handles, missing blueprint, or unknown blueprint return `FanappsError` with `status: 422`.
231
243
 
package/dist/index.d.mts CHANGED
@@ -212,6 +212,9 @@ declare class FanappsClient {
212
212
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
213
213
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
214
214
  deletePushTarget(targetId: string): Promise<void>;
215
+ listTopicSubscriptions(): Promise<string[]>;
216
+ subscribeToTopic(name: string): Promise<void>;
217
+ unsubscribeFromTopic(name: string): Promise<void>;
215
218
  createEntry(input: CreateEntryInput): Promise<Entry>;
216
219
  updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
217
220
  deleteEntry(id: string | number): Promise<void>;
@@ -265,6 +268,7 @@ interface UseAuthResult {
265
268
  status: AuthStatus;
266
269
  signInWithEmail(email: string, password: string): Promise<AuthUser>;
267
270
  signUpWithEmail(email: string, password: string): Promise<AuthUser>;
271
+ signInAnonymously(): Promise<AuthUser>;
268
272
  sendPasswordResetEmail(email: string): Promise<void>;
269
273
  sendEmailVerification(): Promise<void>;
270
274
  signOut(): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -212,6 +212,9 @@ declare class FanappsClient {
212
212
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
213
213
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
214
214
  deletePushTarget(targetId: string): Promise<void>;
215
+ listTopicSubscriptions(): Promise<string[]>;
216
+ subscribeToTopic(name: string): Promise<void>;
217
+ unsubscribeFromTopic(name: string): Promise<void>;
215
218
  createEntry(input: CreateEntryInput): Promise<Entry>;
216
219
  updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
217
220
  deleteEntry(id: string | number): Promise<void>;
@@ -265,6 +268,7 @@ interface UseAuthResult {
265
268
  status: AuthStatus;
266
269
  signInWithEmail(email: string, password: string): Promise<AuthUser>;
267
270
  signUpWithEmail(email: string, password: string): Promise<AuthUser>;
271
+ signInAnonymously(): Promise<AuthUser>;
268
272
  sendPasswordResetEmail(email: string): Promise<void>;
269
273
  sendEmailVerification(): Promise<void>;
270
274
  signOut(): Promise<void>;
package/dist/index.js CHANGED
@@ -170,6 +170,19 @@ var FanappsClient = class {
170
170
  `/api/account/targets/push/${encodeURIComponent(targetId)}`
171
171
  );
172
172
  }
173
+ async listTopicSubscriptions() {
174
+ const response = await this.get("/api/account/topics");
175
+ return response.data;
176
+ }
177
+ async subscribeToTopic(name) {
178
+ await this.post(
179
+ `/api/account/topics/${encodeURIComponent(name)}`,
180
+ {}
181
+ );
182
+ }
183
+ async unsubscribeFromTopic(name) {
184
+ await this.delete(`/api/account/topics/${encodeURIComponent(name)}`);
185
+ }
173
186
  async createEntry(input) {
174
187
  return this.post("/api/entries", toEntryBody(input));
175
188
  }
@@ -375,16 +388,26 @@ function useAuth() {
375
388
  () => authStore.getSnapshot(),
376
389
  () => authStore.getSnapshot()
377
390
  );
391
+ const signInAnonymously = (0, import_react3.useCallback)(async () => {
392
+ const cred = await firebaseAuth().signInAnonymously();
393
+ return authStore.getSnapshot().user ?? mapMinimal(cred.user);
394
+ }, [authStore]);
378
395
  const signInWithEmail = (0, import_react3.useCallback)(
379
396
  async (email, password) => {
380
- const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);
397
+ const cred = await firebaseAuth().signInWithEmailAndPassword(
398
+ email,
399
+ password
400
+ );
381
401
  return authStore.getSnapshot().user ?? mapMinimal(cred.user);
382
402
  },
383
403
  [authStore]
384
404
  );
385
405
  const signUpWithEmail = (0, import_react3.useCallback)(
386
406
  async (email, password) => {
387
- const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);
407
+ const cred = await firebaseAuth().createUserWithEmailAndPassword(
408
+ email,
409
+ password
410
+ );
388
411
  return authStore.getSnapshot().user ?? mapMinimal(cred.user);
389
412
  },
390
413
  [authStore]
@@ -405,6 +428,7 @@ function useAuth() {
405
428
  status: snapshot.status,
406
429
  signInWithEmail,
407
430
  signUpWithEmail,
431
+ signInAnonymously,
408
432
  sendPasswordResetEmail,
409
433
  sendEmailVerification,
410
434
  signOut
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/auth/firebaseApp.ts","../src/auth/authStore.ts","../src/errors.ts","../src/client.ts","../src/context.ts","../src/auth/errors.ts","../src/hooks/useFanappsClient.ts","../src/hooks/useAuth.ts","../src/hooks/useEntries.ts","../src/hooks/useEntry.ts","../src/hooks/useCreateEntry.ts","../src/hooks/useUpdateEntry.ts","../src/hooks/useDeleteEntry.ts","../src/hooks/useUploadAsset.ts","../src/hooks/useArticles.ts","../src/hooks/useArticle.ts","../src/hooks/useTrivias.ts","../src/hooks/useTrivia.ts","../src/hooks/useSubmitTriviaResponse.ts"],"sourcesContent":["export { FanappsProvider, type FanappsProviderProps } from './provider';\nexport { FanappsClient, type FanappsClientOptions } from './client';\nexport { FanappsError } from './errors';\nexport { FanappsAuthError } from './auth/errors';\nexport { useFanapps, type FanappsContextValue } from './context';\nexport type { StorageAdapter } from './storage';\nexport { useFanappsClient } from './hooks/useFanappsClient';\nexport { useAuth, type UseAuthResult } from './hooks/useAuth';\nexport { useEntries } from './hooks/useEntries';\nexport { useEntry } from './hooks/useEntry';\nexport { useCreateEntry } from './hooks/useCreateEntry';\nexport { useUpdateEntry } from './hooks/useUpdateEntry';\nexport { useDeleteEntry } from './hooks/useDeleteEntry';\nexport { useUploadAsset } from './hooks/useUploadAsset';\nexport { useArticles } from './hooks/useArticles';\nexport { useArticle } from './hooks/useArticle';\nexport { useTrivias } from './hooks/useTrivias';\nexport { useTrivia } from './hooks/useTrivia';\nexport {\n useSubmitTriviaResponse,\n type SubmitTriviaResponseInput,\n} from './hooks/useSubmitTriviaResponse';\nexport type {\n Article,\n ArticleFilters,\n ArticleStatus,\n Asset,\n AssetUploadFile,\n AuthStatus,\n AuthUser,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n EntryData,\n EntryFieldFilters,\n EntryFilterParams,\n EntryFilters,\n HookOptions,\n Locale,\n Paginated,\n PaginationLinks,\n PaginationMeta,\n PaginationParams,\n PushTarget,\n Trivia,\n TriviaAnswer,\n TriviaResponseResult,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n","import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react';\nimport { AuthStore } from './auth/authStore';\nimport { FanappsClient } from './client';\nimport { FanappsContext, type FanappsContextValue } from './context';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nconst DEFAULT_BASE_URL = 'https://fanapps.app';\n\nexport interface FanappsProviderProps {\n apiKey: string;\n project: string;\n locale?: Locale;\n baseUrl?: string;\n queryClient?: QueryClient;\n storage?: StorageAdapter;\n children: ReactNode;\n}\n\nexport function FanappsProvider({\n apiKey,\n project,\n locale,\n baseUrl = DEFAULT_BASE_URL,\n queryClient,\n storage,\n children,\n}: FanappsProviderProps) {\n const authStoreRef = useRef<AuthStore | null>(null);\n if (!authStoreRef.current) {\n authStoreRef.current = new AuthStore();\n }\n const authStore = authStoreRef.current;\n\n useEffect(() => {\n authStore.start();\n return () => authStore.stop();\n }, [authStore]);\n\n const client = useMemo(\n () =>\n new FanappsClient({\n apiKey,\n project,\n baseUrl,\n getIdToken: () => authStore.getCurrentIdToken(),\n }),\n [apiKey, project, baseUrl, authStore],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? new QueryClient(),\n [queryClient],\n );\n\n const value = useMemo<FanappsContextValue>(\n () => ({ client, authStore, storage, locale }),\n [client, authStore, storage, locale],\n );\n\n return (\n <QueryClientProvider client={resolvedQueryClient}>\n <FanappsContext.Provider value={value}>\n {children}\n </FanappsContext.Provider>\n </QueryClientProvider>\n );\n}\n","import authImport, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\n\nlet cached: FirebaseAuthTypes.Module | null = null;\n\nexport function firebaseAuth(): FirebaseAuthTypes.Module {\n if (cached) return cached;\n cached = authImport();\n return cached;\n}\n\nexport function resetFirebaseAuthCache(): void {\n cached = null;\n}\n","import type { FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { firebaseAuth } from './firebaseApp';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport type AuthListener = (snapshot: AuthStoreSnapshot) => void;\n\nexport interface AuthStoreSnapshot {\n user: AuthUser | null;\n firebaseUser: FirebaseAuthTypes.User | null;\n status: AuthStatus;\n}\n\nfunction mapUser(fb: FirebaseAuthTypes.User | null): AuthUser | null {\n if (!fb) return null;\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n\nexport class AuthStore {\n private snapshot: AuthStoreSnapshot = {\n user: null,\n firebaseUser: null,\n status: 'loading',\n };\n\n private listeners = new Set<AuthListener>();\n private unsubscribe: (() => void) | null = null;\n\n start(): void {\n if (this.unsubscribe) return;\n this.unsubscribe = firebaseAuth().onAuthStateChanged((fb) => {\n this.snapshot = {\n user: mapUser(fb),\n firebaseUser: fb,\n status: fb ? 'signed-in' : 'signed-out',\n };\n this.emit();\n });\n }\n\n stop(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n\n subscribe(listener: AuthListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n getSnapshot(): AuthStoreSnapshot {\n return this.snapshot;\n }\n\n async getCurrentIdToken(): Promise<string | null> {\n const user = firebaseAuth().currentUser;\n if (!user) return null;\n return user.getIdToken();\n }\n\n private emit(): void {\n for (const l of this.listeners) l(this.snapshot);\n }\n}\n","export class FanappsError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = 'FanappsError';\n this.status = status;\n this.body = body;\n }\n}\n","import { FanappsError } from './errors';\nimport type {\n Asset,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n PushTarget,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n\nexport interface FanappsClientOptions {\n apiKey: string;\n project: string;\n baseUrl: string;\n getIdToken?: () => Promise<string | null>;\n}\n\nexport type QueryParams = Record<string, unknown>;\n\nexport class FanappsClient {\n private readonly apiKey: string;\n private readonly project: string;\n private readonly baseUrl: string;\n private readonly getIdToken?: () => Promise<string | null>;\n\n constructor(options: FanappsClientOptions) {\n this.apiKey = options.apiKey;\n this.project = options.project;\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.getIdToken = options.getIdToken;\n }\n\n get<T>(path: string, params?: QueryParams, signal?: AbortSignal): Promise<T> {\n return this.request<T>('GET', path, { params, signal });\n }\n\n post<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('POST', path, { body, signal });\n }\n\n patch<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('PATCH', path, { body, signal });\n }\n\n delete<T>(path: string, signal?: AbortSignal): Promise<T> {\n return this.request<T>('DELETE', path, { signal });\n }\n\n async createPushTarget(input: CreatePushTargetInput): Promise<PushTarget> {\n const response = await this.post<{ data: PushTarget }>(\n '/api/account/targets/push',\n input,\n );\n return response.data;\n }\n\n async updatePushTarget(\n targetId: string,\n identifier: string,\n ): Promise<PushTarget> {\n const response = await this.patch<{ data: PushTarget }>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n { identifier },\n );\n return response.data;\n }\n\n async deletePushTarget(targetId: string): Promise<void> {\n await this.delete<void>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n );\n }\n\n async createEntry(input: CreateEntryInput): Promise<Entry> {\n return this.post<Entry>('/api/entries', toEntryBody(input));\n }\n\n async updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry> {\n return this.patch<Entry>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n toEntryBody(rest),\n );\n }\n\n async deleteEntry(id: string | number): Promise<void> {\n await this.delete<void>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n );\n }\n\n async uploadAsset(input: UploadAssetInput): Promise<Asset> {\n const form = new FormData();\n form.append('file', input.file as unknown as Blob);\n if (input.altText !== undefined) {\n form.append('alt_text', input.altText);\n }\n const response = await this.requestMultipart<{ data: Asset }>(\n '/api/assets',\n form,\n );\n return response.data;\n }\n\n private async requestMultipart<T>(\n path: string,\n form: FormData,\n signal?: AbortSignal,\n ): Promise<T> {\n const url = this.buildUrl(path);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: form,\n signal,\n });\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n opts: { params?: QueryParams; body?: unknown; signal?: AbortSignal },\n ): Promise<T> {\n const url = this.buildUrl(path, opts.params);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const init: RequestInit = { method, headers, signal: opts.signal };\n\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(opts.body);\n }\n\n const response = await fetch(url, init);\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private buildUrl(path: string, params?: QueryParams): string {\n const base = path.startsWith('/')\n ? `${this.baseUrl}${path}`\n : `${this.baseUrl}/${path}`;\n if (!params) return base;\n const query = serializeParams(params);\n return query.length > 0 ? `${base}?${query}` : base;\n }\n}\n\nfunction serializeParams(params: QueryParams): string {\n const parts: string[] = [];\n appendParams(parts, params);\n return parts.join('&');\n}\n\nfunction appendParams(parts: string[], value: unknown, prefix?: string): void {\n if (value === undefined || value === null) return;\n\n if (Array.isArray(value)) {\n if (!prefix) return;\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(`${encodeURIComponent(prefix)}[]=${encodeURIComponent(String(item))}`);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const nextKey = prefix ? `${prefix}[${key}]` : key;\n appendParams(parts, child, nextKey);\n }\n return;\n }\n\n if (!prefix) return;\n parts.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(String(value))}`);\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction toEntryBody(\n input: Omit<CreateEntryInput, never> | Omit<UpdateEntryInput, 'id'>,\n): Record<string, unknown> {\n const { publishedAt, ...rest } = input as Record<string, unknown> & {\n publishedAt?: string | null;\n };\n const body: Record<string, unknown> = { ...rest };\n if (publishedAt !== undefined) {\n body.published_at = publishedAt;\n }\n return body;\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthStore } from './auth/authStore';\nimport type { FanappsClient } from './client';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nexport interface FanappsContextValue {\n client: FanappsClient;\n authStore: AuthStore;\n storage: StorageAdapter | undefined;\n locale?: Locale;\n}\n\nexport const FanappsContext = createContext<FanappsContextValue | null>(null);\n\nexport function useFanapps(): FanappsContextValue {\n const ctx = useContext(FanappsContext);\n if (!ctx) {\n throw new Error(\n '@fanapps/react-native: useFanapps must be used inside <FanappsProvider>.',\n );\n }\n return ctx;\n}\n","export class FanappsAuthError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FanappsAuthError';\n this.code = code;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\n/**\n * Fetch a paginated list of entries.\n *\n * Supports filtering by blueprint field values via `filter.field`. The handle\n * keys must match fields defined on the blueprint passed in `filter.blueprint`\n * (or the top-level `blueprint`); unknown handles return 422 from the API.\n * Translatable fields are matched in the active locale with fallback.\n *\n * @example\n * ```ts\n * // Filter entries by a blueprint field value\n * useEntries({\n * blueprint: 'news',\n * filter: {\n * field: { category: 'sports', region: 'eu' },\n * },\n * sort: '-published_at',\n * });\n * ```\n */\nexport function useEntries(\n filters: EntryFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Entry>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entries', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Entry>>('/api/entries', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, HookOptions } from '../types';\n\nexport function useEntry(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Entry> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entry', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Entry }>(\n `/api/entries/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { CreateEntryInput, Entry } from '../types';\n\nexport function useCreateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n CreateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.createEntry(input),\n onSuccess: (entry) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Entry, UpdateEntryInput } from '../types';\n\nexport function useUpdateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n UpdateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.updateEntry(input),\n onSuccess: (entry, variables) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', variables.id],\n });\n if (entry.id !== variables.id) {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n }\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\n\nexport function useDeleteEntry(): UseMutationResult<\n void,\n FanappsError,\n string | number\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.deleteEntry(id),\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.removeQueries({ queryKey: ['fanapps', 'entry', id] });\n },\n });\n}\n","import { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Asset, UploadAssetInput } from '../types';\n\nexport function useUploadAsset(): UseMutationResult<\n Asset,\n FanappsError,\n UploadAssetInput\n> {\n const { client } = useFanapps();\n\n return useMutation({\n mutationFn: (input) => client.uploadAsset(input),\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, ArticleFilters, HookOptions, Paginated } from '../types';\n\nexport function useArticles(\n filters: ArticleFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Article>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'articles', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Article>>('/api/articles', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, HookOptions } from '../types';\n\nexport function useArticle(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Article> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'article', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Article }>(\n `/api/articles/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivias(\n options: HookOptions = {},\n): UseQueryResult<Trivia[]> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivias', { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia[] }>(\n '/api/trivias',\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivia(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Trivia> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivia', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia }>(\n `/api/trivias/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { TriviaResponseResult } from '../types';\n\nexport interface SubmitTriviaResponseInput {\n triviaId: string | number;\n answerId: string | number;\n}\n\nexport function useSubmitTriviaResponse(): UseMutationResult<\n TriviaResponseResult,\n FanappsError,\n SubmitTriviaResponseInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ triviaId, answerId }) =>\n client.post<TriviaResponseResult>(`/api/trivias/${triviaId}/respond`, {\n answer_id: answerId,\n }),\n onSuccess: (_result, variables) => {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'trivia', variables.triviaId],\n });\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'trivias'] });\n },\n });\n}\n"],"mappings":"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","names":["import_react","authImport","import_react","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/auth/firebaseApp.ts","../src/auth/authStore.ts","../src/errors.ts","../src/client.ts","../src/context.ts","../src/auth/errors.ts","../src/hooks/useFanappsClient.ts","../src/hooks/useAuth.ts","../src/hooks/useEntries.ts","../src/hooks/useEntry.ts","../src/hooks/useCreateEntry.ts","../src/hooks/useUpdateEntry.ts","../src/hooks/useDeleteEntry.ts","../src/hooks/useUploadAsset.ts","../src/hooks/useArticles.ts","../src/hooks/useArticle.ts","../src/hooks/useTrivias.ts","../src/hooks/useTrivia.ts","../src/hooks/useSubmitTriviaResponse.ts"],"sourcesContent":["export { FanappsProvider, type FanappsProviderProps } from './provider';\nexport { FanappsClient, type FanappsClientOptions } from './client';\nexport { FanappsError } from './errors';\nexport { FanappsAuthError } from './auth/errors';\nexport { useFanapps, type FanappsContextValue } from './context';\nexport type { StorageAdapter } from './storage';\nexport { useFanappsClient } from './hooks/useFanappsClient';\nexport { useAuth, type UseAuthResult } from './hooks/useAuth';\nexport { useEntries } from './hooks/useEntries';\nexport { useEntry } from './hooks/useEntry';\nexport { useCreateEntry } from './hooks/useCreateEntry';\nexport { useUpdateEntry } from './hooks/useUpdateEntry';\nexport { useDeleteEntry } from './hooks/useDeleteEntry';\nexport { useUploadAsset } from './hooks/useUploadAsset';\nexport { useArticles } from './hooks/useArticles';\nexport { useArticle } from './hooks/useArticle';\nexport { useTrivias } from './hooks/useTrivias';\nexport { useTrivia } from './hooks/useTrivia';\nexport {\n useSubmitTriviaResponse,\n type SubmitTriviaResponseInput,\n} from './hooks/useSubmitTriviaResponse';\nexport type {\n Article,\n ArticleFilters,\n ArticleStatus,\n Asset,\n AssetUploadFile,\n AuthStatus,\n AuthUser,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n EntryData,\n EntryFieldFilters,\n EntryFilterParams,\n EntryFilters,\n HookOptions,\n Locale,\n Paginated,\n PaginationLinks,\n PaginationMeta,\n PaginationParams,\n PushTarget,\n Trivia,\n TriviaAnswer,\n TriviaResponseResult,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n","import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react';\nimport { AuthStore } from './auth/authStore';\nimport { FanappsClient } from './client';\nimport { FanappsContext, type FanappsContextValue } from './context';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nconst DEFAULT_BASE_URL = 'https://fanapps.app';\n\nexport interface FanappsProviderProps {\n apiKey: string;\n project: string;\n locale?: Locale;\n baseUrl?: string;\n queryClient?: QueryClient;\n storage?: StorageAdapter;\n children: ReactNode;\n}\n\nexport function FanappsProvider({\n apiKey,\n project,\n locale,\n baseUrl = DEFAULT_BASE_URL,\n queryClient,\n storage,\n children,\n}: FanappsProviderProps) {\n const authStoreRef = useRef<AuthStore | null>(null);\n if (!authStoreRef.current) {\n authStoreRef.current = new AuthStore();\n }\n const authStore = authStoreRef.current;\n\n useEffect(() => {\n authStore.start();\n return () => authStore.stop();\n }, [authStore]);\n\n const client = useMemo(\n () =>\n new FanappsClient({\n apiKey,\n project,\n baseUrl,\n getIdToken: () => authStore.getCurrentIdToken(),\n }),\n [apiKey, project, baseUrl, authStore],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? new QueryClient(),\n [queryClient],\n );\n\n const value = useMemo<FanappsContextValue>(\n () => ({ client, authStore, storage, locale }),\n [client, authStore, storage, locale],\n );\n\n return (\n <QueryClientProvider client={resolvedQueryClient}>\n <FanappsContext.Provider value={value}>\n {children}\n </FanappsContext.Provider>\n </QueryClientProvider>\n );\n}\n","import authImport, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\n\nlet cached: FirebaseAuthTypes.Module | null = null;\n\nexport function firebaseAuth(): FirebaseAuthTypes.Module {\n if (cached) return cached;\n cached = authImport();\n return cached;\n}\n\nexport function resetFirebaseAuthCache(): void {\n cached = null;\n}\n","import type { FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { firebaseAuth } from './firebaseApp';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport type AuthListener = (snapshot: AuthStoreSnapshot) => void;\n\nexport interface AuthStoreSnapshot {\n user: AuthUser | null;\n firebaseUser: FirebaseAuthTypes.User | null;\n status: AuthStatus;\n}\n\nfunction mapUser(fb: FirebaseAuthTypes.User | null): AuthUser | null {\n if (!fb) return null;\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n\nexport class AuthStore {\n private snapshot: AuthStoreSnapshot = {\n user: null,\n firebaseUser: null,\n status: 'loading',\n };\n\n private listeners = new Set<AuthListener>();\n private unsubscribe: (() => void) | null = null;\n\n start(): void {\n if (this.unsubscribe) return;\n this.unsubscribe = firebaseAuth().onAuthStateChanged((fb) => {\n this.snapshot = {\n user: mapUser(fb),\n firebaseUser: fb,\n status: fb ? 'signed-in' : 'signed-out',\n };\n this.emit();\n });\n }\n\n stop(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n\n subscribe(listener: AuthListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n getSnapshot(): AuthStoreSnapshot {\n return this.snapshot;\n }\n\n async getCurrentIdToken(): Promise<string | null> {\n const user = firebaseAuth().currentUser;\n if (!user) return null;\n return user.getIdToken();\n }\n\n private emit(): void {\n for (const l of this.listeners) l(this.snapshot);\n }\n}\n","export class FanappsError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = 'FanappsError';\n this.status = status;\n this.body = body;\n }\n}\n","import { FanappsError } from './errors';\nimport type {\n Asset,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n PushTarget,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n\nexport interface FanappsClientOptions {\n apiKey: string;\n project: string;\n baseUrl: string;\n getIdToken?: () => Promise<string | null>;\n}\n\nexport type QueryParams = Record<string, unknown>;\n\nexport class FanappsClient {\n private readonly apiKey: string;\n private readonly project: string;\n private readonly baseUrl: string;\n private readonly getIdToken?: () => Promise<string | null>;\n\n constructor(options: FanappsClientOptions) {\n this.apiKey = options.apiKey;\n this.project = options.project;\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.getIdToken = options.getIdToken;\n }\n\n get<T>(path: string, params?: QueryParams, signal?: AbortSignal): Promise<T> {\n return this.request<T>('GET', path, { params, signal });\n }\n\n post<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('POST', path, { body, signal });\n }\n\n patch<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('PATCH', path, { body, signal });\n }\n\n delete<T>(path: string, signal?: AbortSignal): Promise<T> {\n return this.request<T>('DELETE', path, { signal });\n }\n\n async createPushTarget(input: CreatePushTargetInput): Promise<PushTarget> {\n const response = await this.post<{ data: PushTarget }>(\n '/api/account/targets/push',\n input,\n );\n return response.data;\n }\n\n async updatePushTarget(\n targetId: string,\n identifier: string,\n ): Promise<PushTarget> {\n const response = await this.patch<{ data: PushTarget }>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n { identifier },\n );\n return response.data;\n }\n\n async deletePushTarget(targetId: string): Promise<void> {\n await this.delete<void>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n );\n }\n\n async listTopicSubscriptions(): Promise<string[]> {\n const response = await this.get<{ data: string[] }>('/api/account/topics');\n return response.data;\n }\n\n async subscribeToTopic(name: string): Promise<void> {\n await this.post<void>(\n `/api/account/topics/${encodeURIComponent(name)}`,\n {},\n );\n }\n\n async unsubscribeFromTopic(name: string): Promise<void> {\n await this.delete<void>(`/api/account/topics/${encodeURIComponent(name)}`);\n }\n\n async createEntry(input: CreateEntryInput): Promise<Entry> {\n return this.post<Entry>('/api/entries', toEntryBody(input));\n }\n\n async updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry> {\n return this.patch<Entry>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n toEntryBody(rest),\n );\n }\n\n async deleteEntry(id: string | number): Promise<void> {\n await this.delete<void>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n );\n }\n\n async uploadAsset(input: UploadAssetInput): Promise<Asset> {\n const form = new FormData();\n form.append('file', input.file as unknown as Blob);\n if (input.altText !== undefined) {\n form.append('alt_text', input.altText);\n }\n const response = await this.requestMultipart<{ data: Asset }>(\n '/api/assets',\n form,\n );\n return response.data;\n }\n\n private async requestMultipart<T>(\n path: string,\n form: FormData,\n signal?: AbortSignal,\n ): Promise<T> {\n const url = this.buildUrl(path);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: form,\n signal,\n });\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n opts: { params?: QueryParams; body?: unknown; signal?: AbortSignal },\n ): Promise<T> {\n const url = this.buildUrl(path, opts.params);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const init: RequestInit = { method, headers, signal: opts.signal };\n\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(opts.body);\n }\n\n const response = await fetch(url, init);\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private buildUrl(path: string, params?: QueryParams): string {\n const base = path.startsWith('/')\n ? `${this.baseUrl}${path}`\n : `${this.baseUrl}/${path}`;\n if (!params) return base;\n const query = serializeParams(params);\n return query.length > 0 ? `${base}?${query}` : base;\n }\n}\n\nfunction serializeParams(params: QueryParams): string {\n const parts: string[] = [];\n appendParams(parts, params);\n return parts.join('&');\n}\n\nfunction appendParams(parts: string[], value: unknown, prefix?: string): void {\n if (value === undefined || value === null) return;\n\n if (Array.isArray(value)) {\n if (!prefix) return;\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(`${encodeURIComponent(prefix)}[]=${encodeURIComponent(String(item))}`);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const nextKey = prefix ? `${prefix}[${key}]` : key;\n appendParams(parts, child, nextKey);\n }\n return;\n }\n\n if (!prefix) return;\n parts.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(String(value))}`);\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction toEntryBody(\n input: Omit<CreateEntryInput, never> | Omit<UpdateEntryInput, 'id'>,\n): Record<string, unknown> {\n const { publishedAt, ...rest } = input as Record<string, unknown> & {\n publishedAt?: string | null;\n };\n const body: Record<string, unknown> = { ...rest };\n if (publishedAt !== undefined) {\n body.published_at = publishedAt;\n }\n return body;\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthStore } from './auth/authStore';\nimport type { FanappsClient } from './client';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nexport interface FanappsContextValue {\n client: FanappsClient;\n authStore: AuthStore;\n storage: StorageAdapter | undefined;\n locale?: Locale;\n}\n\nexport const FanappsContext = createContext<FanappsContextValue | null>(null);\n\nexport function useFanapps(): FanappsContextValue {\n const ctx = useContext(FanappsContext);\n if (!ctx) {\n throw new Error(\n '@fanapps/react-native: useFanapps must be used inside <FanappsProvider>.',\n );\n }\n return ctx;\n}\n","export class FanappsAuthError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FanappsAuthError';\n this.code = code;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n signInAnonymously(): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInAnonymously = useCallback(async () => {\n const cred = await firebaseAuth().signInAnonymously();\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n }, [authStore]);\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(\n email,\n password,\n );\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(\n email,\n password,\n );\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n signInAnonymously,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\n/**\n * Fetch a paginated list of entries.\n *\n * Supports filtering by blueprint field values via `filter.field`. The handle\n * keys must match fields defined on the blueprint passed in `filter.blueprint`\n * (or the top-level `blueprint`); unknown handles return 422 from the API.\n * Translatable fields are matched in the active locale with fallback.\n *\n * @example\n * ```ts\n * // Filter entries by a blueprint field value\n * useEntries({\n * blueprint: 'news',\n * filter: {\n * field: { category: 'sports', region: 'eu' },\n * },\n * sort: '-published_at',\n * });\n * ```\n */\nexport function useEntries(\n filters: EntryFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Entry>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entries', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Entry>>('/api/entries', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, HookOptions } from '../types';\n\nexport function useEntry(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Entry> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entry', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Entry }>(\n `/api/entries/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { CreateEntryInput, Entry } from '../types';\n\nexport function useCreateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n CreateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.createEntry(input),\n onSuccess: (entry) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Entry, UpdateEntryInput } from '../types';\n\nexport function useUpdateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n UpdateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.updateEntry(input),\n onSuccess: (entry, variables) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', variables.id],\n });\n if (entry.id !== variables.id) {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n }\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\n\nexport function useDeleteEntry(): UseMutationResult<\n void,\n FanappsError,\n string | number\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.deleteEntry(id),\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.removeQueries({ queryKey: ['fanapps', 'entry', id] });\n },\n });\n}\n","import { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Asset, UploadAssetInput } from '../types';\n\nexport function useUploadAsset(): UseMutationResult<\n Asset,\n FanappsError,\n UploadAssetInput\n> {\n const { client } = useFanapps();\n\n return useMutation({\n mutationFn: (input) => client.uploadAsset(input),\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, ArticleFilters, HookOptions, Paginated } from '../types';\n\nexport function useArticles(\n filters: ArticleFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Article>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'articles', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Article>>('/api/articles', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, HookOptions } from '../types';\n\nexport function useArticle(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Article> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'article', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Article }>(\n `/api/articles/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivias(\n options: HookOptions = {},\n): UseQueryResult<Trivia[]> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivias', { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia[] }>(\n '/api/trivias',\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivia(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Trivia> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivia', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia }>(\n `/api/trivias/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { TriviaResponseResult } from '../types';\n\nexport interface SubmitTriviaResponseInput {\n triviaId: string | number;\n answerId: string | number;\n}\n\nexport function useSubmitTriviaResponse(): UseMutationResult<\n TriviaResponseResult,\n FanappsError,\n SubmitTriviaResponseInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ triviaId, answerId }) =>\n client.post<TriviaResponseResult>(`/api/trivias/${triviaId}/respond`, {\n answer_id: answerId,\n }),\n onSuccess: (_result, variables) => {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'trivia', variables.triviaId],\n });\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'trivias'] });\n },\n });\n}\n"],"mappings":"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","names":["import_react","authImport","import_react","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query","import_react_query"]}
package/dist/index.mjs CHANGED
@@ -117,6 +117,19 @@ var FanappsClient = class {
117
117
  `/api/account/targets/push/${encodeURIComponent(targetId)}`
118
118
  );
119
119
  }
120
+ async listTopicSubscriptions() {
121
+ const response = await this.get("/api/account/topics");
122
+ return response.data;
123
+ }
124
+ async subscribeToTopic(name) {
125
+ await this.post(
126
+ `/api/account/topics/${encodeURIComponent(name)}`,
127
+ {}
128
+ );
129
+ }
130
+ async unsubscribeFromTopic(name) {
131
+ await this.delete(`/api/account/topics/${encodeURIComponent(name)}`);
132
+ }
120
133
  async createEntry(input) {
121
134
  return this.post("/api/entries", toEntryBody(input));
122
135
  }
@@ -322,16 +335,26 @@ function useAuth() {
322
335
  () => authStore.getSnapshot(),
323
336
  () => authStore.getSnapshot()
324
337
  );
338
+ const signInAnonymously = useCallback(async () => {
339
+ const cred = await firebaseAuth().signInAnonymously();
340
+ return authStore.getSnapshot().user ?? mapMinimal(cred.user);
341
+ }, [authStore]);
325
342
  const signInWithEmail = useCallback(
326
343
  async (email, password) => {
327
- const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);
344
+ const cred = await firebaseAuth().signInWithEmailAndPassword(
345
+ email,
346
+ password
347
+ );
328
348
  return authStore.getSnapshot().user ?? mapMinimal(cred.user);
329
349
  },
330
350
  [authStore]
331
351
  );
332
352
  const signUpWithEmail = useCallback(
333
353
  async (email, password) => {
334
- const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);
354
+ const cred = await firebaseAuth().createUserWithEmailAndPassword(
355
+ email,
356
+ password
357
+ );
335
358
  return authStore.getSnapshot().user ?? mapMinimal(cred.user);
336
359
  },
337
360
  [authStore]
@@ -352,6 +375,7 @@ function useAuth() {
352
375
  status: snapshot.status,
353
376
  signInWithEmail,
354
377
  signUpWithEmail,
378
+ signInAnonymously,
355
379
  sendPasswordResetEmail,
356
380
  sendEmailVerification,
357
381
  signOut
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/auth/firebaseApp.ts","../src/auth/authStore.ts","../src/errors.ts","../src/client.ts","../src/context.ts","../src/auth/errors.ts","../src/hooks/useFanappsClient.ts","../src/hooks/useAuth.ts","../src/hooks/useEntries.ts","../src/hooks/useEntry.ts","../src/hooks/useCreateEntry.ts","../src/hooks/useUpdateEntry.ts","../src/hooks/useDeleteEntry.ts","../src/hooks/useUploadAsset.ts","../src/hooks/useArticles.ts","../src/hooks/useArticle.ts","../src/hooks/useTrivias.ts","../src/hooks/useTrivia.ts","../src/hooks/useSubmitTriviaResponse.ts"],"sourcesContent":["import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react';\nimport { AuthStore } from './auth/authStore';\nimport { FanappsClient } from './client';\nimport { FanappsContext, type FanappsContextValue } from './context';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nconst DEFAULT_BASE_URL = 'https://fanapps.app';\n\nexport interface FanappsProviderProps {\n apiKey: string;\n project: string;\n locale?: Locale;\n baseUrl?: string;\n queryClient?: QueryClient;\n storage?: StorageAdapter;\n children: ReactNode;\n}\n\nexport function FanappsProvider({\n apiKey,\n project,\n locale,\n baseUrl = DEFAULT_BASE_URL,\n queryClient,\n storage,\n children,\n}: FanappsProviderProps) {\n const authStoreRef = useRef<AuthStore | null>(null);\n if (!authStoreRef.current) {\n authStoreRef.current = new AuthStore();\n }\n const authStore = authStoreRef.current;\n\n useEffect(() => {\n authStore.start();\n return () => authStore.stop();\n }, [authStore]);\n\n const client = useMemo(\n () =>\n new FanappsClient({\n apiKey,\n project,\n baseUrl,\n getIdToken: () => authStore.getCurrentIdToken(),\n }),\n [apiKey, project, baseUrl, authStore],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? new QueryClient(),\n [queryClient],\n );\n\n const value = useMemo<FanappsContextValue>(\n () => ({ client, authStore, storage, locale }),\n [client, authStore, storage, locale],\n );\n\n return (\n <QueryClientProvider client={resolvedQueryClient}>\n <FanappsContext.Provider value={value}>\n {children}\n </FanappsContext.Provider>\n </QueryClientProvider>\n );\n}\n","import authImport, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\n\nlet cached: FirebaseAuthTypes.Module | null = null;\n\nexport function firebaseAuth(): FirebaseAuthTypes.Module {\n if (cached) return cached;\n cached = authImport();\n return cached;\n}\n\nexport function resetFirebaseAuthCache(): void {\n cached = null;\n}\n","import type { FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { firebaseAuth } from './firebaseApp';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport type AuthListener = (snapshot: AuthStoreSnapshot) => void;\n\nexport interface AuthStoreSnapshot {\n user: AuthUser | null;\n firebaseUser: FirebaseAuthTypes.User | null;\n status: AuthStatus;\n}\n\nfunction mapUser(fb: FirebaseAuthTypes.User | null): AuthUser | null {\n if (!fb) return null;\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n\nexport class AuthStore {\n private snapshot: AuthStoreSnapshot = {\n user: null,\n firebaseUser: null,\n status: 'loading',\n };\n\n private listeners = new Set<AuthListener>();\n private unsubscribe: (() => void) | null = null;\n\n start(): void {\n if (this.unsubscribe) return;\n this.unsubscribe = firebaseAuth().onAuthStateChanged((fb) => {\n this.snapshot = {\n user: mapUser(fb),\n firebaseUser: fb,\n status: fb ? 'signed-in' : 'signed-out',\n };\n this.emit();\n });\n }\n\n stop(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n\n subscribe(listener: AuthListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n getSnapshot(): AuthStoreSnapshot {\n return this.snapshot;\n }\n\n async getCurrentIdToken(): Promise<string | null> {\n const user = firebaseAuth().currentUser;\n if (!user) return null;\n return user.getIdToken();\n }\n\n private emit(): void {\n for (const l of this.listeners) l(this.snapshot);\n }\n}\n","export class FanappsError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = 'FanappsError';\n this.status = status;\n this.body = body;\n }\n}\n","import { FanappsError } from './errors';\nimport type {\n Asset,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n PushTarget,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n\nexport interface FanappsClientOptions {\n apiKey: string;\n project: string;\n baseUrl: string;\n getIdToken?: () => Promise<string | null>;\n}\n\nexport type QueryParams = Record<string, unknown>;\n\nexport class FanappsClient {\n private readonly apiKey: string;\n private readonly project: string;\n private readonly baseUrl: string;\n private readonly getIdToken?: () => Promise<string | null>;\n\n constructor(options: FanappsClientOptions) {\n this.apiKey = options.apiKey;\n this.project = options.project;\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.getIdToken = options.getIdToken;\n }\n\n get<T>(path: string, params?: QueryParams, signal?: AbortSignal): Promise<T> {\n return this.request<T>('GET', path, { params, signal });\n }\n\n post<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('POST', path, { body, signal });\n }\n\n patch<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('PATCH', path, { body, signal });\n }\n\n delete<T>(path: string, signal?: AbortSignal): Promise<T> {\n return this.request<T>('DELETE', path, { signal });\n }\n\n async createPushTarget(input: CreatePushTargetInput): Promise<PushTarget> {\n const response = await this.post<{ data: PushTarget }>(\n '/api/account/targets/push',\n input,\n );\n return response.data;\n }\n\n async updatePushTarget(\n targetId: string,\n identifier: string,\n ): Promise<PushTarget> {\n const response = await this.patch<{ data: PushTarget }>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n { identifier },\n );\n return response.data;\n }\n\n async deletePushTarget(targetId: string): Promise<void> {\n await this.delete<void>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n );\n }\n\n async createEntry(input: CreateEntryInput): Promise<Entry> {\n return this.post<Entry>('/api/entries', toEntryBody(input));\n }\n\n async updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry> {\n return this.patch<Entry>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n toEntryBody(rest),\n );\n }\n\n async deleteEntry(id: string | number): Promise<void> {\n await this.delete<void>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n );\n }\n\n async uploadAsset(input: UploadAssetInput): Promise<Asset> {\n const form = new FormData();\n form.append('file', input.file as unknown as Blob);\n if (input.altText !== undefined) {\n form.append('alt_text', input.altText);\n }\n const response = await this.requestMultipart<{ data: Asset }>(\n '/api/assets',\n form,\n );\n return response.data;\n }\n\n private async requestMultipart<T>(\n path: string,\n form: FormData,\n signal?: AbortSignal,\n ): Promise<T> {\n const url = this.buildUrl(path);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: form,\n signal,\n });\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n opts: { params?: QueryParams; body?: unknown; signal?: AbortSignal },\n ): Promise<T> {\n const url = this.buildUrl(path, opts.params);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const init: RequestInit = { method, headers, signal: opts.signal };\n\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(opts.body);\n }\n\n const response = await fetch(url, init);\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private buildUrl(path: string, params?: QueryParams): string {\n const base = path.startsWith('/')\n ? `${this.baseUrl}${path}`\n : `${this.baseUrl}/${path}`;\n if (!params) return base;\n const query = serializeParams(params);\n return query.length > 0 ? `${base}?${query}` : base;\n }\n}\n\nfunction serializeParams(params: QueryParams): string {\n const parts: string[] = [];\n appendParams(parts, params);\n return parts.join('&');\n}\n\nfunction appendParams(parts: string[], value: unknown, prefix?: string): void {\n if (value === undefined || value === null) return;\n\n if (Array.isArray(value)) {\n if (!prefix) return;\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(`${encodeURIComponent(prefix)}[]=${encodeURIComponent(String(item))}`);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const nextKey = prefix ? `${prefix}[${key}]` : key;\n appendParams(parts, child, nextKey);\n }\n return;\n }\n\n if (!prefix) return;\n parts.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(String(value))}`);\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction toEntryBody(\n input: Omit<CreateEntryInput, never> | Omit<UpdateEntryInput, 'id'>,\n): Record<string, unknown> {\n const { publishedAt, ...rest } = input as Record<string, unknown> & {\n publishedAt?: string | null;\n };\n const body: Record<string, unknown> = { ...rest };\n if (publishedAt !== undefined) {\n body.published_at = publishedAt;\n }\n return body;\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthStore } from './auth/authStore';\nimport type { FanappsClient } from './client';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nexport interface FanappsContextValue {\n client: FanappsClient;\n authStore: AuthStore;\n storage: StorageAdapter | undefined;\n locale?: Locale;\n}\n\nexport const FanappsContext = createContext<FanappsContextValue | null>(null);\n\nexport function useFanapps(): FanappsContextValue {\n const ctx = useContext(FanappsContext);\n if (!ctx) {\n throw new Error(\n '@fanapps/react-native: useFanapps must be used inside <FanappsProvider>.',\n );\n }\n return ctx;\n}\n","export class FanappsAuthError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FanappsAuthError';\n this.code = code;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\n/**\n * Fetch a paginated list of entries.\n *\n * Supports filtering by blueprint field values via `filter.field`. The handle\n * keys must match fields defined on the blueprint passed in `filter.blueprint`\n * (or the top-level `blueprint`); unknown handles return 422 from the API.\n * Translatable fields are matched in the active locale with fallback.\n *\n * @example\n * ```ts\n * // Filter entries by a blueprint field value\n * useEntries({\n * blueprint: 'news',\n * filter: {\n * field: { category: 'sports', region: 'eu' },\n * },\n * sort: '-published_at',\n * });\n * ```\n */\nexport function useEntries(\n filters: EntryFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Entry>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entries', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Entry>>('/api/entries', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, HookOptions } from '../types';\n\nexport function useEntry(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Entry> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entry', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Entry }>(\n `/api/entries/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { CreateEntryInput, Entry } from '../types';\n\nexport function useCreateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n CreateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.createEntry(input),\n onSuccess: (entry) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Entry, UpdateEntryInput } from '../types';\n\nexport function useUpdateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n UpdateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.updateEntry(input),\n onSuccess: (entry, variables) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', variables.id],\n });\n if (entry.id !== variables.id) {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n }\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\n\nexport function useDeleteEntry(): UseMutationResult<\n void,\n FanappsError,\n string | number\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.deleteEntry(id),\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.removeQueries({ queryKey: ['fanapps', 'entry', id] });\n },\n });\n}\n","import { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Asset, UploadAssetInput } from '../types';\n\nexport function useUploadAsset(): UseMutationResult<\n Asset,\n FanappsError,\n UploadAssetInput\n> {\n const { client } = useFanapps();\n\n return useMutation({\n mutationFn: (input) => client.uploadAsset(input),\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, ArticleFilters, HookOptions, Paginated } from '../types';\n\nexport function useArticles(\n filters: ArticleFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Article>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'articles', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Article>>('/api/articles', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, HookOptions } from '../types';\n\nexport function useArticle(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Article> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'article', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Article }>(\n `/api/articles/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivias(\n options: HookOptions = {},\n): UseQueryResult<Trivia[]> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivias', { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia[] }>(\n '/api/trivias',\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivia(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Trivia> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivia', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia }>(\n `/api/trivias/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { TriviaResponseResult } from '../types';\n\nexport interface SubmitTriviaResponseInput {\n triviaId: string | number;\n answerId: string | number;\n}\n\nexport function useSubmitTriviaResponse(): UseMutationResult<\n TriviaResponseResult,\n FanappsError,\n SubmitTriviaResponseInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ triviaId, answerId }) =>\n client.post<TriviaResponseResult>(`/api/trivias/${triviaId}/respond`, {\n answer_id: answerId,\n }),\n onSuccess: (_result, variables) => {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'trivia', variables.triviaId],\n });\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'trivias'] });\n },\n });\n}\n"],"mappings":"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","names":["useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useMutation","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/auth/firebaseApp.ts","../src/auth/authStore.ts","../src/errors.ts","../src/client.ts","../src/context.ts","../src/auth/errors.ts","../src/hooks/useFanappsClient.ts","../src/hooks/useAuth.ts","../src/hooks/useEntries.ts","../src/hooks/useEntry.ts","../src/hooks/useCreateEntry.ts","../src/hooks/useUpdateEntry.ts","../src/hooks/useDeleteEntry.ts","../src/hooks/useUploadAsset.ts","../src/hooks/useArticles.ts","../src/hooks/useArticle.ts","../src/hooks/useTrivias.ts","../src/hooks/useTrivia.ts","../src/hooks/useSubmitTriviaResponse.ts"],"sourcesContent":["import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react';\nimport { AuthStore } from './auth/authStore';\nimport { FanappsClient } from './client';\nimport { FanappsContext, type FanappsContextValue } from './context';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nconst DEFAULT_BASE_URL = 'https://fanapps.app';\n\nexport interface FanappsProviderProps {\n apiKey: string;\n project: string;\n locale?: Locale;\n baseUrl?: string;\n queryClient?: QueryClient;\n storage?: StorageAdapter;\n children: ReactNode;\n}\n\nexport function FanappsProvider({\n apiKey,\n project,\n locale,\n baseUrl = DEFAULT_BASE_URL,\n queryClient,\n storage,\n children,\n}: FanappsProviderProps) {\n const authStoreRef = useRef<AuthStore | null>(null);\n if (!authStoreRef.current) {\n authStoreRef.current = new AuthStore();\n }\n const authStore = authStoreRef.current;\n\n useEffect(() => {\n authStore.start();\n return () => authStore.stop();\n }, [authStore]);\n\n const client = useMemo(\n () =>\n new FanappsClient({\n apiKey,\n project,\n baseUrl,\n getIdToken: () => authStore.getCurrentIdToken(),\n }),\n [apiKey, project, baseUrl, authStore],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? new QueryClient(),\n [queryClient],\n );\n\n const value = useMemo<FanappsContextValue>(\n () => ({ client, authStore, storage, locale }),\n [client, authStore, storage, locale],\n );\n\n return (\n <QueryClientProvider client={resolvedQueryClient}>\n <FanappsContext.Provider value={value}>\n {children}\n </FanappsContext.Provider>\n </QueryClientProvider>\n );\n}\n","import authImport, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\n\nlet cached: FirebaseAuthTypes.Module | null = null;\n\nexport function firebaseAuth(): FirebaseAuthTypes.Module {\n if (cached) return cached;\n cached = authImport();\n return cached;\n}\n\nexport function resetFirebaseAuthCache(): void {\n cached = null;\n}\n","import type { FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { firebaseAuth } from './firebaseApp';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport type AuthListener = (snapshot: AuthStoreSnapshot) => void;\n\nexport interface AuthStoreSnapshot {\n user: AuthUser | null;\n firebaseUser: FirebaseAuthTypes.User | null;\n status: AuthStatus;\n}\n\nfunction mapUser(fb: FirebaseAuthTypes.User | null): AuthUser | null {\n if (!fb) return null;\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n\nexport class AuthStore {\n private snapshot: AuthStoreSnapshot = {\n user: null,\n firebaseUser: null,\n status: 'loading',\n };\n\n private listeners = new Set<AuthListener>();\n private unsubscribe: (() => void) | null = null;\n\n start(): void {\n if (this.unsubscribe) return;\n this.unsubscribe = firebaseAuth().onAuthStateChanged((fb) => {\n this.snapshot = {\n user: mapUser(fb),\n firebaseUser: fb,\n status: fb ? 'signed-in' : 'signed-out',\n };\n this.emit();\n });\n }\n\n stop(): void {\n this.unsubscribe?.();\n this.unsubscribe = null;\n }\n\n subscribe(listener: AuthListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n getSnapshot(): AuthStoreSnapshot {\n return this.snapshot;\n }\n\n async getCurrentIdToken(): Promise<string | null> {\n const user = firebaseAuth().currentUser;\n if (!user) return null;\n return user.getIdToken();\n }\n\n private emit(): void {\n for (const l of this.listeners) l(this.snapshot);\n }\n}\n","export class FanappsError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = 'FanappsError';\n this.status = status;\n this.body = body;\n }\n}\n","import { FanappsError } from './errors';\nimport type {\n Asset,\n CreateEntryInput,\n CreatePushTargetInput,\n Entry,\n PushTarget,\n UpdateEntryInput,\n UploadAssetInput,\n} from './types';\n\nexport interface FanappsClientOptions {\n apiKey: string;\n project: string;\n baseUrl: string;\n getIdToken?: () => Promise<string | null>;\n}\n\nexport type QueryParams = Record<string, unknown>;\n\nexport class FanappsClient {\n private readonly apiKey: string;\n private readonly project: string;\n private readonly baseUrl: string;\n private readonly getIdToken?: () => Promise<string | null>;\n\n constructor(options: FanappsClientOptions) {\n this.apiKey = options.apiKey;\n this.project = options.project;\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.getIdToken = options.getIdToken;\n }\n\n get<T>(path: string, params?: QueryParams, signal?: AbortSignal): Promise<T> {\n return this.request<T>('GET', path, { params, signal });\n }\n\n post<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('POST', path, { body, signal });\n }\n\n patch<T>(path: string, body?: unknown, signal?: AbortSignal): Promise<T> {\n return this.request<T>('PATCH', path, { body, signal });\n }\n\n delete<T>(path: string, signal?: AbortSignal): Promise<T> {\n return this.request<T>('DELETE', path, { signal });\n }\n\n async createPushTarget(input: CreatePushTargetInput): Promise<PushTarget> {\n const response = await this.post<{ data: PushTarget }>(\n '/api/account/targets/push',\n input,\n );\n return response.data;\n }\n\n async updatePushTarget(\n targetId: string,\n identifier: string,\n ): Promise<PushTarget> {\n const response = await this.patch<{ data: PushTarget }>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n { identifier },\n );\n return response.data;\n }\n\n async deletePushTarget(targetId: string): Promise<void> {\n await this.delete<void>(\n `/api/account/targets/push/${encodeURIComponent(targetId)}`,\n );\n }\n\n async listTopicSubscriptions(): Promise<string[]> {\n const response = await this.get<{ data: string[] }>('/api/account/topics');\n return response.data;\n }\n\n async subscribeToTopic(name: string): Promise<void> {\n await this.post<void>(\n `/api/account/topics/${encodeURIComponent(name)}`,\n {},\n );\n }\n\n async unsubscribeFromTopic(name: string): Promise<void> {\n await this.delete<void>(`/api/account/topics/${encodeURIComponent(name)}`);\n }\n\n async createEntry(input: CreateEntryInput): Promise<Entry> {\n return this.post<Entry>('/api/entries', toEntryBody(input));\n }\n\n async updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry> {\n return this.patch<Entry>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n toEntryBody(rest),\n );\n }\n\n async deleteEntry(id: string | number): Promise<void> {\n await this.delete<void>(\n `/api/entries/${encodeURIComponent(String(id))}`,\n );\n }\n\n async uploadAsset(input: UploadAssetInput): Promise<Asset> {\n const form = new FormData();\n form.append('file', input.file as unknown as Blob);\n if (input.altText !== undefined) {\n form.append('alt_text', input.altText);\n }\n const response = await this.requestMultipart<{ data: Asset }>(\n '/api/assets',\n form,\n );\n return response.data;\n }\n\n private async requestMultipart<T>(\n path: string,\n form: FormData,\n signal?: AbortSignal,\n ): Promise<T> {\n const url = this.buildUrl(path);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: form,\n signal,\n });\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n opts: { params?: QueryParams; body?: unknown; signal?: AbortSignal },\n ): Promise<T> {\n const url = this.buildUrl(path, opts.params);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Tenant': this.project,\n Accept: 'application/json',\n };\n\n if (this.getIdToken) {\n const idToken = await this.getIdToken();\n if (idToken) {\n headers['X-Firebase-Token'] = idToken;\n }\n }\n\n const init: RequestInit = { method, headers, signal: opts.signal };\n\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(opts.body);\n }\n\n const response = await fetch(url, init);\n\n const raw = await response.text();\n const payload = raw.length > 0 ? safeJson(raw) : null;\n\n if (!response.ok) {\n const message =\n (payload && typeof payload === 'object' && 'message' in payload\n ? String((payload as { message: unknown }).message)\n : null) ?? `Fanapps request failed with status ${response.status}`;\n throw new FanappsError(message, response.status, payload);\n }\n\n return payload as T;\n }\n\n private buildUrl(path: string, params?: QueryParams): string {\n const base = path.startsWith('/')\n ? `${this.baseUrl}${path}`\n : `${this.baseUrl}/${path}`;\n if (!params) return base;\n const query = serializeParams(params);\n return query.length > 0 ? `${base}?${query}` : base;\n }\n}\n\nfunction serializeParams(params: QueryParams): string {\n const parts: string[] = [];\n appendParams(parts, params);\n return parts.join('&');\n}\n\nfunction appendParams(parts: string[], value: unknown, prefix?: string): void {\n if (value === undefined || value === null) return;\n\n if (Array.isArray(value)) {\n if (!prefix) return;\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(`${encodeURIComponent(prefix)}[]=${encodeURIComponent(String(item))}`);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const nextKey = prefix ? `${prefix}[${key}]` : key;\n appendParams(parts, child, nextKey);\n }\n return;\n }\n\n if (!prefix) return;\n parts.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(String(value))}`);\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction toEntryBody(\n input: Omit<CreateEntryInput, never> | Omit<UpdateEntryInput, 'id'>,\n): Record<string, unknown> {\n const { publishedAt, ...rest } = input as Record<string, unknown> & {\n publishedAt?: string | null;\n };\n const body: Record<string, unknown> = { ...rest };\n if (publishedAt !== undefined) {\n body.published_at = publishedAt;\n }\n return body;\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthStore } from './auth/authStore';\nimport type { FanappsClient } from './client';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nexport interface FanappsContextValue {\n client: FanappsClient;\n authStore: AuthStore;\n storage: StorageAdapter | undefined;\n locale?: Locale;\n}\n\nexport const FanappsContext = createContext<FanappsContextValue | null>(null);\n\nexport function useFanapps(): FanappsContextValue {\n const ctx = useContext(FanappsContext);\n if (!ctx) {\n throw new Error(\n '@fanapps/react-native: useFanapps must be used inside <FanappsProvider>.',\n );\n }\n return ctx;\n}\n","export class FanappsAuthError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FanappsAuthError';\n this.code = code;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n signInAnonymously(): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInAnonymously = useCallback(async () => {\n const cred = await firebaseAuth().signInAnonymously();\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n }, [authStore]);\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(\n email,\n password,\n );\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(\n email,\n password,\n );\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n signInAnonymously,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\n/**\n * Fetch a paginated list of entries.\n *\n * Supports filtering by blueprint field values via `filter.field`. The handle\n * keys must match fields defined on the blueprint passed in `filter.blueprint`\n * (or the top-level `blueprint`); unknown handles return 422 from the API.\n * Translatable fields are matched in the active locale with fallback.\n *\n * @example\n * ```ts\n * // Filter entries by a blueprint field value\n * useEntries({\n * blueprint: 'news',\n * filter: {\n * field: { category: 'sports', region: 'eu' },\n * },\n * sort: '-published_at',\n * });\n * ```\n */\nexport function useEntries(\n filters: EntryFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Entry>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entries', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Entry>>('/api/entries', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, HookOptions } from '../types';\n\nexport function useEntry(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Entry> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entry', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Entry }>(\n `/api/entries/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { CreateEntryInput, Entry } from '../types';\n\nexport function useCreateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n CreateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.createEntry(input),\n onSuccess: (entry) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Entry, UpdateEntryInput } from '../types';\n\nexport function useUpdateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n UpdateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.updateEntry(input),\n onSuccess: (entry, variables) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', variables.id],\n });\n if (entry.id !== variables.id) {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n }\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\n\nexport function useDeleteEntry(): UseMutationResult<\n void,\n FanappsError,\n string | number\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.deleteEntry(id),\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.removeQueries({ queryKey: ['fanapps', 'entry', id] });\n },\n });\n}\n","import { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Asset, UploadAssetInput } from '../types';\n\nexport function useUploadAsset(): UseMutationResult<\n Asset,\n FanappsError,\n UploadAssetInput\n> {\n const { client } = useFanapps();\n\n return useMutation({\n mutationFn: (input) => client.uploadAsset(input),\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, ArticleFilters, HookOptions, Paginated } from '../types';\n\nexport function useArticles(\n filters: ArticleFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Article>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'articles', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Article>>('/api/articles', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, HookOptions } from '../types';\n\nexport function useArticle(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Article> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'article', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Article }>(\n `/api/articles/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivias(\n options: HookOptions = {},\n): UseQueryResult<Trivia[]> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivias', { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia[] }>(\n '/api/trivias',\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivia(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Trivia> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivia', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia }>(\n `/api/trivias/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { TriviaResponseResult } from '../types';\n\nexport interface SubmitTriviaResponseInput {\n triviaId: string | number;\n answerId: string | number;\n}\n\nexport function useSubmitTriviaResponse(): UseMutationResult<\n TriviaResponseResult,\n FanappsError,\n SubmitTriviaResponseInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ triviaId, answerId }) =>\n client.post<TriviaResponseResult>(`/api/trivias/${triviaId}/respond`, {\n answer_id: answerId,\n }),\n onSuccess: (_result, variables) => {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'trivia', variables.triviaId],\n });\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'trivias'] });\n },\n });\n}\n"],"mappings":"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","names":["useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useMutation","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation"]}
package/dist/push.d.mts CHANGED
@@ -13,8 +13,13 @@ interface UseRegisterDeviceResult {
13
13
  declare function useRegisterDevice(): UseRegisterDeviceResult;
14
14
 
15
15
  interface UseTopicSubscriptionResult {
16
+ /** Topic names the authenticated user is subscribed to. */
17
+ topics: string[];
18
+ isLoading: boolean;
19
+ error: Error | null;
16
20
  subscribe(topic: string): Promise<void>;
17
21
  unsubscribe(topic: string): Promise<void>;
22
+ refresh(): Promise<void>;
18
23
  }
19
24
  declare function useTopicSubscription(): UseTopicSubscriptionResult;
20
25
 
package/dist/push.d.ts CHANGED
@@ -13,8 +13,13 @@ interface UseRegisterDeviceResult {
13
13
  declare function useRegisterDevice(): UseRegisterDeviceResult;
14
14
 
15
15
  interface UseTopicSubscriptionResult {
16
+ /** Topic names the authenticated user is subscribed to. */
17
+ topics: string[];
18
+ isLoading: boolean;
19
+ error: Error | null;
16
20
  subscribe(topic: string): Promise<void>;
17
21
  unsubscribe(topic: string): Promise<void>;
22
+ refresh(): Promise<void>;
18
23
  }
19
24
  declare function useTopicSubscription(): UseTopicSubscriptionResult;
20
25
 
package/dist/push.js CHANGED
@@ -182,14 +182,64 @@ function useRegisterDevice() {
182
182
 
183
183
  // src/push/useTopicSubscription.ts
184
184
  var import_react2 = require("react");
185
+ var import_react_native3 = require("@fanapps/react-native");
185
186
  function useTopicSubscription() {
186
- const subscribe = (0, import_react2.useCallback)(async (topic) => {
187
- await firebaseMessaging().subscribeToTopic(topic);
188
- }, []);
189
- const unsubscribe = (0, import_react2.useCallback)(async (topic) => {
190
- await firebaseMessaging().unsubscribeFromTopic(topic);
191
- }, []);
192
- return { subscribe, unsubscribe };
187
+ const { client } = (0, import_react_native3.useFanapps)();
188
+ const [topics, setTopics] = (0, import_react2.useState)([]);
189
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
190
+ const [error, setError] = (0, import_react2.useState)(null);
191
+ const latestRequestRef = (0, import_react2.useRef)(0);
192
+ const refresh = (0, import_react2.useCallback)(async () => {
193
+ const requestId = ++latestRequestRef.current;
194
+ setIsLoading(true);
195
+ setError(null);
196
+ try {
197
+ const result = await client.listTopicSubscriptions();
198
+ if (requestId !== latestRequestRef.current) return;
199
+ setTopics(result);
200
+ } catch (e) {
201
+ if (requestId !== latestRequestRef.current) return;
202
+ setError(e instanceof Error ? e : new Error(String(e)));
203
+ } finally {
204
+ if (requestId === latestRequestRef.current) setIsLoading(false);
205
+ }
206
+ }, [client]);
207
+ (0, import_react2.useEffect)(() => {
208
+ void refresh();
209
+ }, [refresh]);
210
+ const subscribe = (0, import_react2.useCallback)(
211
+ async (topic) => {
212
+ try {
213
+ await client.subscribeToTopic(topic);
214
+ } catch (e) {
215
+ const err = e instanceof Error ? e : new Error(String(e));
216
+ setError(err);
217
+ throw err;
218
+ }
219
+ latestRequestRef.current++;
220
+ setIsLoading(false);
221
+ setError(null);
222
+ setTopics((prev) => prev.includes(topic) ? prev : [...prev, topic]);
223
+ },
224
+ [client]
225
+ );
226
+ const unsubscribe = (0, import_react2.useCallback)(
227
+ async (topic) => {
228
+ try {
229
+ await client.unsubscribeFromTopic(topic);
230
+ } catch (e) {
231
+ const err = e instanceof Error ? e : new Error(String(e));
232
+ setError(err);
233
+ throw err;
234
+ }
235
+ latestRequestRef.current++;
236
+ setIsLoading(false);
237
+ setError(null);
238
+ setTopics((prev) => prev.filter((t) => t !== topic));
239
+ },
240
+ [client]
241
+ );
242
+ return { topics, isLoading, error, subscribe, unsubscribe, refresh };
193
243
  }
194
244
  // Annotate the CommonJS export names for ESM import in node:
195
245
  0 && (module.exports = {
package/dist/push.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/push/index.ts","../src/push/useRegisterDevice.ts","../src/push/messaging.ts","../src/push/storage.ts","../src/push/targetIdStore.ts","../src/push/useTopicSubscription.ts"],"sourcesContent":["export {\n useRegisterDevice,\n type UseRegisterDeviceResult,\n} from './useRegisterDevice';\nexport {\n useTopicSubscription,\n type UseTopicSubscriptionResult,\n} from './useTopicSubscription';\nexport type { StorageAdapter } from './storage';\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform } from 'react-native';\nimport { firebaseMessaging } from './messaging';\nimport { resolveStorage } from './storage';\nimport { generateTargetId, TargetIdStore } from './targetIdStore';\nimport { useFanapps, type PushTarget } from '@fanapps/react-native';\n\nexport interface UseRegisterDeviceResult {\n targetId: string | null;\n token: string | null;\n target: PushTarget | null;\n isRegistering: boolean;\n error: Error | null;\n register(): Promise<PushTarget>;\n unregister(): Promise<void>;\n}\n\nexport function useRegisterDevice(): UseRegisterDeviceResult {\n const { client, storage } = useFanapps();\n\n const [targetId, setTargetId] = useState<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [target, setTarget] = useState<PushTarget | null>(null);\n const [isRegistering, setIsRegistering] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const targetStoreRef = useRef<TargetIdStore | null>(null);\n if (!targetStoreRef.current) {\n targetStoreRef.current = new TargetIdStore(resolveStorage(storage));\n }\n const targetStore = targetStoreRef.current;\n\n const tokenRefreshUnsubRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n };\n }, []);\n\n const register = useCallback(async (): Promise<PushTarget> => {\n setIsRegistering(true);\n setError(null);\n try {\n const messaging = firebaseMessaging();\n\n // Request permission (idempotent; no-op if already granted).\n await messaging.requestPermission();\n\n const fcmToken = await messaging.getToken();\n setToken(fcmToken);\n\n const existingId = await targetStore.get();\n\n let result: PushTarget;\n if (existingId) {\n try {\n result = await client.updatePushTarget(existingId, fcmToken);\n } catch {\n // If the stored target is gone (404), create a new one with the same id.\n result = await client.createPushTarget({\n targetId: existingId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n }\n } else {\n const newId = generateTargetId();\n result = await client.createPushTarget({\n targetId: newId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n await targetStore.set(result.id);\n }\n\n setTargetId(result.id);\n setTarget(result);\n\n // Subscribe to onTokenRefresh once.\n if (!tokenRefreshUnsubRef.current) {\n tokenRefreshUnsubRef.current = messaging.onTokenRefresh(async (newToken: string) => {\n try {\n const id = await targetStore.get();\n if (!id) return;\n const updated = await client.updatePushTarget(id, newToken);\n setToken(newToken);\n setTarget(updated);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n } finally {\n setIsRegistering(false);\n }\n }, [client, targetStore]);\n\n const unregister = useCallback(async (): Promise<void> => {\n const id = await targetStore.get();\n if (id) {\n try {\n await client.deletePushTarget(id);\n } catch {\n // Swallow network/404; we still want to clear local state.\n }\n await targetStore.clear();\n }\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n setTargetId(null);\n setToken(null);\n setTarget(null);\n }, [client, targetStore]);\n\n return {\n targetId,\n token,\n target,\n isRegistering,\n error,\n register,\n unregister,\n };\n}\n","import messagingImport, {\n type FirebaseMessagingTypes,\n} from '@react-native-firebase/messaging';\n\nlet cached: FirebaseMessagingTypes.Module | null = null;\n\nexport function firebaseMessaging(): FirebaseMessagingTypes.Module {\n if (cached) return cached;\n cached = messagingImport();\n return cached;\n}\n","import AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { StorageAdapter } from '../storage';\n\nexport function resolveStorage(explicit?: StorageAdapter): StorageAdapter {\n return explicit ?? AsyncStorage;\n}\n\nexport type { StorageAdapter };\n","import type { StorageAdapter } from './storage';\n\nconst KEY = 'fanapps.pushTargetId';\n\nexport class TargetIdStore {\n constructor(private readonly storage: StorageAdapter) {}\n\n get(): Promise<string | null> {\n return this.storage.getItem(KEY);\n }\n\n async set(id: string): Promise<void> {\n await this.storage.setItem(KEY, id);\n }\n\n async clear(): Promise<void> {\n await this.storage.removeItem(KEY);\n }\n}\n\nexport function generateTargetId(): string {\n // 16 bytes of URL-safe hex — safely within Appwrite's 36-char, safe-char constraint.\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { useCallback } from 'react';\nimport { firebaseMessaging } from './messaging';\n\nexport interface UseTopicSubscriptionResult {\n subscribe(topic: string): Promise<void>;\n unsubscribe(topic: string): Promise<void>;\n}\n\nexport function useTopicSubscription(): UseTopicSubscriptionResult {\n const subscribe = useCallback(async (topic: string) => {\n await firebaseMessaging().subscribeToTopic(topic);\n }, []);\n\n const unsubscribe = useCallback(async (topic: string) => {\n await firebaseMessaging().unsubscribeFromTopic(topic);\n }, []);\n\n return { subscribe, unsubscribe };\n}\n"],"mappings":"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","names":["messagingImport","AsyncStorage","import_react_native","import_react"]}
1
+ {"version":3,"sources":["../src/push/index.ts","../src/push/useRegisterDevice.ts","../src/push/messaging.ts","../src/push/storage.ts","../src/push/targetIdStore.ts","../src/push/useTopicSubscription.ts"],"sourcesContent":["export {\n useRegisterDevice,\n type UseRegisterDeviceResult,\n} from './useRegisterDevice';\nexport {\n useTopicSubscription,\n type UseTopicSubscriptionResult,\n} from './useTopicSubscription';\nexport type { StorageAdapter } from './storage';\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform } from 'react-native';\nimport { firebaseMessaging } from './messaging';\nimport { resolveStorage } from './storage';\nimport { generateTargetId, TargetIdStore } from './targetIdStore';\nimport { useFanapps, type PushTarget } from '@fanapps/react-native';\n\nexport interface UseRegisterDeviceResult {\n targetId: string | null;\n token: string | null;\n target: PushTarget | null;\n isRegistering: boolean;\n error: Error | null;\n register(): Promise<PushTarget>;\n unregister(): Promise<void>;\n}\n\nexport function useRegisterDevice(): UseRegisterDeviceResult {\n const { client, storage } = useFanapps();\n\n const [targetId, setTargetId] = useState<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [target, setTarget] = useState<PushTarget | null>(null);\n const [isRegistering, setIsRegistering] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const targetStoreRef = useRef<TargetIdStore | null>(null);\n if (!targetStoreRef.current) {\n targetStoreRef.current = new TargetIdStore(resolveStorage(storage));\n }\n const targetStore = targetStoreRef.current;\n\n const tokenRefreshUnsubRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n };\n }, []);\n\n const register = useCallback(async (): Promise<PushTarget> => {\n setIsRegistering(true);\n setError(null);\n try {\n const messaging = firebaseMessaging();\n\n // Request permission (idempotent; no-op if already granted).\n await messaging.requestPermission();\n\n const fcmToken = await messaging.getToken();\n setToken(fcmToken);\n\n const existingId = await targetStore.get();\n\n let result: PushTarget;\n if (existingId) {\n try {\n result = await client.updatePushTarget(existingId, fcmToken);\n } catch {\n // If the stored target is gone (404), create a new one with the same id.\n result = await client.createPushTarget({\n targetId: existingId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n }\n } else {\n const newId = generateTargetId();\n result = await client.createPushTarget({\n targetId: newId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n await targetStore.set(result.id);\n }\n\n setTargetId(result.id);\n setTarget(result);\n\n // Subscribe to onTokenRefresh once.\n if (!tokenRefreshUnsubRef.current) {\n tokenRefreshUnsubRef.current = messaging.onTokenRefresh(async (newToken: string) => {\n try {\n const id = await targetStore.get();\n if (!id) return;\n const updated = await client.updatePushTarget(id, newToken);\n setToken(newToken);\n setTarget(updated);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n } finally {\n setIsRegistering(false);\n }\n }, [client, targetStore]);\n\n const unregister = useCallback(async (): Promise<void> => {\n const id = await targetStore.get();\n if (id) {\n try {\n await client.deletePushTarget(id);\n } catch {\n // Swallow network/404; we still want to clear local state.\n }\n await targetStore.clear();\n }\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n setTargetId(null);\n setToken(null);\n setTarget(null);\n }, [client, targetStore]);\n\n return {\n targetId,\n token,\n target,\n isRegistering,\n error,\n register,\n unregister,\n };\n}\n","import messagingImport, {\n type FirebaseMessagingTypes,\n} from '@react-native-firebase/messaging';\n\nlet cached: FirebaseMessagingTypes.Module | null = null;\n\nexport function firebaseMessaging(): FirebaseMessagingTypes.Module {\n if (cached) return cached;\n cached = messagingImport();\n return cached;\n}\n","import AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { StorageAdapter } from '../storage';\n\nexport function resolveStorage(explicit?: StorageAdapter): StorageAdapter {\n return explicit ?? AsyncStorage;\n}\n\nexport type { StorageAdapter };\n","import type { StorageAdapter } from './storage';\n\nconst KEY = 'fanapps.pushTargetId';\n\nexport class TargetIdStore {\n constructor(private readonly storage: StorageAdapter) {}\n\n get(): Promise<string | null> {\n return this.storage.getItem(KEY);\n }\n\n async set(id: string): Promise<void> {\n await this.storage.setItem(KEY, id);\n }\n\n async clear(): Promise<void> {\n await this.storage.removeItem(KEY);\n }\n}\n\nexport function generateTargetId(): string {\n // 16 bytes of URL-safe hex — safely within Appwrite's 36-char, safe-char constraint.\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useFanapps } from '@fanapps/react-native';\n\nexport interface UseTopicSubscriptionResult {\n /** Topic names the authenticated user is subscribed to. */\n topics: string[];\n isLoading: boolean;\n error: Error | null;\n subscribe(topic: string): Promise<void>;\n unsubscribe(topic: string): Promise<void>;\n refresh(): Promise<void>;\n}\n\nexport function useTopicSubscription(): UseTopicSubscriptionResult {\n const { client } = useFanapps();\n\n const [topics, setTopics] = useState<string[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const latestRequestRef = useRef(0);\n\n const refresh = useCallback(async () => {\n const requestId = ++latestRequestRef.current;\n setIsLoading(true);\n setError(null);\n try {\n const result = await client.listTopicSubscriptions();\n if (requestId !== latestRequestRef.current) return;\n setTopics(result);\n } catch (e) {\n if (requestId !== latestRequestRef.current) return;\n setError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n if (requestId === latestRequestRef.current) setIsLoading(false);\n }\n }, [client]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const subscribe = useCallback(\n async (topic: string) => {\n try {\n await client.subscribeToTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => (prev.includes(topic) ? prev : [...prev, topic]));\n },\n [client],\n );\n\n const unsubscribe = useCallback(\n async (topic: string) => {\n try {\n await client.unsubscribeFromTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => prev.filter((t) => t !== topic));\n },\n [client],\n );\n\n return { topics, isLoading, error, subscribe, unsubscribe, refresh };\n}\n"],"mappings":"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","names":["messagingImport","AsyncStorage","import_react_native","import_react","import_react_native"]}
package/dist/push.mjs CHANGED
@@ -144,15 +144,65 @@ function useRegisterDevice() {
144
144
  }
145
145
 
146
146
  // src/push/useTopicSubscription.ts
147
- import { useCallback as useCallback2 } from "react";
147
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
148
+ import { useFanapps as useFanapps2 } from "@fanapps/react-native";
148
149
  function useTopicSubscription() {
149
- const subscribe = useCallback2(async (topic) => {
150
- await firebaseMessaging().subscribeToTopic(topic);
151
- }, []);
152
- const unsubscribe = useCallback2(async (topic) => {
153
- await firebaseMessaging().unsubscribeFromTopic(topic);
154
- }, []);
155
- return { subscribe, unsubscribe };
150
+ const { client } = useFanapps2();
151
+ const [topics, setTopics] = useState2([]);
152
+ const [isLoading, setIsLoading] = useState2(true);
153
+ const [error, setError] = useState2(null);
154
+ const latestRequestRef = useRef2(0);
155
+ const refresh = useCallback2(async () => {
156
+ const requestId = ++latestRequestRef.current;
157
+ setIsLoading(true);
158
+ setError(null);
159
+ try {
160
+ const result = await client.listTopicSubscriptions();
161
+ if (requestId !== latestRequestRef.current) return;
162
+ setTopics(result);
163
+ } catch (e) {
164
+ if (requestId !== latestRequestRef.current) return;
165
+ setError(e instanceof Error ? e : new Error(String(e)));
166
+ } finally {
167
+ if (requestId === latestRequestRef.current) setIsLoading(false);
168
+ }
169
+ }, [client]);
170
+ useEffect2(() => {
171
+ void refresh();
172
+ }, [refresh]);
173
+ const subscribe = useCallback2(
174
+ async (topic) => {
175
+ try {
176
+ await client.subscribeToTopic(topic);
177
+ } catch (e) {
178
+ const err = e instanceof Error ? e : new Error(String(e));
179
+ setError(err);
180
+ throw err;
181
+ }
182
+ latestRequestRef.current++;
183
+ setIsLoading(false);
184
+ setError(null);
185
+ setTopics((prev) => prev.includes(topic) ? prev : [...prev, topic]);
186
+ },
187
+ [client]
188
+ );
189
+ const unsubscribe = useCallback2(
190
+ async (topic) => {
191
+ try {
192
+ await client.unsubscribeFromTopic(topic);
193
+ } catch (e) {
194
+ const err = e instanceof Error ? e : new Error(String(e));
195
+ setError(err);
196
+ throw err;
197
+ }
198
+ latestRequestRef.current++;
199
+ setIsLoading(false);
200
+ setError(null);
201
+ setTopics((prev) => prev.filter((t) => t !== topic));
202
+ },
203
+ [client]
204
+ );
205
+ return { topics, isLoading, error, subscribe, unsubscribe, refresh };
156
206
  }
157
207
  export {
158
208
  useRegisterDevice,
package/dist/push.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/push/useRegisterDevice.ts","../src/push/messaging.ts","../src/push/storage.ts","../src/push/targetIdStore.ts","../src/push/useTopicSubscription.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform } from 'react-native';\nimport { firebaseMessaging } from './messaging';\nimport { resolveStorage } from './storage';\nimport { generateTargetId, TargetIdStore } from './targetIdStore';\nimport { useFanapps, type PushTarget } from '@fanapps/react-native';\n\nexport interface UseRegisterDeviceResult {\n targetId: string | null;\n token: string | null;\n target: PushTarget | null;\n isRegistering: boolean;\n error: Error | null;\n register(): Promise<PushTarget>;\n unregister(): Promise<void>;\n}\n\nexport function useRegisterDevice(): UseRegisterDeviceResult {\n const { client, storage } = useFanapps();\n\n const [targetId, setTargetId] = useState<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [target, setTarget] = useState<PushTarget | null>(null);\n const [isRegistering, setIsRegistering] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const targetStoreRef = useRef<TargetIdStore | null>(null);\n if (!targetStoreRef.current) {\n targetStoreRef.current = new TargetIdStore(resolveStorage(storage));\n }\n const targetStore = targetStoreRef.current;\n\n const tokenRefreshUnsubRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n };\n }, []);\n\n const register = useCallback(async (): Promise<PushTarget> => {\n setIsRegistering(true);\n setError(null);\n try {\n const messaging = firebaseMessaging();\n\n // Request permission (idempotent; no-op if already granted).\n await messaging.requestPermission();\n\n const fcmToken = await messaging.getToken();\n setToken(fcmToken);\n\n const existingId = await targetStore.get();\n\n let result: PushTarget;\n if (existingId) {\n try {\n result = await client.updatePushTarget(existingId, fcmToken);\n } catch {\n // If the stored target is gone (404), create a new one with the same id.\n result = await client.createPushTarget({\n targetId: existingId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n }\n } else {\n const newId = generateTargetId();\n result = await client.createPushTarget({\n targetId: newId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n await targetStore.set(result.id);\n }\n\n setTargetId(result.id);\n setTarget(result);\n\n // Subscribe to onTokenRefresh once.\n if (!tokenRefreshUnsubRef.current) {\n tokenRefreshUnsubRef.current = messaging.onTokenRefresh(async (newToken: string) => {\n try {\n const id = await targetStore.get();\n if (!id) return;\n const updated = await client.updatePushTarget(id, newToken);\n setToken(newToken);\n setTarget(updated);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n } finally {\n setIsRegistering(false);\n }\n }, [client, targetStore]);\n\n const unregister = useCallback(async (): Promise<void> => {\n const id = await targetStore.get();\n if (id) {\n try {\n await client.deletePushTarget(id);\n } catch {\n // Swallow network/404; we still want to clear local state.\n }\n await targetStore.clear();\n }\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n setTargetId(null);\n setToken(null);\n setTarget(null);\n }, [client, targetStore]);\n\n return {\n targetId,\n token,\n target,\n isRegistering,\n error,\n register,\n unregister,\n };\n}\n","import messagingImport, {\n type FirebaseMessagingTypes,\n} from '@react-native-firebase/messaging';\n\nlet cached: FirebaseMessagingTypes.Module | null = null;\n\nexport function firebaseMessaging(): FirebaseMessagingTypes.Module {\n if (cached) return cached;\n cached = messagingImport();\n return cached;\n}\n","import AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { StorageAdapter } from '../storage';\n\nexport function resolveStorage(explicit?: StorageAdapter): StorageAdapter {\n return explicit ?? AsyncStorage;\n}\n\nexport type { StorageAdapter };\n","import type { StorageAdapter } from './storage';\n\nconst KEY = 'fanapps.pushTargetId';\n\nexport class TargetIdStore {\n constructor(private readonly storage: StorageAdapter) {}\n\n get(): Promise<string | null> {\n return this.storage.getItem(KEY);\n }\n\n async set(id: string): Promise<void> {\n await this.storage.setItem(KEY, id);\n }\n\n async clear(): Promise<void> {\n await this.storage.removeItem(KEY);\n }\n}\n\nexport function generateTargetId(): string {\n // 16 bytes of URL-safe hex — safely within Appwrite's 36-char, safe-char constraint.\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { useCallback } from 'react';\nimport { firebaseMessaging } from './messaging';\n\nexport interface UseTopicSubscriptionResult {\n subscribe(topic: string): Promise<void>;\n unsubscribe(topic: string): Promise<void>;\n}\n\nexport function useTopicSubscription(): UseTopicSubscriptionResult {\n const subscribe = useCallback(async (topic: string) => {\n await firebaseMessaging().subscribeToTopic(topic);\n }, []);\n\n const unsubscribe = useCallback(async (topic: string) => {\n await firebaseMessaging().unsubscribeFromTopic(topic);\n }, []);\n\n return { subscribe, unsubscribe };\n}\n"],"mappings":";AAAA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,gBAAgB;;;ACDzB,OAAO,qBAEA;AAEP,IAAI,SAA+C;AAE5C,SAAS,oBAAmD;AACjE,MAAI,OAAQ,QAAO;AACnB,WAAS,gBAAgB;AACzB,SAAO;AACT;;;ACVA,OAAO,kBAAkB;AAGlB,SAAS,eAAe,UAA2C;AACxE,SAAO,YAAY;AACrB;;;ACHA,IAAM,MAAM;AAEL,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAA6B,SAAyB;AAAzB;AAAA,EAA0B;AAAA,EAEvD,MAA8B;AAC5B,WAAO,KAAK,QAAQ,QAAQ,GAAG;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,IAA2B;AACnC,UAAM,KAAK,QAAQ,QAAQ,KAAK,EAAE;AAAA,EACpC;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,QAAQ,WAAW,GAAG;AAAA,EACnC;AACF;AAEO,SAAS,mBAA2B;AAEzC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,MAAI,OAAO,WAAW,QAAQ,oBAAoB,YAAY;AAC5D,eAAW,OAAO,gBAAgB,KAAK;AAAA,EACzC,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,OAAM,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EAClF;AACA,SAAO,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC1E;;;AHxBA,SAAS,kBAAmC;AAYrC,SAAS,oBAA6C;AAC3D,QAAM,EAAE,QAAQ,QAAQ,IAAI,WAAW;AAEvC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4B,IAAI;AAC5D,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AAErD,QAAM,iBAAiB,OAA6B,IAAI;AACxD,MAAI,CAAC,eAAe,SAAS;AAC3B,mBAAe,UAAU,IAAI,cAAc,eAAe,OAAO,CAAC;AAAA,EACpE;AACA,QAAM,cAAc,eAAe;AAEnC,QAAM,uBAAuB,OAA4B,IAAI;AAE7D,YAAU,MAAM;AACd,WAAO,MAAM;AACX,2BAAqB,UAAU;AAC/B,2BAAqB,UAAU;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,YAAY,YAAiC;AAC5D,qBAAiB,IAAI;AACrB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,YAAY,kBAAkB;AAGpC,YAAM,UAAU,kBAAkB;AAElC,YAAM,WAAW,MAAM,UAAU,SAAS;AAC1C,eAAS,QAAQ;AAEjB,YAAM,aAAa,MAAM,YAAY,IAAI;AAEzC,UAAI;AACJ,UAAI,YAAY;AACd,YAAI;AACF,mBAAS,MAAM,OAAO,iBAAiB,YAAY,QAAQ;AAAA,QAC7D,QAAQ;AAEN,mBAAS,MAAM,OAAO,iBAAiB;AAAA,YACrC,UAAU;AAAA,YACV,YAAY;AAAA,YACZ,QAAQ,SAAS,OAAO,QAAQ,QAAQ;AAAA,UAC1C,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,cAAM,QAAQ,iBAAiB;AAC/B,iBAAS,MAAM,OAAO,iBAAiB;AAAA,UACrC,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,QAAQ,SAAS,OAAO,QAAQ,QAAQ;AAAA,QAC1C,CAAC;AACD,cAAM,YAAY,IAAI,OAAO,EAAE;AAAA,MACjC;AAEA,kBAAY,OAAO,EAAE;AACrB,gBAAU,MAAM;AAGhB,UAAI,CAAC,qBAAqB,SAAS;AACjC,6BAAqB,UAAU,UAAU,eAAe,OAAO,aAAqB;AAClF,cAAI;AACF,kBAAM,KAAK,MAAM,YAAY,IAAI;AACjC,gBAAI,CAAC,GAAI;AACT,kBAAM,UAAU,MAAM,OAAO,iBAAiB,IAAI,QAAQ;AAC1D,qBAAS,QAAQ;AACjB,sBAAU,OAAO;AAAA,UACnB,SAAS,GAAG;AACV,qBAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,UACxD;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT,SAAS,GAAG;AACV,YAAM,MAAM,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AACxD,eAAS,GAAG;AACZ,YAAM;AAAA,IACR,UAAE;AACA,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,QAAM,aAAa,YAAY,YAA2B;AACxD,UAAM,KAAK,MAAM,YAAY,IAAI;AACjC,QAAI,IAAI;AACN,UAAI;AACF,cAAM,OAAO,iBAAiB,EAAE;AAAA,MAClC,QAAQ;AAAA,MAER;AACA,YAAM,YAAY,MAAM;AAAA,IAC1B;AACA,yBAAqB,UAAU;AAC/B,yBAAqB,UAAU;AAC/B,gBAAY,IAAI;AAChB,aAAS,IAAI;AACb,cAAU,IAAI;AAAA,EAChB,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AInIA,SAAS,eAAAA,oBAAmB;AAQrB,SAAS,uBAAmD;AACjE,QAAM,YAAYC,aAAY,OAAO,UAAkB;AACrD,UAAM,kBAAkB,EAAE,iBAAiB,KAAK;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,cAAcA,aAAY,OAAO,UAAkB;AACvD,UAAM,kBAAkB,EAAE,qBAAqB,KAAK;AAAA,EACtD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,YAAY;AAClC;","names":["useCallback","useCallback"]}
1
+ {"version":3,"sources":["../src/push/useRegisterDevice.ts","../src/push/messaging.ts","../src/push/storage.ts","../src/push/targetIdStore.ts","../src/push/useTopicSubscription.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform } from 'react-native';\nimport { firebaseMessaging } from './messaging';\nimport { resolveStorage } from './storage';\nimport { generateTargetId, TargetIdStore } from './targetIdStore';\nimport { useFanapps, type PushTarget } from '@fanapps/react-native';\n\nexport interface UseRegisterDeviceResult {\n targetId: string | null;\n token: string | null;\n target: PushTarget | null;\n isRegistering: boolean;\n error: Error | null;\n register(): Promise<PushTarget>;\n unregister(): Promise<void>;\n}\n\nexport function useRegisterDevice(): UseRegisterDeviceResult {\n const { client, storage } = useFanapps();\n\n const [targetId, setTargetId] = useState<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [target, setTarget] = useState<PushTarget | null>(null);\n const [isRegistering, setIsRegistering] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const targetStoreRef = useRef<TargetIdStore | null>(null);\n if (!targetStoreRef.current) {\n targetStoreRef.current = new TargetIdStore(resolveStorage(storage));\n }\n const targetStore = targetStoreRef.current;\n\n const tokenRefreshUnsubRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n };\n }, []);\n\n const register = useCallback(async (): Promise<PushTarget> => {\n setIsRegistering(true);\n setError(null);\n try {\n const messaging = firebaseMessaging();\n\n // Request permission (idempotent; no-op if already granted).\n await messaging.requestPermission();\n\n const fcmToken = await messaging.getToken();\n setToken(fcmToken);\n\n const existingId = await targetStore.get();\n\n let result: PushTarget;\n if (existingId) {\n try {\n result = await client.updatePushTarget(existingId, fcmToken);\n } catch {\n // If the stored target is gone (404), create a new one with the same id.\n result = await client.createPushTarget({\n targetId: existingId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n }\n } else {\n const newId = generateTargetId();\n result = await client.createPushTarget({\n targetId: newId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n await targetStore.set(result.id);\n }\n\n setTargetId(result.id);\n setTarget(result);\n\n // Subscribe to onTokenRefresh once.\n if (!tokenRefreshUnsubRef.current) {\n tokenRefreshUnsubRef.current = messaging.onTokenRefresh(async (newToken: string) => {\n try {\n const id = await targetStore.get();\n if (!id) return;\n const updated = await client.updatePushTarget(id, newToken);\n setToken(newToken);\n setTarget(updated);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n } finally {\n setIsRegistering(false);\n }\n }, [client, targetStore]);\n\n const unregister = useCallback(async (): Promise<void> => {\n const id = await targetStore.get();\n if (id) {\n try {\n await client.deletePushTarget(id);\n } catch {\n // Swallow network/404; we still want to clear local state.\n }\n await targetStore.clear();\n }\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n setTargetId(null);\n setToken(null);\n setTarget(null);\n }, [client, targetStore]);\n\n return {\n targetId,\n token,\n target,\n isRegistering,\n error,\n register,\n unregister,\n };\n}\n","import messagingImport, {\n type FirebaseMessagingTypes,\n} from '@react-native-firebase/messaging';\n\nlet cached: FirebaseMessagingTypes.Module | null = null;\n\nexport function firebaseMessaging(): FirebaseMessagingTypes.Module {\n if (cached) return cached;\n cached = messagingImport();\n return cached;\n}\n","import AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { StorageAdapter } from '../storage';\n\nexport function resolveStorage(explicit?: StorageAdapter): StorageAdapter {\n return explicit ?? AsyncStorage;\n}\n\nexport type { StorageAdapter };\n","import type { StorageAdapter } from './storage';\n\nconst KEY = 'fanapps.pushTargetId';\n\nexport class TargetIdStore {\n constructor(private readonly storage: StorageAdapter) {}\n\n get(): Promise<string | null> {\n return this.storage.getItem(KEY);\n }\n\n async set(id: string): Promise<void> {\n await this.storage.setItem(KEY, id);\n }\n\n async clear(): Promise<void> {\n await this.storage.removeItem(KEY);\n }\n}\n\nexport function generateTargetId(): string {\n // 16 bytes of URL-safe hex — safely within Appwrite's 36-char, safe-char constraint.\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useFanapps } from '@fanapps/react-native';\n\nexport interface UseTopicSubscriptionResult {\n /** Topic names the authenticated user is subscribed to. */\n topics: string[];\n isLoading: boolean;\n error: Error | null;\n subscribe(topic: string): Promise<void>;\n unsubscribe(topic: string): Promise<void>;\n refresh(): Promise<void>;\n}\n\nexport function useTopicSubscription(): UseTopicSubscriptionResult {\n const { client } = useFanapps();\n\n const [topics, setTopics] = useState<string[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const latestRequestRef = useRef(0);\n\n const refresh = useCallback(async () => {\n const requestId = ++latestRequestRef.current;\n setIsLoading(true);\n setError(null);\n try {\n const result = await client.listTopicSubscriptions();\n if (requestId !== latestRequestRef.current) return;\n setTopics(result);\n } catch (e) {\n if (requestId !== latestRequestRef.current) return;\n setError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n if (requestId === latestRequestRef.current) setIsLoading(false);\n }\n }, [client]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const subscribe = useCallback(\n async (topic: string) => {\n try {\n await client.subscribeToTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => (prev.includes(topic) ? prev : [...prev, topic]));\n },\n [client],\n );\n\n const unsubscribe = useCallback(\n async (topic: string) => {\n try {\n await client.unsubscribeFromTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => prev.filter((t) => t !== topic));\n },\n [client],\n );\n\n return { topics, isLoading, error, subscribe, unsubscribe, refresh };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useFanapps"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanapps/react-native",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "React Native SDK for the Fanapps API.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",