@fanapps/react-native 0.7.0 → 0.9.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
 
@@ -178,17 +179,27 @@ function PushSetup() {
178
179
 
179
180
  ### Subscribe to topics
180
181
 
181
- 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.
182
183
 
183
184
  ```tsx
184
185
  import { useTopicSubscription } from '@fanapps/react-native/push';
185
186
 
186
- const topics = useTopicSubscription();
187
- await topics.subscribe('news');
188
- 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
+ }
189
198
  ```
190
199
 
191
- 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.
192
203
 
193
204
  ### Displaying notifications
194
205
 
@@ -356,6 +367,31 @@ submit.mutate(
356
367
 
357
368
  On success the mutation invalidates the related `useTrivia(id)` query so `responses_count` and other derived values refresh.
358
369
 
370
+ ### Message inbox
371
+
372
+ ```ts
373
+ useMessages(filters?: MessageFilters, options?) // Paginated<InboxMessage>
374
+ useUnreadMessagesCount(options?) // number
375
+ useMarkMessageRead() // mutation
376
+ useMarkAllMessagesRead() // mutation
377
+ ```
378
+
379
+ Filters: `type` (`push` | `email` | `sms`), `unread`, `page`, `perPage`.
380
+
381
+ Inbox messages aren't localized, so these hooks' `options` accept only `{ enabled? }` — no `locale`.
382
+
383
+ ```tsx
384
+ const { data } = useMessages({ unread: true });
385
+ const { data: unread } = useUnreadMessagesCount();
386
+ const markRead = useMarkMessageRead();
387
+ const markAllRead = useMarkAllMessagesRead();
388
+
389
+ // markRead.mutate(message.id);
390
+ // markAllRead.mutate();
391
+ ```
392
+
393
+ On success, both mutations invalidate the `['fanapps', 'messages']` query prefix, refreshing the message list and unread count together.
394
+
359
395
  ## Escape hatch
360
396
 
361
397
  For endpoints not covered by a hook:
package/dist/index.d.mts CHANGED
@@ -180,6 +180,21 @@ interface UpdateEntryInput {
180
180
  terms?: Record<string, Array<number | string>>;
181
181
  [field: string]: unknown;
182
182
  }
183
+ type MessageType = 'push' | 'email' | 'sms';
184
+ interface InboxMessage {
185
+ id: string;
186
+ type: MessageType;
187
+ title: string | null;
188
+ body: string | null;
189
+ image: string | null;
190
+ data: Record<string, string> | null;
191
+ sent_at: string | null;
192
+ read_at: string | null;
193
+ }
194
+ interface MessageFilters extends Omit<PaginationParams, 'sort'> {
195
+ type?: MessageType;
196
+ unread?: boolean;
197
+ }
183
198
 
184
199
  interface FanappsProviderProps {
185
200
  apiKey: string;
@@ -212,6 +227,13 @@ declare class FanappsClient {
212
227
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
213
228
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
214
229
  deletePushTarget(targetId: string): Promise<void>;
230
+ listTopicSubscriptions(): Promise<string[]>;
231
+ subscribeToTopic(name: string): Promise<void>;
232
+ unsubscribeFromTopic(name: string): Promise<void>;
233
+ listMessages(filters?: MessageFilters, signal?: AbortSignal): Promise<Paginated<InboxMessage>>;
234
+ markMessageRead(id: string): Promise<InboxMessage>;
235
+ markAllMessagesRead(): Promise<number>;
236
+ getUnreadMessagesCount(signal?: AbortSignal): Promise<number>;
215
237
  createEntry(input: CreateEntryInput): Promise<Entry>;
216
238
  updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
217
239
  deleteEntry(id: string | number): Promise<void>;
@@ -318,4 +340,18 @@ interface SubmitTriviaResponseInput {
318
340
  }
319
341
  declare function useSubmitTriviaResponse(): UseMutationResult<TriviaResponseResult, FanappsError, SubmitTriviaResponseInput>;
320
342
 
321
- export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFieldFilters, type EntryFilterParams, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type Locale, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias, useUpdateEntry, useUploadAsset };
343
+ interface UseMessagesOptions {
344
+ enabled?: boolean;
345
+ }
346
+ declare function useMessages(filters?: MessageFilters, options?: UseMessagesOptions): UseQueryResult<Paginated<InboxMessage>>;
347
+
348
+ interface UseUnreadMessagesCountOptions {
349
+ enabled?: boolean;
350
+ }
351
+ declare function useUnreadMessagesCount(options?: UseUnreadMessagesCountOptions): UseQueryResult<number>;
352
+
353
+ declare function useMarkMessageRead(): UseMutationResult<InboxMessage, FanappsError, string>;
354
+
355
+ declare function useMarkAllMessagesRead(): UseMutationResult<number, FanappsError, void>;
356
+
357
+ export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFieldFilters, type EntryFilterParams, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type InboxMessage, type Locale, type MessageFilters, type MessageType, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, type UseMessagesOptions, type UseUnreadMessagesCountOptions, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useMarkAllMessagesRead, useMarkMessageRead, useMessages, useSubmitTriviaResponse, useTrivia, useTrivias, useUnreadMessagesCount, useUpdateEntry, useUploadAsset };
package/dist/index.d.ts CHANGED
@@ -180,6 +180,21 @@ interface UpdateEntryInput {
180
180
  terms?: Record<string, Array<number | string>>;
181
181
  [field: string]: unknown;
182
182
  }
183
+ type MessageType = 'push' | 'email' | 'sms';
184
+ interface InboxMessage {
185
+ id: string;
186
+ type: MessageType;
187
+ title: string | null;
188
+ body: string | null;
189
+ image: string | null;
190
+ data: Record<string, string> | null;
191
+ sent_at: string | null;
192
+ read_at: string | null;
193
+ }
194
+ interface MessageFilters extends Omit<PaginationParams, 'sort'> {
195
+ type?: MessageType;
196
+ unread?: boolean;
197
+ }
183
198
 
184
199
  interface FanappsProviderProps {
185
200
  apiKey: string;
@@ -212,6 +227,13 @@ declare class FanappsClient {
212
227
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
213
228
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
214
229
  deletePushTarget(targetId: string): Promise<void>;
230
+ listTopicSubscriptions(): Promise<string[]>;
231
+ subscribeToTopic(name: string): Promise<void>;
232
+ unsubscribeFromTopic(name: string): Promise<void>;
233
+ listMessages(filters?: MessageFilters, signal?: AbortSignal): Promise<Paginated<InboxMessage>>;
234
+ markMessageRead(id: string): Promise<InboxMessage>;
235
+ markAllMessagesRead(): Promise<number>;
236
+ getUnreadMessagesCount(signal?: AbortSignal): Promise<number>;
215
237
  createEntry(input: CreateEntryInput): Promise<Entry>;
216
238
  updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
217
239
  deleteEntry(id: string | number): Promise<void>;
@@ -318,4 +340,18 @@ interface SubmitTriviaResponseInput {
318
340
  }
319
341
  declare function useSubmitTriviaResponse(): UseMutationResult<TriviaResponseResult, FanappsError, SubmitTriviaResponseInput>;
320
342
 
321
- export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFieldFilters, type EntryFilterParams, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type Locale, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias, useUpdateEntry, useUploadAsset };
343
+ interface UseMessagesOptions {
344
+ enabled?: boolean;
345
+ }
346
+ declare function useMessages(filters?: MessageFilters, options?: UseMessagesOptions): UseQueryResult<Paginated<InboxMessage>>;
347
+
348
+ interface UseUnreadMessagesCountOptions {
349
+ enabled?: boolean;
350
+ }
351
+ declare function useUnreadMessagesCount(options?: UseUnreadMessagesCountOptions): UseQueryResult<number>;
352
+
353
+ declare function useMarkMessageRead(): UseMutationResult<InboxMessage, FanappsError, string>;
354
+
355
+ declare function useMarkAllMessagesRead(): UseMutationResult<number, FanappsError, void>;
356
+
357
+ export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFieldFilters, type EntryFilterParams, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type InboxMessage, type Locale, type MessageFilters, type MessageType, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, type UseMessagesOptions, type UseUnreadMessagesCountOptions, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useMarkAllMessagesRead, useMarkMessageRead, useMessages, useSubmitTriviaResponse, useTrivia, useTrivias, useUnreadMessagesCount, useUpdateEntry, useUploadAsset };
package/dist/index.js CHANGED
@@ -43,9 +43,13 @@ __export(src_exports, {
43
43
  useEntry: () => useEntry,
44
44
  useFanapps: () => useFanapps,
45
45
  useFanappsClient: () => useFanappsClient,
46
+ useMarkAllMessagesRead: () => useMarkAllMessagesRead,
47
+ useMarkMessageRead: () => useMarkMessageRead,
48
+ useMessages: () => useMessages,
46
49
  useSubmitTriviaResponse: () => useSubmitTriviaResponse,
47
50
  useTrivia: () => useTrivia,
48
51
  useTrivias: () => useTrivias,
52
+ useUnreadMessagesCount: () => useUnreadMessagesCount,
49
53
  useUpdateEntry: () => useUpdateEntry,
50
54
  useUploadAsset: () => useUploadAsset
51
55
  });
@@ -170,6 +174,53 @@ var FanappsClient = class {
170
174
  `/api/account/targets/push/${encodeURIComponent(targetId)}`
171
175
  );
172
176
  }
177
+ async listTopicSubscriptions() {
178
+ const response = await this.get("/api/account/topics");
179
+ return response.data;
180
+ }
181
+ async subscribeToTopic(name) {
182
+ await this.post(
183
+ `/api/account/topics/${encodeURIComponent(name)}`,
184
+ {}
185
+ );
186
+ }
187
+ async unsubscribeFromTopic(name) {
188
+ await this.delete(`/api/account/topics/${encodeURIComponent(name)}`);
189
+ }
190
+ listMessages(filters = {}, signal) {
191
+ const { type, unread, ...pagination } = filters;
192
+ return this.get(
193
+ "/api/account/messages",
194
+ {
195
+ ...pagination,
196
+ filter: {
197
+ ...type ? { type } : {},
198
+ ...unread ? { unread: 1 } : {}
199
+ }
200
+ },
201
+ signal
202
+ );
203
+ }
204
+ async markMessageRead(id) {
205
+ const response = await this.post(
206
+ `/api/account/messages/${encodeURIComponent(id)}/read`
207
+ );
208
+ return response.data;
209
+ }
210
+ async markAllMessagesRead() {
211
+ const response = await this.post(
212
+ "/api/account/messages/read-all"
213
+ );
214
+ return response.data.count;
215
+ }
216
+ async getUnreadMessagesCount(signal) {
217
+ const response = await this.get(
218
+ "/api/account/messages/unread-count",
219
+ void 0,
220
+ signal
221
+ );
222
+ return response.data.count;
223
+ }
173
224
  async createEntry(input) {
174
225
  return this.post("/api/entries", toEntryBody(input));
175
226
  }
@@ -610,6 +661,54 @@ function useSubmitTriviaResponse() {
610
661
  }
611
662
  });
