@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 +46 -10
- package/dist/index.d.mts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +105 -0
- package/dist/index.mjs.map +1 -1
- package/dist/push.d.mts +5 -0
- package/dist/push.d.ts +5 -0
- package/dist/push.js +57 -7
- package/dist/push.js.map +1 -1
- package/dist/push.mjs +58 -8
- package/dist/push.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
19
|
-
|
|
|
20
|
-
| Push registration
|
|
21
|
-
|
|
|
22
|
-
|
|
|
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
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|
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/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
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,gBAA4B;AAQrB,SAAS,uBAAmD;AACjE,QAAM,gBAAY,2BAAY,OAAO,UAAkB;AACrD,UAAM,kBAAkB,EAAE,iBAAiB,KAAK;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAc,2BAAY,OAAO,UAAkB;AACvD,UAAM,kBAAkB,EAAE,qBAAqB,KAAK;AAAA,EACtD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,WAAW,YAAY;AAClC;","names":["messagingImport","AsyncStorage","import_react_native","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/push/index.ts","../src/push/useRegisterDevice.ts","../src/push/messaging.ts","../src/push/storage.ts","../src/push/targetIdStore.ts","../src/push/useTopicSubscription.ts"],"sourcesContent":["export {\n useRegisterDevice,\n type UseRegisterDeviceResult,\n} from './useRegisterDevice';\nexport {\n useTopicSubscription,\n type UseTopicSubscriptionResult,\n} from './useTopicSubscription';\nexport type { StorageAdapter } from './storage';\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Platform } from 'react-native';\nimport { firebaseMessaging } from './messaging';\nimport { resolveStorage } from './storage';\nimport { generateTargetId, TargetIdStore } from './targetIdStore';\nimport { useFanapps, type PushTarget } from '@fanapps/react-native';\n\nexport interface UseRegisterDeviceResult {\n targetId: string | null;\n token: string | null;\n target: PushTarget | null;\n isRegistering: boolean;\n error: Error | null;\n register(): Promise<PushTarget>;\n unregister(): Promise<void>;\n}\n\nexport function useRegisterDevice(): UseRegisterDeviceResult {\n const { client, storage } = useFanapps();\n\n const [targetId, setTargetId] = useState<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [target, setTarget] = useState<PushTarget | null>(null);\n const [isRegistering, setIsRegistering] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const targetStoreRef = useRef<TargetIdStore | null>(null);\n if (!targetStoreRef.current) {\n targetStoreRef.current = new TargetIdStore(resolveStorage(storage));\n }\n const targetStore = targetStoreRef.current;\n\n const tokenRefreshUnsubRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n };\n }, []);\n\n const register = useCallback(async (): Promise<PushTarget> => {\n setIsRegistering(true);\n setError(null);\n try {\n const messaging = firebaseMessaging();\n\n // Request permission (idempotent; no-op if already granted).\n await messaging.requestPermission();\n\n const fcmToken = await messaging.getToken();\n setToken(fcmToken);\n\n const existingId = await targetStore.get();\n\n let result: PushTarget;\n if (existingId) {\n try {\n result = await client.updatePushTarget(existingId, fcmToken);\n } catch {\n // If the stored target is gone (404), create a new one with the same id.\n result = await client.createPushTarget({\n targetId: existingId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n }\n } else {\n const newId = generateTargetId();\n result = await client.createPushTarget({\n targetId: newId,\n identifier: fcmToken,\n osName: Platform.OS === 'ios' ? 'iOS' : 'Android',\n });\n await targetStore.set(result.id);\n }\n\n setTargetId(result.id);\n setTarget(result);\n\n // Subscribe to onTokenRefresh once.\n if (!tokenRefreshUnsubRef.current) {\n tokenRefreshUnsubRef.current = messaging.onTokenRefresh(async (newToken: string) => {\n try {\n const id = await targetStore.get();\n if (!id) return;\n const updated = await client.updatePushTarget(id, newToken);\n setToken(newToken);\n setTarget(updated);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n } finally {\n setIsRegistering(false);\n }\n }, [client, targetStore]);\n\n const unregister = useCallback(async (): Promise<void> => {\n const id = await targetStore.get();\n if (id) {\n try {\n await client.deletePushTarget(id);\n } catch {\n // Swallow network/404; we still want to clear local state.\n }\n await targetStore.clear();\n }\n tokenRefreshUnsubRef.current?.();\n tokenRefreshUnsubRef.current = null;\n setTargetId(null);\n setToken(null);\n setTarget(null);\n }, [client, targetStore]);\n\n return {\n targetId,\n token,\n target,\n isRegistering,\n error,\n register,\n unregister,\n };\n}\n","import messagingImport, {\n type FirebaseMessagingTypes,\n} from '@react-native-firebase/messaging';\n\nlet cached: FirebaseMessagingTypes.Module | null = null;\n\nexport function firebaseMessaging(): FirebaseMessagingTypes.Module {\n if (cached) return cached;\n cached = messagingImport();\n return cached;\n}\n","import AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { StorageAdapter } from '../storage';\n\nexport function resolveStorage(explicit?: StorageAdapter): StorageAdapter {\n return explicit ?? AsyncStorage;\n}\n\nexport type { StorageAdapter };\n","import type { StorageAdapter } from './storage';\n\nconst KEY = 'fanapps.pushTargetId';\n\nexport class TargetIdStore {\n constructor(private readonly storage: StorageAdapter) {}\n\n get(): Promise<string | null> {\n return this.storage.getItem(KEY);\n }\n\n async set(id: string): Promise<void> {\n await this.storage.setItem(KEY, id);\n }\n\n async clear(): Promise<void> {\n await this.storage.removeItem(KEY);\n }\n}\n\nexport function generateTargetId(): string {\n // 16 bytes of URL-safe hex — safely within Appwrite's 36-char, safe-char constraint.\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useFanapps } from '@fanapps/react-native';\n\nexport interface UseTopicSubscriptionResult {\n /** Topic names the authenticated user is subscribed to. */\n topics: string[];\n isLoading: boolean;\n error: Error | null;\n subscribe(topic: string): Promise<void>;\n unsubscribe(topic: string): Promise<void>;\n refresh(): Promise<void>;\n}\n\nexport function useTopicSubscription(): UseTopicSubscriptionResult {\n const { client } = useFanapps();\n\n const [topics, setTopics] = useState<string[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const latestRequestRef = useRef(0);\n\n const refresh = useCallback(async () => {\n const requestId = ++latestRequestRef.current;\n setIsLoading(true);\n setError(null);\n try {\n const result = await client.listTopicSubscriptions();\n if (requestId !== latestRequestRef.current) return;\n setTopics(result);\n } catch (e) {\n if (requestId !== latestRequestRef.current) return;\n setError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n if (requestId === latestRequestRef.current) setIsLoading(false);\n }\n }, [client]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const subscribe = useCallback(\n async (topic: string) => {\n try {\n await client.subscribeToTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => (prev.includes(topic) ? prev : [...prev, topic]));\n },\n [client],\n );\n\n const unsubscribe = useCallback(\n async (topic: string) => {\n try {\n await client.unsubscribeFromTopic(topic);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n throw err;\n }\n latestRequestRef.current++;\n setIsLoading(false);\n setError(null);\n setTopics((prev) => prev.filter((t) => t !== topic));\n },\n [client],\n );\n\n return { topics, isLoading, error, subscribe, unsubscribe, refresh };\n}\n"],"mappings":"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","names":["messagingImport","AsyncStorage","import_react_native","import_react","import_react_native"]}
|
package/dist/push.mjs
CHANGED
|
@@ -144,15 +144,65 @@ function useRegisterDevice() {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// src/push/useTopicSubscription.ts
|
|
147
|
-
import { useCallback as useCallback2 } from "react";
|
|
147
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
148
|
+
import { useFanapps as useFanapps2 } from "@fanapps/react-native";
|
|
148
149
|
function useTopicSubscription() {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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"]}
|