@fanapps/react-native 0.4.0 → 0.5.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 +108 -2
- package/dist/apple.js +4 -14
- package/dist/apple.js.map +1 -1
- package/dist/apple.mjs +1 -4
- package/dist/apple.mjs.map +1 -1
- package/dist/index.d.mts +209 -3
- package/dist/index.d.ts +209 -3
- package/dist/index.js +144 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +161 -12
- package/dist/index.mjs.map +1 -1
- package/dist/push.d.mts +2 -2
- package/dist/push.d.ts +2 -2
- package/dist/push.js +16 -28
- package/dist/push.js.map +1 -1
- package/dist/push.mjs +1 -4
- package/dist/push.mjs.map +1 -1
- package/dist/storage-D6z5ScLn.d.mts +14 -0
- package/dist/storage-D6z5ScLn.d.ts +14 -0
- package/package.json +1 -1
- package/dist/chunk-SWOKCWWX.mjs +0 -13
- package/dist/chunk-SWOKCWWX.mjs.map +0 -1
- package/dist/chunk-YZINATR6.mjs +0 -18
- package/dist/chunk-YZINATR6.mjs.map +0 -1
- package/dist/types-CKpYrzCw.d.mts +0 -147
- package/dist/types-CKpYrzCw.d.ts +0 -147
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx","../src/auth/firebaseApp.ts","../src/auth/authStore.ts","../src/errors.ts","../src/client.ts","../src/hooks/useFanappsClient.ts","../src/hooks/useAuth.ts","../src/hooks/useEntries.ts","../src/hooks/useEntry.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 { CreatePushTargetInput, PushTarget } 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 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 for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(\n `${encodeURIComponent(key)}[]=${encodeURIComponent(String(item))}`,\n );\n }\n continue;\n }\n parts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,\n );\n }\n return parts.join('&');\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\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 { 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","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery"]}
|
|
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 for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) continue;\n parts.push(\n `${encodeURIComponent(key)}[]=${encodeURIComponent(String(item))}`,\n );\n }\n continue;\n }\n parts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,\n );\n }\n return parts.join('&');\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction toEntryBody(\n input: Omit<CreateEntryInput, never> | Omit<UpdateEntryInput, 'id'>,\n): Record<string, unknown> {\n const { publishedAt, ...rest } = input as Record<string, unknown> & {\n publishedAt?: string | null;\n };\n const body: Record<string, unknown> = { ...rest };\n if (publishedAt !== undefined) {\n body.published_at = publishedAt;\n }\n return body;\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthStore } from './auth/authStore';\nimport type { FanappsClient } from './client';\nimport type { StorageAdapter } from './storage';\nimport type { Locale } from './types';\n\nexport interface FanappsContextValue {\n client: FanappsClient;\n authStore: AuthStore;\n storage: StorageAdapter | undefined;\n locale?: Locale;\n}\n\nexport const FanappsContext = createContext<FanappsContextValue | null>(null);\n\nexport function useFanapps(): FanappsContextValue {\n const ctx = useContext(FanappsContext);\n if (!ctx) {\n throw new Error(\n '@fanapps/react-native: useFanapps must be used inside <FanappsProvider>.',\n );\n }\n return ctx;\n}\n","export class FanappsAuthError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = 'FanappsAuthError';\n this.code = code;\n }\n}\n","import { useFanapps } from '../context';\nimport type { FanappsClient } from '../client';\n\nexport function useFanappsClient(): FanappsClient {\n return useFanapps().client;\n}\n","import { useSyncExternalStore, useCallback } from 'react';\nimport { firebaseAuth } from '../auth/firebaseApp';\nimport { useFanapps } from '../context';\nimport type { AuthStatus, AuthUser } from '../types';\n\nexport interface UseAuthResult {\n user: AuthUser | null;\n status: AuthStatus;\n signInWithEmail(email: string, password: string): Promise<AuthUser>;\n signUpWithEmail(email: string, password: string): Promise<AuthUser>;\n sendPasswordResetEmail(email: string): Promise<void>;\n sendEmailVerification(): Promise<void>;\n signOut(): Promise<void>;\n}\n\nexport function useAuth(): UseAuthResult {\n const { authStore } = useFanapps();\n\n const snapshot = useSyncExternalStore(\n (listener) => authStore.subscribe(listener),\n () => authStore.getSnapshot(),\n () => authStore.getSnapshot(),\n );\n\n const signInWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().signInWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const signUpWithEmail = useCallback(\n async (email: string, password: string) => {\n const cred = await firebaseAuth().createUserWithEmailAndPassword(email, password);\n return authStore.getSnapshot().user ?? mapMinimal(cred.user);\n },\n [authStore],\n );\n\n const sendPasswordResetEmail = useCallback(async (email: string) => {\n await firebaseAuth().sendPasswordResetEmail(email);\n }, []);\n\n const sendEmailVerification = useCallback(async () => {\n const current = firebaseAuth().currentUser;\n if (!current) throw new Error('No signed-in user to verify.');\n await current.sendEmailVerification();\n }, []);\n\n const signOut = useCallback(async () => {\n await firebaseAuth().signOut();\n }, []);\n\n return {\n user: snapshot.user,\n status: snapshot.status,\n signInWithEmail,\n signUpWithEmail,\n sendPasswordResetEmail,\n sendEmailVerification,\n signOut,\n };\n}\n\ninterface MinimalFirebaseUser {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n phoneNumber: string | null;\n isAnonymous: boolean;\n providerId?: string | null;\n}\n\nfunction mapMinimal(fb: MinimalFirebaseUser): AuthUser {\n return {\n uid: fb.uid,\n email: fb.email,\n displayName: fb.displayName,\n photoURL: fb.photoURL,\n phoneNumber: fb.phoneNumber,\n isAnonymous: fb.isAnonymous,\n providerId: fb.providerId ?? null,\n };\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, EntryFilters, HookOptions, Paginated } from '../types';\n\nexport function useEntries(\n filters: EntryFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Entry>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entries', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Entry>>('/api/entries', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Entry, HookOptions } from '../types';\n\nexport function useEntry(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Entry> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'entry', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Entry }>(\n `/api/entries/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { CreateEntryInput, Entry } from '../types';\n\nexport function useCreateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n CreateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.createEntry(input),\n onSuccess: (entry) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Entry, UpdateEntryInput } from '../types';\n\nexport function useUpdateEntry(): UseMutationResult<\n Entry,\n FanappsError,\n UpdateEntryInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input) => client.updateEntry(input),\n onSuccess: (entry, variables) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', variables.id],\n });\n if (entry.id !== variables.id) {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'entry', entry.id],\n });\n }\n },\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\n\nexport function useDeleteEntry(): UseMutationResult<\n void,\n FanappsError,\n string | number\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (id) => client.deleteEntry(id),\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'entries'] });\n queryClient.removeQueries({ queryKey: ['fanapps', 'entry', id] });\n },\n });\n}\n","import { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { Asset, UploadAssetInput } from '../types';\n\nexport function useUploadAsset(): UseMutationResult<\n Asset,\n FanappsError,\n UploadAssetInput\n> {\n const { client } = useFanapps();\n\n return useMutation({\n mutationFn: (input) => client.uploadAsset(input),\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, ArticleFilters, HookOptions, Paginated } from '../types';\n\nexport function useArticles(\n filters: ArticleFilters = {},\n options: HookOptions = {},\n): UseQueryResult<Paginated<Article>> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'articles', { locale, ...filters }],\n queryFn: ({ signal }) =>\n client.get<Paginated<Article>>('/api/articles', { ...filters, locale }, signal),\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { Article, HookOptions } from '../types';\n\nexport function useArticle(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Article> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'article', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Article }>(\n `/api/articles/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivias(\n options: HookOptions = {},\n): UseQueryResult<Trivia[]> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivias', { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia[] }>(\n '/api/trivias',\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: options.enabled ?? true,\n });\n}\n","import { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { HookOptions, Trivia } from '../types';\n\nexport function useTrivia(\n id: string | number | null | undefined,\n options: HookOptions = {},\n): UseQueryResult<Trivia> {\n const { client, locale: providerLocale } = useFanapps();\n const locale = options.locale ?? providerLocale;\n\n return useQuery({\n queryKey: ['fanapps', 'trivia', id, { locale }],\n queryFn: async ({ signal }) => {\n const response = await client.get<{ data: Trivia }>(\n `/api/trivias/${id}`,\n { locale },\n signal,\n );\n return response.data;\n },\n enabled: (options.enabled ?? true) && id != null && id !== '',\n });\n}\n","import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';\nimport { useFanapps } from '../context';\nimport type { FanappsError } from '../errors';\nimport type { TriviaResponseResult } from '../types';\n\nexport interface SubmitTriviaResponseInput {\n triviaId: string | number;\n answerId: string | number;\n}\n\nexport function useSubmitTriviaResponse(): UseMutationResult<\n TriviaResponseResult,\n FanappsError,\n SubmitTriviaResponseInput\n> {\n const { client } = useFanapps();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ triviaId, answerId }) =>\n client.post<TriviaResponseResult>(`/api/trivias/${triviaId}/respond`, {\n answer_id: answerId,\n }),\n onSuccess: (_result, variables) => {\n queryClient.invalidateQueries({\n queryKey: ['fanapps', 'trivia', variables.triviaId],\n });\n queryClient.invalidateQueries({ queryKey: ['fanapps', 'trivias'] });\n },\n });\n}\n"],"mappings":"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","names":["useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useQueryClient","useQueryClient","useMutation","useMutation","useMutation","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useMutation","useQueryClient","useQueryClient","useMutation"]}
|
package/dist/push.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { S as StorageAdapter } from './
|
|
1
|
+
import { PushTarget } from '@fanapps/react-native';
|
|
2
|
+
export { S as StorageAdapter } from './storage-D6z5ScLn.mjs';
|
|
3
3
|
|
|
4
4
|
interface UseRegisterDeviceResult {
|
|
5
5
|
targetId: string | null;
|
package/dist/push.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { S as StorageAdapter } from './
|
|
1
|
+
import { PushTarget } from '@fanapps/react-native';
|
|
2
|
+
export { S as StorageAdapter } from './storage-D6z5ScLn.js';
|
|
3
3
|
|
|
4
4
|
interface UseRegisterDeviceResult {
|
|
5
5
|
targetId: string | null;
|
package/dist/push.js
CHANGED
|
@@ -36,7 +36,7 @@ __export(push_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(push_exports);
|
|
37
37
|
|
|
38
38
|
// src/push/useRegisterDevice.ts
|
|
39
|
-
var
|
|
39
|
+
var import_react = require("react");
|
|
40
40
|
var import_react_native = require("react-native");
|
|
41
41
|
|
|
42
42
|
// src/push/messaging.ts
|
|
@@ -80,40 +80,28 @@ function generateTargetId() {
|
|
|
80
80
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// src/context.ts
|
|
84
|
-
var import_react = require("react");
|
|
85
|
-
var FanappsContext = (0, import_react.createContext)(null);
|
|
86
|
-
function useFanapps() {
|
|
87
|
-
const ctx = (0, import_react.useContext)(FanappsContext);
|
|
88
|
-
if (!ctx) {
|
|
89
|
-
throw new Error(
|
|
90
|
-
"@fanapps/react-native: useFanapps must be used inside <FanappsProvider>."
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
return ctx;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
83
|
// src/push/useRegisterDevice.ts
|
|
84
|
+
var import_react_native2 = require("@fanapps/react-native");
|
|
97
85
|
function useRegisterDevice() {
|
|
98
|
-
const { client, storage } = useFanapps();
|
|
99
|
-
const [targetId, setTargetId] = (0,
|
|
100
|
-
const [token, setToken] = (0,
|
|
101
|
-
const [target, setTarget] = (0,
|
|
102
|
-
const [isRegistering, setIsRegistering] = (0,
|
|
103
|
-
const [error, setError] = (0,
|
|
104
|
-
const targetStoreRef = (0,
|
|
86
|
+
const { client, storage } = (0, import_react_native2.useFanapps)();
|
|
87
|
+
const [targetId, setTargetId] = (0, import_react.useState)(null);
|
|
88
|
+
const [token, setToken] = (0, import_react.useState)(null);
|
|
89
|
+
const [target, setTarget] = (0, import_react.useState)(null);
|
|
90
|
+
const [isRegistering, setIsRegistering] = (0, import_react.useState)(false);
|
|
91
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
92
|
+
const targetStoreRef = (0, import_react.useRef)(null);
|
|
105
93
|
if (!targetStoreRef.current) {
|
|
106
94
|
targetStoreRef.current = new TargetIdStore(resolveStorage(storage));
|
|
107
95
|
}
|
|
108
96
|
const targetStore = targetStoreRef.current;
|
|
109
|
-
const tokenRefreshUnsubRef = (0,
|
|
110
|
-
(0,
|
|
97
|
+
const tokenRefreshUnsubRef = (0, import_react.useRef)(null);
|
|
98
|
+
(0, import_react.useEffect)(() => {
|
|
111
99
|
return () => {
|
|
112
100
|
tokenRefreshUnsubRef.current?.();
|
|
113
101
|
tokenRefreshUnsubRef.current = null;
|
|
114
102
|
};
|
|
115
103
|
}, []);
|
|
116
|
-
const register = (0,
|
|
104
|
+
const register = (0, import_react.useCallback)(async () => {
|
|
117
105
|
setIsRegistering(true);
|
|
118
106
|
setError(null);
|
|
119
107
|
try {
|
|
@@ -166,7 +154,7 @@ function useRegisterDevice() {
|
|
|
166
154
|
setIsRegistering(false);
|
|
167
155
|
}
|
|
168
156
|
}, [client, targetStore]);
|
|
169
|
-
const unregister = (0,
|
|
157
|
+
const unregister = (0, import_react.useCallback)(async () => {
|
|
170
158
|
const id = await targetStore.get();
|
|
171
159
|
if (id) {
|
|
172
160
|
try {
|
|
@@ -193,12 +181,12 @@ function useRegisterDevice() {
|
|
|
193
181
|
}
|
|
194
182
|
|
|
195
183
|
// src/push/useTopicSubscription.ts
|
|
196
|
-
var
|
|
184
|
+
var import_react2 = require("react");
|
|
197
185
|
function useTopicSubscription() {
|
|
198
|
-
const subscribe = (0,
|
|
186
|
+
const subscribe = (0, import_react2.useCallback)(async (topic) => {
|
|
199
187
|
await firebaseMessaging().subscribeToTopic(topic);
|
|
200
188
|
}, []);
|
|
201
|
-
const unsubscribe = (0,
|
|
189
|
+
const unsubscribe = (0, import_react2.useCallback)(async (topic) => {
|
|
202
190
|
await firebaseMessaging().unsubscribeFromTopic(topic);
|
|
203
191
|
}, []);
|
|
204
192
|
return { subscribe, unsubscribe };
|
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/context.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 } from '../context';\nimport type { PushTarget } from '../types';\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 { 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","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":["import_react","messagingImport","AsyncStorage","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 } 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"]}
|
package/dist/push.mjs
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useFanapps
|
|
3
|
-
} from "./chunk-YZINATR6.mjs";
|
|
4
|
-
|
|
5
1
|
// src/push/useRegisterDevice.ts
|
|
6
2
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
3
|
import { Platform } from "react-native";
|
|
@@ -48,6 +44,7 @@ function generateTargetId() {
|
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
// src/push/useRegisterDevice.ts
|
|
47
|
+
import { useFanapps } from "@fanapps/react-native";
|
|
51
48
|
function useRegisterDevice() {
|
|
52
49
|
const { client, storage } = useFanapps();
|
|
53
50
|
const [targetId, setTargetId] = useState(null);
|
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
|
|
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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape for SDK persistent storage. Matches `@react-native-async-storage/async-storage`'s
|
|
3
|
+
* default-export interface so users can pass it through directly.
|
|
4
|
+
*
|
|
5
|
+
* The interface lives in the core entry (no implementation import) so consumers who don't
|
|
6
|
+
* use push features don't pull AsyncStorage into their bundle.
|
|
7
|
+
*/
|
|
8
|
+
interface StorageAdapter {
|
|
9
|
+
getItem(key: string): Promise<string | null>;
|
|
10
|
+
setItem(key: string, value: string): Promise<void>;
|
|
11
|
+
removeItem(key: string): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type { StorageAdapter as S };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape for SDK persistent storage. Matches `@react-native-async-storage/async-storage`'s
|
|
3
|
+
* default-export interface so users can pass it through directly.
|
|
4
|
+
*
|
|
5
|
+
* The interface lives in the core entry (no implementation import) so consumers who don't
|
|
6
|
+
* use push features don't pull AsyncStorage into their bundle.
|
|
7
|
+
*/
|
|
8
|
+
interface StorageAdapter {
|
|
9
|
+
getItem(key: string): Promise<string | null>;
|
|
10
|
+
setItem(key: string, value: string): Promise<void>;
|
|
11
|
+
removeItem(key: string): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type { StorageAdapter as S };
|
package/package.json
CHANGED
package/dist/chunk-SWOKCWWX.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// src/auth/errors.ts
|
|
2
|
-
var FanappsAuthError = class extends Error {
|
|
3
|
-
constructor(message, code) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.name = "FanappsAuthError";
|
|
6
|
-
this.code = code;
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
FanappsAuthError
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=chunk-SWOKCWWX.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth/errors.ts"],"sourcesContent":["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"],"mappings":";AAAO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAG1C,YAAY,SAAiB,MAAc;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
package/dist/chunk-YZINATR6.mjs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// src/context.ts
|
|
2
|
-
import { createContext, useContext } from "react";
|
|
3
|
-
var FanappsContext = createContext(null);
|
|
4
|
-
function useFanapps() {
|
|
5
|
-
const ctx = useContext(FanappsContext);
|
|
6
|
-
if (!ctx) {
|
|
7
|
-
throw new Error(
|
|
8
|
-
"@fanapps/react-native: useFanapps must be used inside <FanappsProvider>."
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
return ctx;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
FanappsContext,
|
|
16
|
-
useFanapps
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=chunk-YZINATR6.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts"],"sourcesContent":["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"],"mappings":";AAAA,SAAS,eAAe,kBAAkB;AAanC,IAAM,iBAAiB,cAA0C,IAAI;AAErE,SAAS,aAAkC;AAChD,QAAM,MAAM,WAAW,cAAc;AACrC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shape for SDK persistent storage. Matches `@react-native-async-storage/async-storage`'s
|
|
3
|
-
* default-export interface so users can pass it through directly.
|
|
4
|
-
*
|
|
5
|
-
* The interface lives in the core entry (no implementation import) so consumers who don't
|
|
6
|
-
* use push features don't pull AsyncStorage into their bundle.
|
|
7
|
-
*/
|
|
8
|
-
interface StorageAdapter {
|
|
9
|
-
getItem(key: string): Promise<string | null>;
|
|
10
|
-
setItem(key: string, value: string): Promise<void>;
|
|
11
|
-
removeItem(key: string): Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type Locale = string;
|
|
15
|
-
type EntryData = Record<string, unknown>;
|
|
16
|
-
interface Entry {
|
|
17
|
-
id: string | number;
|
|
18
|
-
slug: string;
|
|
19
|
-
published: boolean;
|
|
20
|
-
date: string | null;
|
|
21
|
-
order: number | null;
|
|
22
|
-
collection: string | null;
|
|
23
|
-
blueprint: string;
|
|
24
|
-
data: EntryData;
|
|
25
|
-
created_at: string;
|
|
26
|
-
updated_at: string;
|
|
27
|
-
locale: Locale;
|
|
28
|
-
available_locales?: Locale[];
|
|
29
|
-
}
|
|
30
|
-
type ArticleStatus = 'draft' | 'scheduled' | 'published';
|
|
31
|
-
interface Article {
|
|
32
|
-
id: string | number;
|
|
33
|
-
title: string;
|
|
34
|
-
content: string;
|
|
35
|
-
status: ArticleStatus;
|
|
36
|
-
published_at: string | null;
|
|
37
|
-
featured_image_url: string | null;
|
|
38
|
-
created_at: string;
|
|
39
|
-
updated_at: string;
|
|
40
|
-
locale: Locale;
|
|
41
|
-
available_locales?: Locale[];
|
|
42
|
-
}
|
|
43
|
-
interface TriviaAnswer {
|
|
44
|
-
id: string | number;
|
|
45
|
-
text: string;
|
|
46
|
-
is_correct: boolean;
|
|
47
|
-
sort_order: number;
|
|
48
|
-
}
|
|
49
|
-
interface Trivia {
|
|
50
|
-
id: string | number;
|
|
51
|
-
title: string;
|
|
52
|
-
description: string | null;
|
|
53
|
-
featured_image_id: string | number | null;
|
|
54
|
-
featured_image?: {
|
|
55
|
-
id: string | number;
|
|
56
|
-
url: string;
|
|
57
|
-
[key: string]: unknown;
|
|
58
|
-
} | null;
|
|
59
|
-
awards_points: boolean;
|
|
60
|
-
points_amount: number;
|
|
61
|
-
max_time_seconds: number | null;
|
|
62
|
-
show_correct_after: boolean;
|
|
63
|
-
starts_at: string | null;
|
|
64
|
-
ends_at: string | null;
|
|
65
|
-
answers: TriviaAnswer[];
|
|
66
|
-
responses_count?: number;
|
|
67
|
-
created_at: string;
|
|
68
|
-
updated_at: string;
|
|
69
|
-
}
|
|
70
|
-
interface TriviaResponseResult {
|
|
71
|
-
is_correct: boolean;
|
|
72
|
-
points_awarded: number;
|
|
73
|
-
correct_answer?: TriviaAnswer;
|
|
74
|
-
}
|
|
75
|
-
interface PaginationMeta {
|
|
76
|
-
current_page: number;
|
|
77
|
-
last_page: number;
|
|
78
|
-
per_page: number;
|
|
79
|
-
total: number;
|
|
80
|
-
from: number | null;
|
|
81
|
-
to: number | null;
|
|
82
|
-
path?: string;
|
|
83
|
-
}
|
|
84
|
-
interface PaginationLinks {
|
|
85
|
-
first: string | null;
|
|
86
|
-
last: string | null;
|
|
87
|
-
prev: string | null;
|
|
88
|
-
next: string | null;
|
|
89
|
-
}
|
|
90
|
-
interface Paginated<T> {
|
|
91
|
-
data: T[];
|
|
92
|
-
meta: PaginationMeta;
|
|
93
|
-
links: PaginationLinks;
|
|
94
|
-
}
|
|
95
|
-
interface PaginationParams {
|
|
96
|
-
page?: number;
|
|
97
|
-
perPage?: number;
|
|
98
|
-
sort?: string;
|
|
99
|
-
}
|
|
100
|
-
interface EntryFilters extends PaginationParams {
|
|
101
|
-
blueprint?: string;
|
|
102
|
-
collection?: string;
|
|
103
|
-
slug?: string;
|
|
104
|
-
published?: boolean;
|
|
105
|
-
}
|
|
106
|
-
interface ArticleFilters extends PaginationParams {
|
|
107
|
-
status?: ArticleStatus;
|
|
108
|
-
}
|
|
109
|
-
interface HookOptions {
|
|
110
|
-
locale?: Locale;
|
|
111
|
-
enabled?: boolean;
|
|
112
|
-
}
|
|
113
|
-
type AuthStatus = 'loading' | 'signed-in' | 'signed-out';
|
|
114
|
-
interface AuthUser {
|
|
115
|
-
uid: string;
|
|
116
|
-
email: string | null;
|
|
117
|
-
displayName: string | null;
|
|
118
|
-
photoURL: string | null;
|
|
119
|
-
phoneNumber: string | null;
|
|
120
|
-
isAnonymous: boolean;
|
|
121
|
-
providerId: string | null;
|
|
122
|
-
}
|
|
123
|
-
interface PushTarget {
|
|
124
|
-
id: string;
|
|
125
|
-
app_user_id: number | string | null;
|
|
126
|
-
identifier: string;
|
|
127
|
-
provider: 'fcm' | 'apns';
|
|
128
|
-
provider_id: string | null;
|
|
129
|
-
device_brand: string | null;
|
|
130
|
-
device_model: string | null;
|
|
131
|
-
os_name: string | null;
|
|
132
|
-
os_version: string | null;
|
|
133
|
-
last_seen_at: string | null;
|
|
134
|
-
created_at: string;
|
|
135
|
-
updated_at: string;
|
|
136
|
-
}
|
|
137
|
-
interface CreatePushTargetInput {
|
|
138
|
-
targetId: string;
|
|
139
|
-
identifier: string;
|
|
140
|
-
providerId?: string;
|
|
141
|
-
deviceBrand?: string;
|
|
142
|
-
deviceModel?: string;
|
|
143
|
-
osName?: string;
|
|
144
|
-
osVersion?: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export type { AuthUser as A, CreatePushTargetInput as C, EntryFilters as E, HookOptions as H, Locale as L, PushTarget as P, StorageAdapter as S, Trivia as T, AuthStatus as a, Paginated as b, Entry as c, ArticleFilters as d, Article as e, TriviaResponseResult as f, ArticleStatus as g, EntryData as h, PaginationLinks as i, PaginationMeta as j, PaginationParams as k, TriviaAnswer as l };
|