612
663
  }
664
+
665
+ // src/hooks/useMessages.ts
666
+ var import_react_query13 = require("@tanstack/react-query");
667
+ function useMessages(filters = {}, options = {}) {
668
+ const { client } = useFanapps();
669
+ return (0, import_react_query13.useQuery)({
670
+ queryKey: ["fanapps", "messages", "list", filters],
671
+ queryFn: ({ signal }) => client.listMessages(filters, signal),
672
+ enabled: options.enabled ?? true
673
+ });
674
+ }
675
+
676
+ // src/hooks/useUnreadMessagesCount.ts
677
+ var import_react_query14 = require("@tanstack/react-query");
678
+ function useUnreadMessagesCount(options = {}) {
679
+ const { client } = useFanapps();
680
+ return (0, import_react_query14.useQuery)({
681
+ queryKey: ["fanapps", "messages", "unread-count"],
682
+ queryFn: ({ signal }) => client.getUnreadMessagesCount(signal),
683
+ enabled: options.enabled ?? true
684
+ });
685
+ }
686
+
687
+ // src/hooks/useMarkMessageRead.ts
688
+ var import_react_query15 = require("@tanstack/react-query");
689
+ function useMarkMessageRead() {
690
+ const { client } = useFanapps();
691
+ const queryClient = (0, import_react_query15.useQueryClient)();
692
+ return (0, import_react_query15.useMutation)({
693
+ mutationFn: (id) => client.markMessageRead(id),
694
+ onSuccess: () => {
695
+ queryClient.invalidateQueries({ queryKey: ["fanapps", "messages"] });
696
+ }
697
+ });
698
+ }
699
+
700
+ // src/hooks/useMarkAllMessagesRead.ts
701
+ var import_react_query16 = require("@tanstack/react-query");
702
+ function useMarkAllMessagesRead() {
703
+ const { client } = useFanapps();
704
+ const queryClient = (0, import_react_query16.useQueryClient)();
705
+ return (0, import_react_query16.useMutation)({
706
+ mutationFn: () => client.markAllMessagesRead(),
707
+ onSuccess: () => {
708
+ queryClient.invalidateQueries({ queryKey: ["fanapps", "messages"] });
709
+ }
710
+ });
711
+ }
613
712
  // Annotate the CommonJS export names for ESM import in node:
614
713
  0 && (module.exports = {
615
714
  FanappsAuthError,
@@ -625,9 +724,13 @@ function useSubmitTriviaResponse() {
625
724
  useEntry,
626
725
  useFanapps,
627
726
  useFanappsClient,
727
+ useMarkAllMessagesRead,
728
+ useMarkMessageRead,
729
+ useMessages,
628
730
  useSubmitTriviaResponse,
629
731
  useTrivia,
630
732
  useTrivias,
733
+ useUnreadMessagesCount,
631
734
  useUpdateEntry,
632
735
  useUploadAsset
633
736
  });
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 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"]}
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","../src/hooks/useMessages.ts","../src/hooks/useUnreadMessagesCount.ts","../src/hooks/useMarkMessageRead.ts","../src/hooks/useMarkAllMessagesRead.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 { useMessages, type UseMessagesOptions } from './hooks/useMessages';\nexport {\n useUnreadMessagesCount,\n type UseUnreadMessagesCountOptions,\n} from './hooks/useUnreadMessagesCount';\nexport { useMarkMessageRead } from './hooks/useMarkMessageRead';\nexport { useMarkAllMessagesRead } from './hooks/useMarkAllMessagesRead';\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 InboxMessage,\n Locale,\n MessageFilters,\n MessageType,\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 InboxMessage,\n MessageFilters,\n Paginated,\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 listMessages(\n filters: MessageFilters = {},\n signal?: AbortSignal,\n ): Promise<Paginated<InboxMessage>> {\n const { type, unread, ...pagination } = filters;\n return this.get<Paginated<InboxMessage>>(\n '/api/account/messages',\n {\n ...pagination,\n filter: {\n ...(type ? { type } : {}),\n ...(unread ? { unread: 1 } : {}),\n },\n },\n signal,\n );\n }\n\n async markMessageRead(id: string): Promise<InboxMessage> {\n const response = await this.post<{ data: InboxMessage }>(\n `/api/account/messages/${encodeURIComponent(id)}/read`,\n );\n return response.data;\n }\n\n async markAllMessagesRead(): Promise<number> {\n const response = await this.post<{ data: { count: number } }>(\n '/api/account/messages/read-all',\n );\n return response.data.count;\n }\n\n async getUnreadMessagesCount(signal?: AbortSignal): Promise<number> {\n const response = await this.get<{ data: { count: number } }>(\n '/api/account/messages/unread-count',\n undefined,\n signal,\n );\n return response.data.count;\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","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { InboxMessage, MessageFilters, Paginated } from '../types';\n\nexport interface UseMessagesOptions {\n enabled?: boolean;\n}\n\nexport function useMessages(\n filters: MessageFilters = {},\n options: UseMessagesOptions = {},\n): UseQueryResult<Paginated<InboxMessage>> {\n const { client } = useFanapps();\n\n return useQuery({\n queryKey: ['fanapps', 'messages', 'list', filters],\n queryFn: ({ signal }) => client.listMessages(filters, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\n\nexport interface UseUnreadMessagesCountOptions {\n enabled?: boolean;\n}\n\nexport function useUnreadMessagesCount(\n options: UseUnreadMessagesCountOptions = {},\n): UseQueryResult<number> {\n const { client } = useFanapps();\n\n return useQuery({\n queryKey: ['fanapps', 'messages', 'unread-count'],\n queryFn: ({ signal }) => client.getUnreadMessagesCount(signal),\n enabled: options.enabled ?? true,\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 { InboxMessage } from '../types';\n\nexport function useMarkMessageRead(): UseMutationResult<\n InboxMessage,\n FanappsError,\n string\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.markMessageRead(id),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'messages'] });\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 useMarkAllMessagesRead(): UseMutationResult<\n number,\n FanappsError,\n void\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: () => client.markAllMessagesRead(),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'messages'] });\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","import_react_query","import_react_query","import_react_query","import_react_query"]}
package/dist/index.mjs CHANGED
@@ -117,6 +117,53 @@ 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
+ }
133
+ listMessages(filters = {}, signal) {
134
+ const { type, unread, ...pagination } = filters;
135
+ return this.get(
136
+ "/api/account/messages",
137
+ {
138
+ ...pagination,
139
+ filter: {
140
+ ...type ? { type } : {},
141
+ ...unread ? { unread: 1 } : {}
142
+ }
143
+ },
144
+ signal
145
+ );
146
+ }
147
+ async markMessageRead(id) {
148
+ const response = await this.post(
149
+ `/api/account/messages/${encodeURIComponent(id)}/read`
150
+ );
151
+ return response.data;
152
+ }
153
+ async markAllMessagesRead() {
154
+ const response = await this.post(
155
+ "/api/account/messages/read-all"
156
+ );
157
+ return response.data.count;
158
+ }
159
+ async getUnreadMessagesCount(signal) {
160
+ const response = await this.get(
161
+ "/api/account/messages/unread-count",
162
+ void 0,
163
+ signal
164
+ );
165
+ return response.data.count;
166
+ }
120
167
  async createEntry(input) {
121
168
  return this.post("/api/entries", toEntryBody(input));
122
169
  }
@@ -566,6 +613,60 @@ function useSubmitTriviaResponse() {
566
613
  }
567
614
  });
568
615
  }
616
+
617
+ // src/hooks/useMessages.ts
618
+ import { useQuery as useQuery7 } from "@tanstack/react-query";
619
+ function useMessages(filters = {}, options = {}) {
620
+ const { client } = useFanapps();
621
+ return useQuery7({
622
+ queryKey: ["fanapps", "messages", "list", filters],
623
+ queryFn: ({ signal }) => client.listMessages(filters, signal),
624
+ enabled: options.enabled ?? true
625
+ });
626
+ }
627
+
628
+ // src/hooks/useUnreadMessagesCount.ts
629
+ import { useQuery as useQuery8 } from "@tanstack/react-query";
630
+ function useUnreadMessagesCount(options = {}) {
631
+ const { client } = useFanapps();
632
+ return useQuery8({
633
+ queryKey: ["fanapps", "messages", "unread-count"],
634
+ queryFn: ({ signal }) => client.getUnreadMessagesCount(signal),
635
+ enabled: options.enabled ?? true
636
+ });
637
+ }
638
+
639
+ // src/hooks/useMarkMessageRead.ts
640
+ import {
641
+ useMutation as useMutation6,
642
+ useQueryClient as useQueryClient5
643
+ } from "@tanstack/react-query";
644
+ function useMarkMessageRead() {
645
+ const { client } = useFanapps();
646
+ const queryClient = useQueryClient5();
647
+ return useMutation6({
648
+ mutationFn: (id) => client.markMessageRead(id),
649
+ onSuccess: () => {
650
+ queryClient.invalidateQueries({ queryKey: ["fanapps", "messages"] });
651
+ }
652
+ });
653
+ }
654
+
655
+ // src/hooks/useMarkAllMessagesRead.ts
656
+ import {
657
+ useMutation as useMutation7,
658
+ useQueryClient as useQueryClient6
659
+ } from "@tanstack/react-query";
660
+ function useMarkAllMessagesRead() {
661
+ const { client } = useFanapps();
662
+ const queryClient = useQueryClient6();
663
+ return useMutation7({
664
+ mutationFn: () => client.markAllMessagesRead(),
665
+ onSuccess: () => {
666
+ queryClient.invalidateQueries({ queryKey: ["fanapps", "messages"] });
667
+ }
668
+ });
669
+ }
569
670
  export {
570
671
  FanappsAuthError,
571
672
  FanappsClient,
@@ -580,9 +681,13 @@ export {
580
681
  useEntry,
581
682
  useFanapps,
582
683
  useFanappsClient,
684
+ useMarkAllMessagesRead,
685
+ useMarkMessageRead,
686
+ useMessages,
583
687
  useSubmitTriviaResponse,
584
688
  useTrivia,
585
689
  useTrivias,
690
+ useUnreadMessagesCount,
586
691
  useUpdateEntry,
587
692
  useUploadAsset
588
693
  };
@@ -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 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"]}
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","../src/hooks/useMessages.ts","../src/hooks/useUnreadMessagesCount.ts","../src/hooks/useMarkMessageRead.ts","../src/hooks/useMarkAllMessagesRead.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 InboxMessage,\n MessageFilters,\n Paginated,\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 listMessages(\n filters: MessageFilters = {},\n signal?: AbortSignal,\n ): Promise<Paginated<InboxMessage>> {\n const { type, unread, ...pagination } = filters;\n return this.get<Paginated<InboxMessage>>(\n '/api/account/messages',\n {\n ...pagination,\n filter: {\n ...(type ? { type } : {}),\n ...(unread ? { unread: 1 } : {}),\n },\n },\n signal,\n );\n }\n\n async markMessageRead(id: string): Promise<InboxMessage> {\n const response = await this.post<{ data: InboxMessage }>(\n `/api/account/messages/${encodeURIComponent(id)}/read`,\n );\n return response.data;\n }\n\n async markAllMessagesRead(): Promise<number> {\n const response = await this.post<{ data: { count: number } }>(\n '/api/account/messages/read-all',\n );\n return response.data.count;\n }\n\n async getUnreadMessagesCount(signal?: AbortSignal): Promise<number> {\n const response = await this.get<{ data: { count: number } }>(\n '/api/account/messages/unread-count',\n undefined,\n signal,\n );\n return response.data.count;\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","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { InboxMessage, MessageFilters, Paginated } from '../types';\n\nexport interface UseMessagesOptions {\n enabled?: boolean;\n}\n\nexport function useMessages(\n filters: MessageFilters = {},\n options: UseMessagesOptions = {},\n): UseQueryResult<Paginated<InboxMessage>> {\n const { client } = useFanapps();\n\n return useQuery({\n queryKey: ['fanapps', 'messages', 'list', filters],\n queryFn: ({ signal }) => client.listMessages(filters, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\n\nexport interface UseUnreadMessagesCountOptions {\n enabled?: boolean;\n}\n\nexport function useUnreadMessagesCount(\n options: UseUnreadMessagesCountOptions = {},\n): UseQueryResult<number> {\n const { client } = useFanapps();\n\n return useQuery({\n queryKey: ['fanapps', 'messages', 'unread-count'],\n queryFn: ({ signal }) => client.getUnreadMessagesCount(signal),\n enabled: options.enabled ?? true,\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 { InboxMessage } from '../types';\n\nexport function useMarkMessageRead(): UseMutationResult<\n InboxMessage,\n FanappsError,\n string\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.markMessageRead(id),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'messages'] });\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 useMarkAllMessagesRead(): UseMutationResult<\n number,\n FanappsError,\n void\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: () => client.markAllMessagesRead(),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'messages'] });\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","useQuery","useQuery","useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation","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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyD;AACzD,0BAAyB;;;ACDzB,uBAEO;AAEP,IAAI,SAA+C;AAE5C,SAAS,oBAAmD;AACjE,MAAI,OAAQ,QAAO;AACnB,eAAS,iBAAAA,SAAgB;AACzB,SAAO;AACT;;;ACVA,2BAAyB;AAGlB,SAAS,eAAe,UAA2C;AACxE,SAAO,YAAY,qBAAAC;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,IAAAC,uBAA4C;AAYrC,SAAS,oBAA6C;AAC3D,QAAM,EAAE,QAAQ,QAAQ,QAAI,iCAAW;AAEvC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAwB,IAAI;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AACtD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAA4B,IAAI;AAC5D,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,KAAK;AACxD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAuB,IAAI;AAErD,QAAM,qBAAiB,qBAA6B,IAAI;AACxD,MAAI,CAAC,eAAe,SAAS;AAC3B,mBAAe,UAAU,IAAI,cAAc,eAAe,OAAO,CAAC;AAAA,EACpE;AACA,QAAM,cAAc,eAAe;AAEnC,QAAM,2BAAuB,qBAA4B,IAAI;AAE7D,8BAAU,MAAM;AACd,WAAO,MAAM;AACX,2BAAqB,UAAU;AAC/B,2BAAqB,UAAU;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAW,0BAAY,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,6BAAS,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,6BAAS,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,iBAAa,0BAAY,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,IAAAC,gBAAyD;AACzD,IAAAC,uBAA2B;AAYpB,SAAS,uBAAmD;AACjE,QAAM,EAAE,OAAO,QAAI,iCAAW;AAE9B,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAAmB,CAAC,CAAC;AACjD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,QAAM,uBAAmB,sBAAO,CAAC;AAEjC,QAAM,cAAU,2BAAY,YAAY;AACtC,UAAM,YAAY,EAAE,iBAAiB;AACrC,iBAAa,IAAI;AACjB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,uBAAuB;AACnD,UAAI,cAAc,iBAAiB,QAAS;AAC5C,gBAAU,MAAM;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,cAAc,iBAAiB,QAAS;AAC5C,eAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,IACxD,UAAE;AACA,UAAI,cAAc,iBAAiB,QAAS,cAAa,KAAK;AAAA,IAChE;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,+BAAU,MAAM;AACd,SAAK,QAAQ;AAAA,EACf,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,gBAAY;AAAA,IAChB,OAAO,UAAkB;AACvB,UAAI;AACF,cAAM,OAAO,iBAAiB,KAAK;AAAA,MACrC,SAAS,GAAG;AACV,cAAM,MAAM,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AACxD,iBAAS,GAAG;AACZ,cAAM;AAAA,MACR;AACA,uBAAiB;AACjB,mBAAa,KAAK;AAClB,eAAS,IAAI;AACb,gBAAU,CAAC,SAAU,KAAK,SAAS,KAAK,IAAI,OAAO,CAAC,GAAG,MAAM,KAAK,CAAE;AAAA,IACtE;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,kBAAc;AAAA,IAClB,OAAO,UAAkB;AACvB,UAAI;AACF,cAAM,OAAO,qBAAqB,KAAK;AAAA,MACzC,SAAS,GAAG;AACV,cAAM,MAAM,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AACxD,iBAAS,GAAG;AACZ,cAAM;AAAA,MACR;AACA,uBAAiB;AACjB,mBAAa,KAAK;AAClB,eAAS,IAAI;AACb,gBAAU,CAAC,SAAS,KAAK,OAAO,CAAC,MAAM,MAAM,KAAK,CAAC;AAAA,IACrD;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,SAAO,EAAE,QAAQ,WAAW,OAAO,WAAW,aAAa,QAAQ;AACrE;","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":"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","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.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "React Native SDK for the Fanapps API.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",