@fanapps/react-native 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @fanapps/react-native
2
2
 
3
- React Native SDK for the Fanapps API — Firebase-powered auth, paginated content hooks, and FCM push-target registration.
3
+ React Native SDK for the Fanapps API — Firebase-powered auth, paginated content hooks, entry create/update/delete mutations, asset upload, and FCM push-target registration.
4
4
 
5
5
  ## Install
6
6
 
@@ -98,7 +98,32 @@ function Screen() {
98
98
  }
99
99
  ```
100
100
 
101
- Google and Apple sign-in are imported from subpaths (peer-isolated):
101
+ ### Email / password
102
+
103
+ ```tsx
104
+ const { signInWithEmail, signUpWithEmail, sendPasswordResetEmail, sendEmailVerification, signOut } = useAuth();
105
+
106
+ // Sign in
107
+ const user = await signInWithEmail('a@b.com', 's3cret');
108
+
109
+ // Sign up (creates Firebase user, signs them in)
110
+ const newUser = await signUpWithEmail('new@b.com', 's3cret');
111
+
112
+ // Password reset email
113
+ await sendPasswordResetEmail('a@b.com');
114
+
115
+ // Send verification email to currently signed-in user
116
+ await sendEmailVerification();
117
+
118
+ // Sign out
119
+ await signOut();
120
+ ```
121
+
122
+ All return promises; failures throw Firebase errors (e.g. `auth/wrong-password`, `auth/email-already-in-use`).
123
+
124
+ ### Google and Apple
125
+
126
+ Imported from subpaths (peer-isolated):
102
127
 
103
128
  ```tsx
104
129
  import { signInWithGoogle } from '@fanapps/react-native/google';
@@ -193,6 +218,87 @@ useEntry(id, options?) // Entry
193
218
 
194
219
  Filters: `blueprint`, `collection`, `slug`, `published`, `sort` (e.g. `-date`), `perPage`, `page`.
195
220
 
221
+ ### Mutations: create / update / delete entries
222
+
223
+ ```ts
224
+ useCreateEntry() // UseMutationResult<Entry, FanappsError, CreateEntryInput>
225
+ useUpdateEntry() // UseMutationResult<Entry, FanappsError, UpdateEntryInput>
226
+ useDeleteEntry() // UseMutationResult<void, FanappsError, string | number>
227
+ ```
228
+
229
+ Each hook returns a React Query mutation. Pass field values keyed by their blueprint **handle** — validation is derived dynamically from the blueprint's field configuration on the server. Translatable fields write into the locale resolved by the backend (`SetLocale` middleware) — pass `locale` as a query param via the escape hatch if you need to target a specific one.
230
+
231
+ ```tsx
232
+ import { useCreateEntry, useUpdateEntry, useDeleteEntry } from '@fanapps/react-native';
233
+
234
+ function NewsForm() {
235
+ const create = useCreateEntry();
236
+ const update = useUpdateEntry();
237
+ const remove = useDeleteEntry();
238
+
239
+ const onCreate = () =>
240
+ create.mutate({
241
+ blueprint: 'news', // required: blueprint handle
242
+ name: 'Hello world', // any field defined on the blueprint
243
+ body: 'Lorem ipsum',
244
+ featured: true,
245
+ publishedAt: '2026-01-01T12:00:00Z', // optional, null = draft
246
+ terms: { category: [1, 2] }, // optional taxonomy tag IDs
247
+ });
248
+
249
+ const onUpdate = (id: number) =>
250
+ update.mutate({ id, body: 'Updated body' });
251
+
252
+ const onDelete = (id: number) => remove.mutate(id);
253
+
254
+ if (create.isError) console.error(create.error.body);
255
+ return null;
256
+ }
257
+ ```
258
+
259
+ On success, the hooks invalidate `['fanapps','entries']` and the affected `['fanapps','entry', id]` query so paginated lists and detail views refetch automatically. `useDeleteEntry` removes the cached detail entirely.
260
+
261
+ Validation errors come back as `FanappsError` with `status: 422` and `body: { message, errors: { fieldHandle: [...] } }`.
262
+
263
+ ### Assets
264
+
265
+ `useUploadAsset` uploads a single file via multipart/form-data and returns the saved `Asset` (with `id`, `url`, `thumbnail_url`, `width`, `height`, etc.). Reference the returned `id` in entry asset fields.
266
+
267
+ ```tsx
268
+ import { useUploadAsset, useCreateEntry } from '@fanapps/react-native';
269
+ import * as ImagePicker from 'expo-image-picker';
270
+
271
+ function PickAndUpload() {
272
+ const upload = useUploadAsset();
273
+ const create = useCreateEntry();
274
+
275
+ const onPick = async () => {
276
+ const picked = await ImagePicker.launchImageLibraryAsync({ mediaTypes: 'images' });
277
+ if (picked.canceled) return;
278
+
279
+ const [file] = picked.assets;
280
+ const asset = await upload.mutateAsync({
281
+ file: {
282
+ uri: file.uri,
283
+ name: file.fileName ?? 'photo.jpg',
284
+ type: file.mimeType ?? 'image/jpeg',
285
+ },
286
+ altText: 'Optional alt text',
287
+ });
288
+
289
+ await create.mutateAsync({
290
+ blueprint: 'gallery',
291
+ name: 'My gallery',
292
+ images: [{ id: asset.id }], // shape expected by `assets` field type
293
+ });
294
+ };
295
+
296
+ return null;
297
+ }
298
+ ```
299
+
300
+ The file shape `{ uri, name, type }` matches the React Native `FormData` convention and works directly with output from `expo-image-picker`, `react-native-image-picker`, and `expo-document-picker`. Max upload size is 10 MB; files larger than that throw `FanappsError` with `status: 422`.
301
+
196
302
  ### Articles
197
303
 
198
304
  ```ts
package/dist/apple.js CHANGED
@@ -36,26 +36,16 @@ module.exports = __toCommonJS(apple_exports);
36
36
  var import_auth = __toESM(require("@react-native-firebase/auth"));
37
37
  var import_react_native_apple_authentication = require("@invertase/react-native-apple-authentication");
38
38
  var import_react_native = require("react-native");
39
-
40
- // src/auth/errors.ts
41
- var FanappsAuthError = class extends Error {
42
- constructor(message, code) {
43
- super(message);
44
- this.name = "FanappsAuthError";
45
- this.code = code;
46
- }
47
- };
48
-
49
- // src/apple/index.ts
39
+ var import_react_native2 = require("@fanapps/react-native");
50
40
  async function signInWithApple() {
51
41
  if (import_react_native.Platform.OS !== "ios") {
52
- throw new FanappsAuthError(
42
+ throw new import_react_native2.FanappsAuthError(
53
43
  "Apple sign-in is only supported on iOS in v1.",
54
44
  "auth/platform-not-supported"
55
45
  );
56
46
  }
57
47
  if (!import_react_native_apple_authentication.appleAuth.isSupported) {
58
- throw new FanappsAuthError(
48
+ throw new import_react_native2.FanappsAuthError(
59
49
  "Apple sign-in not supported on this device.",
60
50
  "auth/not-supported"
61
51
  );
@@ -65,7 +55,7 @@ async function signInWithApple() {
65
55
  requestedScopes: [import_react_native_apple_authentication.appleAuth.Scope.EMAIL, import_react_native_apple_authentication.appleAuth.Scope.FULL_NAME]
66
56
  });
67
57
  if (!result.identityToken) {
68
- throw new FanappsAuthError(
58
+ throw new import_react_native2.FanappsAuthError(
69
59
  "Apple did not return an identity token.",
70
60
  "auth/no-token"
71
61
  );
package/dist/apple.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/apple/index.ts","../src/auth/errors.ts"],"sourcesContent":["import auth, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { appleAuth } from '@invertase/react-native-apple-authentication';\nimport { Platform } from 'react-native';\nimport { FanappsAuthError } from '../auth/errors';\n\nexport async function signInWithApple(): Promise<FirebaseAuthTypes.UserCredential> {\n if (Platform.OS !== 'ios') {\n throw new FanappsAuthError(\n 'Apple sign-in is only supported on iOS in v1.',\n 'auth/platform-not-supported',\n );\n }\n\n if (!appleAuth.isSupported) {\n throw new FanappsAuthError(\n 'Apple sign-in not supported on this device.',\n 'auth/not-supported',\n );\n }\n\n const result = await appleAuth.performRequest({\n requestedOperation: appleAuth.Operation.LOGIN,\n requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],\n });\n\n if (!result.identityToken) {\n throw new FanappsAuthError(\n 'Apple did not return an identity token.',\n 'auth/no-token',\n );\n }\n\n const credential = auth.AppleAuthProvider.credential(\n result.identityToken,\n result.nonce ?? undefined,\n );\n\n return auth().signInWithCredential(credential);\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6C;AAC7C,+CAA0B;AAC1B,0BAAyB;;;ACFlB,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAG1C,YAAY,SAAiB,MAAc;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;;;ADHA,eAAsB,kBAA6D;AACjF,MAAI,6BAAS,OAAO,OAAO;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,mDAAU,aAAa;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,mDAAU,eAAe;AAAA,IAC5C,oBAAoB,mDAAU,UAAU;AAAA,IACxC,iBAAiB,CAAC,mDAAU,MAAM,OAAO,mDAAU,MAAM,SAAS;AAAA,EACpE,CAAC;AAED,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,YAAAA,QAAK,kBAAkB;AAAA,IACxC,OAAO;AAAA,IACP,OAAO,SAAS;AAAA,EAClB;AAEA,aAAO,YAAAA,SAAK,EAAE,qBAAqB,UAAU;AAC/C;","names":["auth"]}
1
+ {"version":3,"sources":["../src/apple/index.ts"],"sourcesContent":["import auth, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { appleAuth } from '@invertase/react-native-apple-authentication';\nimport { Platform } from 'react-native';\nimport { FanappsAuthError } from '@fanapps/react-native';\n\nexport async function signInWithApple(): Promise<FirebaseAuthTypes.UserCredential> {\n if (Platform.OS !== 'ios') {\n throw new FanappsAuthError(\n 'Apple sign-in is only supported on iOS in v1.',\n 'auth/platform-not-supported',\n );\n }\n\n if (!appleAuth.isSupported) {\n throw new FanappsAuthError(\n 'Apple sign-in not supported on this device.',\n 'auth/not-supported',\n );\n }\n\n const result = await appleAuth.performRequest({\n requestedOperation: appleAuth.Operation.LOGIN,\n requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],\n });\n\n if (!result.identityToken) {\n throw new FanappsAuthError(\n 'Apple did not return an identity token.',\n 'auth/no-token',\n );\n }\n\n const credential = auth.AppleAuthProvider.credential(\n result.identityToken,\n result.nonce ?? undefined,\n );\n\n return auth().signInWithCredential(credential);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6C;AAC7C,+CAA0B;AAC1B,0BAAyB;AACzB,IAAAA,uBAAiC;AAEjC,eAAsB,kBAA6D;AACjF,MAAI,6BAAS,OAAO,OAAO;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,mDAAU,aAAa;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,mDAAU,eAAe;AAAA,IAC5C,oBAAoB,mDAAU,UAAU;AAAA,IACxC,iBAAiB,CAAC,mDAAU,MAAM,OAAO,mDAAU,MAAM,SAAS;AAAA,EACpE,CAAC;AAED,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,YAAAC,QAAK,kBAAkB;AAAA,IACxC,OAAO;AAAA,IACP,OAAO,SAAS;AAAA,EAClB;AAEA,aAAO,YAAAA,SAAK,EAAE,qBAAqB,UAAU;AAC/C;","names":["import_react_native","auth"]}
package/dist/apple.mjs CHANGED
@@ -1,11 +1,8 @@
1
- import {
2
- FanappsAuthError
3
- } from "./chunk-SWOKCWWX.mjs";
4
-
5
1
  // src/apple/index.ts
6
2
  import auth from "@react-native-firebase/auth";
7
3
  import { appleAuth } from "@invertase/react-native-apple-authentication";
8
4
  import { Platform } from "react-native";
5
+ import { FanappsAuthError } from "@fanapps/react-native";
9
6
  async function signInWithApple() {
10
7
  if (Platform.OS !== "ios") {
11
8
  throw new FanappsAuthError(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/apple/index.ts"],"sourcesContent":["import auth, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { appleAuth } from '@invertase/react-native-apple-authentication';\nimport { Platform } from 'react-native';\nimport { FanappsAuthError } from '../auth/errors';\n\nexport async function signInWithApple(): Promise<FirebaseAuthTypes.UserCredential> {\n if (Platform.OS !== 'ios') {\n throw new FanappsAuthError(\n 'Apple sign-in is only supported on iOS in v1.',\n 'auth/platform-not-supported',\n );\n }\n\n if (!appleAuth.isSupported) {\n throw new FanappsAuthError(\n 'Apple sign-in not supported on this device.',\n 'auth/not-supported',\n );\n }\n\n const result = await appleAuth.performRequest({\n requestedOperation: appleAuth.Operation.LOGIN,\n requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],\n });\n\n if (!result.identityToken) {\n throw new FanappsAuthError(\n 'Apple did not return an identity token.',\n 'auth/no-token',\n );\n }\n\n const credential = auth.AppleAuthProvider.credential(\n result.identityToken,\n result.nonce ?? undefined,\n );\n\n return auth().signInWithCredential(credential);\n}\n"],"mappings":";;;;;AAAA,OAAO,UAAsC;AAC7C,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AAGzB,eAAsB,kBAA6D;AACjF,MAAI,SAAS,OAAO,OAAO;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,UAAU,aAAa;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,UAAU,eAAe;AAAA,IAC5C,oBAAoB,UAAU,UAAU;AAAA,IACxC,iBAAiB,CAAC,UAAU,MAAM,OAAO,UAAU,MAAM,SAAS;AAAA,EACpE,CAAC;AAED,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,KAAK,kBAAkB;AAAA,IACxC,OAAO;AAAA,IACP,OAAO,SAAS;AAAA,EAClB;AAEA,SAAO,KAAK,EAAE,qBAAqB,UAAU;AAC/C;","names":[]}
1
+ {"version":3,"sources":["../src/apple/index.ts"],"sourcesContent":["import auth, { type FirebaseAuthTypes } from '@react-native-firebase/auth';\nimport { appleAuth } from '@invertase/react-native-apple-authentication';\nimport { Platform } from 'react-native';\nimport { FanappsAuthError } from '@fanapps/react-native';\n\nexport async function signInWithApple(): Promise<FirebaseAuthTypes.UserCredential> {\n if (Platform.OS !== 'ios') {\n throw new FanappsAuthError(\n 'Apple sign-in is only supported on iOS in v1.',\n 'auth/platform-not-supported',\n );\n }\n\n if (!appleAuth.isSupported) {\n throw new FanappsAuthError(\n 'Apple sign-in not supported on this device.',\n 'auth/not-supported',\n );\n }\n\n const result = await appleAuth.performRequest({\n requestedOperation: appleAuth.Operation.LOGIN,\n requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],\n });\n\n if (!result.identityToken) {\n throw new FanappsAuthError(\n 'Apple did not return an identity token.',\n 'auth/no-token',\n );\n }\n\n const credential = auth.AppleAuthProvider.credential(\n result.identityToken,\n result.nonce ?? undefined,\n );\n\n return auth().signInWithCredential(credential);\n}\n"],"mappings":";AAAA,OAAO,UAAsC;AAC7C,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AAEjC,eAAsB,kBAA6D;AACjF,MAAI,SAAS,OAAO,OAAO;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,UAAU,aAAa;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,UAAU,eAAe;AAAA,IAC5C,oBAAoB,UAAU,UAAU;AAAA,IACxC,iBAAiB,CAAC,UAAU,MAAM,OAAO,UAAU,MAAM,SAAS;AAAA,EACpE,CAAC;AAED,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,KAAK,kBAAkB;AAAA,IACxC,OAAO;AAAA,IACP,OAAO,SAAS;AAAA,EAClB;AAEA,SAAO,KAAK,EAAE,qBAAqB,UAAU;AAC/C;","names":[]}
package/dist/index.d.mts CHANGED
@@ -1,8 +1,175 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { QueryClient, UseQueryResult, UseMutationResult } from '@tanstack/react-query';
3
3
  import { ReactNode } from 'react';
4
- import { L as Locale, S as StorageAdapter, C as CreatePushTargetInput, P as PushTarget, A as AuthUser, a as AuthStatus, E as EntryFilters, H as HookOptions, b as Paginated, c as Entry, d as ArticleFilters, e as Article, T as Trivia, f as TriviaResponseResult } from './types-CKpYrzCw.mjs';
5
- export { g as ArticleStatus, h as EntryData, i as PaginationLinks, j as PaginationMeta, k as PaginationParams, l as TriviaAnswer } from './types-CKpYrzCw.mjs';
4
+ import { S as StorageAdapter } from './storage-D6z5ScLn.mjs';
5
+ import { FirebaseAuthTypes } from '@react-native-firebase/auth';
6
+
7
+ type Locale = string;
8
+ type EntryData = Record<string, unknown>;
9
+ interface Entry {
10
+ id: string | number;
11
+ slug: string;
12
+ published: boolean;
13
+ date: string | null;
14
+ order: number | null;
15
+ collection: string | null;
16
+ blueprint: string;
17
+ data: EntryData;
18
+ created_at: string;
19
+ updated_at: string;
20
+ locale: Locale;
21
+ available_locales?: Locale[];
22
+ }
23
+ type ArticleStatus = 'draft' | 'scheduled' | 'published';
24
+ interface Article {
25
+ id: string | number;
26
+ title: string;
27
+ content: string;
28
+ status: ArticleStatus;
29
+ published_at: string | null;
30
+ featured_image_url: string | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ locale: Locale;
34
+ available_locales?: Locale[];
35
+ }
36
+ interface TriviaAnswer {
37
+ id: string | number;
38
+ text: string;
39
+ is_correct: boolean;
40
+ sort_order: number;
41
+ }
42
+ interface Trivia {
43
+ id: string | number;
44
+ title: string;
45
+ description: string | null;
46
+ featured_image_id: string | number | null;
47
+ featured_image?: {
48
+ id: string | number;
49
+ url: string;
50
+ [key: string]: unknown;
51
+ } | null;
52
+ awards_points: boolean;
53
+ points_amount: number;
54
+ max_time_seconds: number | null;
55
+ show_correct_after: boolean;
56
+ starts_at: string | null;
57
+ ends_at: string | null;
58
+ answers: TriviaAnswer[];
59
+ responses_count?: number;
60
+ created_at: string;
61
+ updated_at: string;
62
+ }
63
+ interface TriviaResponseResult {
64
+ is_correct: boolean;
65
+ points_awarded: number;
66
+ correct_answer?: TriviaAnswer;
67
+ }
68
+ interface PaginationMeta {
69
+ current_page: number;
70
+ last_page: number;
71
+ per_page: number;
72
+ total: number;
73
+ from: number | null;
74
+ to: number | null;
75
+ path?: string;
76
+ }
77
+ interface PaginationLinks {
78
+ first: string | null;
79
+ last: string | null;
80
+ prev: string | null;
81
+ next: string | null;
82
+ }
83
+ interface Paginated<T> {
84
+ data: T[];
85
+ meta: PaginationMeta;
86
+ links: PaginationLinks;
87
+ }
88
+ interface PaginationParams {
89
+ page?: number;
90
+ perPage?: number;
91
+ sort?: string;
92
+ }
93
+ interface EntryFilters extends PaginationParams {
94
+ blueprint?: string;
95
+ collection?: string;
96
+ slug?: string;
97
+ published?: boolean;
98
+ }
99
+ interface ArticleFilters extends PaginationParams {
100
+ status?: ArticleStatus;
101
+ }
102
+ interface HookOptions {
103
+ locale?: Locale;
104
+ enabled?: boolean;
105
+ }
106
+ type AuthStatus = 'loading' | 'signed-in' | 'signed-out';
107
+ interface AuthUser {
108
+ uid: string;
109
+ email: string | null;
110
+ displayName: string | null;
111
+ photoURL: string | null;
112
+ phoneNumber: string | null;
113
+ isAnonymous: boolean;
114
+ providerId: string | null;
115
+ }
116
+ interface PushTarget {
117
+ id: string;
118
+ app_user_id: number | string | null;
119
+ identifier: string;
120
+ provider: 'fcm' | 'apns';
121
+ provider_id: string | null;
122
+ device_brand: string | null;
123
+ device_model: string | null;
124
+ os_name: string | null;
125
+ os_version: string | null;
126
+ last_seen_at: string | null;
127
+ created_at: string;
128
+ updated_at: string;
129
+ }
130
+ interface CreatePushTargetInput {
131
+ targetId: string;
132
+ identifier: string;
133
+ providerId?: string;
134
+ deviceBrand?: string;
135
+ deviceModel?: string;
136
+ osName?: string;
137
+ osVersion?: string;
138
+ }
139
+ interface Asset {
140
+ id: number;
141
+ name: string;
142
+ alt_text: string | null;
143
+ url: string | null;
144
+ thumbnail_url: string | null;
145
+ mime_type: string | null;
146
+ size: number | null;
147
+ width: number | null;
148
+ height: number | null;
149
+ created_at: string;
150
+ updated_at: string;
151
+ }
152
+ interface AssetUploadFile {
153
+ uri: string;
154
+ name: string;
155
+ type: string;
156
+ }
157
+ interface UploadAssetInput {
158
+ file: AssetUploadFile;
159
+ altText?: string;
160
+ }
161
+ interface CreateEntryInput {
162
+ blueprint: string;
163
+ publishedAt?: string | null;
164
+ terms?: Record<string, Array<number | string>>;
165
+ [field: string]: unknown;
166
+ }
167
+ interface UpdateEntryInput {
168
+ id: string | number;
169
+ publishedAt?: string | null;
170
+ terms?: Record<string, Array<number | string>>;
171
+ [field: string]: unknown;
172
+ }
6
173
 
7
174
  interface FanappsProviderProps {
8
175
  apiKey: string;
@@ -35,6 +202,11 @@ declare class FanappsClient {
35
202
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
36
203
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
37
204
  deletePushTarget(targetId: string): Promise<void>;
205
+ createEntry(input: CreateEntryInput): Promise<Entry>;
206
+ updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
207
+ deleteEntry(id: string | number): Promise<void>;
208
+ uploadAsset(input: UploadAssetInput): Promise<Asset>;
209
+ private requestMultipart;
38
210
  private request;
39
211
  private buildUrl;
40
212
  }
@@ -50,6 +222,32 @@ declare class FanappsAuthError extends Error {
50
222
  constructor(message: string, code: string);
51
223
  }
52
224
 
225
+ type AuthListener = (snapshot: AuthStoreSnapshot) => void;
226
+ interface AuthStoreSnapshot {
227
+ user: AuthUser | null;
228
+ firebaseUser: FirebaseAuthTypes.User | null;
229
+ status: AuthStatus;
230
+ }
231
+ declare class AuthStore {
232
+ private snapshot;
233
+ private listeners;
234
+ private unsubscribe;
235
+ start(): void;
236
+ stop(): void;
237
+ subscribe(listener: AuthListener): () => void;
238
+ getSnapshot(): AuthStoreSnapshot;
239
+ getCurrentIdToken(): Promise<string | null>;
240
+ private emit;
241
+ }
242
+
243
+ interface FanappsContextValue {
244
+ client: FanappsClient;
245
+ authStore: AuthStore;
246
+ storage: StorageAdapter | undefined;
247
+ locale?: Locale;
248
+ }
249
+ declare function useFanapps(): FanappsContextValue;
250
+
53
251
  declare function useFanappsClient(): FanappsClient;
54
252
 
55
253
  interface UseAuthResult {
@@ -67,6 +265,14 @@ declare function useEntries(filters?: EntryFilters, options?: HookOptions): UseQ
67
265
 
68
266
  declare function useEntry(id: string | number | null | undefined, options?: HookOptions): UseQueryResult<Entry>;
69
267
 
268
+ declare function useCreateEntry(): UseMutationResult<Entry, FanappsError, CreateEntryInput>;
269
+
270
+ declare function useUpdateEntry(): UseMutationResult<Entry, FanappsError, UpdateEntryInput>;
271
+
272
+ declare function useDeleteEntry(): UseMutationResult<void, FanappsError, string | number>;
273
+
274
+ declare function useUploadAsset(): UseMutationResult<Asset, FanappsError, UploadAssetInput>;
275
+
70
276
  declare function useArticles(filters?: ArticleFilters, options?: HookOptions): UseQueryResult<Paginated<Article>>;
71
277
 
72
278
  declare function useArticle(id: string | number | null | undefined, options?: HookOptions): UseQueryResult<Article>;
@@ -81,4 +287,4 @@ interface SubmitTriviaResponseInput {
81
287
  }
82
288
  declare function useSubmitTriviaResponse(): UseMutationResult<TriviaResponseResult, FanappsError, SubmitTriviaResponseInput>;
83
289
 
84
- export { Article, ArticleFilters, AuthStatus, AuthUser, CreatePushTargetInput, Entry, EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, FanappsError, FanappsProvider, type FanappsProviderProps, HookOptions, Locale, Paginated, PushTarget, StorageAdapter, type SubmitTriviaResponseInput, Trivia, TriviaResponseResult, type UseAuthResult, useArticle, useArticles, useAuth, useEntries, useEntry, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias };
290
+ export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type Locale, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias, useUpdateEntry, useUploadAsset };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,175 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { QueryClient, UseQueryResult, UseMutationResult } from '@tanstack/react-query';
3
3
  import { ReactNode } from 'react';
4
- import { L as Locale, S as StorageAdapter, C as CreatePushTargetInput, P as PushTarget, A as AuthUser, a as AuthStatus, E as EntryFilters, H as HookOptions, b as Paginated, c as Entry, d as ArticleFilters, e as Article, T as Trivia, f as TriviaResponseResult } from './types-CKpYrzCw.js';
5
- export { g as ArticleStatus, h as EntryData, i as PaginationLinks, j as PaginationMeta, k as PaginationParams, l as TriviaAnswer } from './types-CKpYrzCw.js';
4
+ import { S as StorageAdapter } from './storage-D6z5ScLn.js';
5
+ import { FirebaseAuthTypes } from '@react-native-firebase/auth';
6
+
7
+ type Locale = string;
8
+ type EntryData = Record<string, unknown>;
9
+ interface Entry {
10
+ id: string | number;
11
+ slug: string;
12
+ published: boolean;
13
+ date: string | null;
14
+ order: number | null;
15
+ collection: string | null;
16
+ blueprint: string;
17
+ data: EntryData;
18
+ created_at: string;
19
+ updated_at: string;
20
+ locale: Locale;
21
+ available_locales?: Locale[];
22
+ }
23
+ type ArticleStatus = 'draft' | 'scheduled' | 'published';
24
+ interface Article {
25
+ id: string | number;
26
+ title: string;
27
+ content: string;
28
+ status: ArticleStatus;
29
+ published_at: string | null;
30
+ featured_image_url: string | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ locale: Locale;
34
+ available_locales?: Locale[];
35
+ }
36
+ interface TriviaAnswer {
37
+ id: string | number;
38
+ text: string;
39
+ is_correct: boolean;
40
+ sort_order: number;
41
+ }
42
+ interface Trivia {
43
+ id: string | number;
44
+ title: string;
45
+ description: string | null;
46
+ featured_image_id: string | number | null;
47
+ featured_image?: {
48
+ id: string | number;
49
+ url: string;
50
+ [key: string]: unknown;
51
+ } | null;
52
+ awards_points: boolean;
53
+ points_amount: number;
54
+ max_time_seconds: number | null;
55
+ show_correct_after: boolean;
56
+ starts_at: string | null;
57
+ ends_at: string | null;
58
+ answers: TriviaAnswer[];
59
+ responses_count?: number;
60
+ created_at: string;
61
+ updated_at: string;
62
+ }
63
+ interface TriviaResponseResult {
64
+ is_correct: boolean;
65
+ points_awarded: number;
66
+ correct_answer?: TriviaAnswer;
67
+ }
68
+ interface PaginationMeta {
69
+ current_page: number;
70
+ last_page: number;
71
+ per_page: number;
72
+ total: number;
73
+ from: number | null;
74
+ to: number | null;
75
+ path?: string;
76
+ }
77
+ interface PaginationLinks {
78
+ first: string | null;
79
+ last: string | null;
80
+ prev: string | null;
81
+ next: string | null;
82
+ }
83
+ interface Paginated<T> {
84
+ data: T[];
85
+ meta: PaginationMeta;
86
+ links: PaginationLinks;
87
+ }
88
+ interface PaginationParams {
89
+ page?: number;
90
+ perPage?: number;
91
+ sort?: string;
92
+ }
93
+ interface EntryFilters extends PaginationParams {
94
+ blueprint?: string;
95
+ collection?: string;
96
+ slug?: string;
97
+ published?: boolean;
98
+ }
99
+ interface ArticleFilters extends PaginationParams {
100
+ status?: ArticleStatus;
101
+ }
102
+ interface HookOptions {
103
+ locale?: Locale;
104
+ enabled?: boolean;
105
+ }
106
+ type AuthStatus = 'loading' | 'signed-in' | 'signed-out';
107
+ interface AuthUser {
108
+ uid: string;
109
+ email: string | null;
110
+ displayName: string | null;
111
+ photoURL: string | null;
112
+ phoneNumber: string | null;
113
+ isAnonymous: boolean;
114
+ providerId: string | null;
115
+ }
116
+ interface PushTarget {
117
+ id: string;
118
+ app_user_id: number | string | null;
119
+ identifier: string;
120
+ provider: 'fcm' | 'apns';
121
+ provider_id: string | null;
122
+ device_brand: string | null;
123
+ device_model: string | null;
124
+ os_name: string | null;
125
+ os_version: string | null;
126
+ last_seen_at: string | null;
127
+ created_at: string;
128
+ updated_at: string;
129
+ }
130
+ interface CreatePushTargetInput {
131
+ targetId: string;
132
+ identifier: string;
133
+ providerId?: string;
134
+ deviceBrand?: string;
135
+ deviceModel?: string;
136
+ osName?: string;
137
+ osVersion?: string;
138
+ }
139
+ interface Asset {
140
+ id: number;
141
+ name: string;
142
+ alt_text: string | null;
143
+ url: string | null;
144
+ thumbnail_url: string | null;
145
+ mime_type: string | null;
146
+ size: number | null;
147
+ width: number | null;
148
+ height: number | null;
149
+ created_at: string;
150
+ updated_at: string;
151
+ }
152
+ interface AssetUploadFile {
153
+ uri: string;
154
+ name: string;
155
+ type: string;
156
+ }
157
+ interface UploadAssetInput {
158
+ file: AssetUploadFile;
159
+ altText?: string;
160
+ }
161
+ interface CreateEntryInput {
162
+ blueprint: string;
163
+ publishedAt?: string | null;
164
+ terms?: Record<string, Array<number | string>>;
165
+ [field: string]: unknown;
166
+ }
167
+ interface UpdateEntryInput {
168
+ id: string | number;
169
+ publishedAt?: string | null;
170
+ terms?: Record<string, Array<number | string>>;
171
+ [field: string]: unknown;
172
+ }
6
173
 
7
174
  interface FanappsProviderProps {
8
175
  apiKey: string;
@@ -35,6 +202,11 @@ declare class FanappsClient {
35
202
  createPushTarget(input: CreatePushTargetInput): Promise<PushTarget>;
36
203
  updatePushTarget(targetId: string, identifier: string): Promise<PushTarget>;
37
204
  deletePushTarget(targetId: string): Promise<void>;
205
+ createEntry(input: CreateEntryInput): Promise<Entry>;
206
+ updateEntry({ id, ...rest }: UpdateEntryInput): Promise<Entry>;
207
+ deleteEntry(id: string | number): Promise<void>;
208
+ uploadAsset(input: UploadAssetInput): Promise<Asset>;
209
+ private requestMultipart;
38
210
  private request;
39
211
  private buildUrl;
40
212
  }
@@ -50,6 +222,32 @@ declare class FanappsAuthError extends Error {
50
222
  constructor(message: string, code: string);
51
223
  }
52
224
 
225
+ type AuthListener = (snapshot: AuthStoreSnapshot) => void;
226
+ interface AuthStoreSnapshot {
227
+ user: AuthUser | null;
228
+ firebaseUser: FirebaseAuthTypes.User | null;
229
+ status: AuthStatus;
230
+ }
231
+ declare class AuthStore {
232
+ private snapshot;
233
+ private listeners;
234
+ private unsubscribe;
235
+ start(): void;
236
+ stop(): void;
237
+ subscribe(listener: AuthListener): () => void;
238
+ getSnapshot(): AuthStoreSnapshot;
239
+ getCurrentIdToken(): Promise<string | null>;
240
+ private emit;
241
+ }
242
+
243
+ interface FanappsContextValue {
244
+ client: FanappsClient;
245
+ authStore: AuthStore;
246
+ storage: StorageAdapter | undefined;
247
+ locale?: Locale;
248
+ }
249
+ declare function useFanapps(): FanappsContextValue;
250
+
53
251
  declare function useFanappsClient(): FanappsClient;
54
252
 
55
253
  interface UseAuthResult {
@@ -67,6 +265,14 @@ declare function useEntries(filters?: EntryFilters, options?: HookOptions): UseQ
67
265
 
68
266
  declare function useEntry(id: string | number | null | undefined, options?: HookOptions): UseQueryResult<Entry>;
69
267
 
268
+ declare function useCreateEntry(): UseMutationResult<Entry, FanappsError, CreateEntryInput>;
269
+
270
+ declare function useUpdateEntry(): UseMutationResult<Entry, FanappsError, UpdateEntryInput>;
271
+
272
+ declare function useDeleteEntry(): UseMutationResult<void, FanappsError, string | number>;
273
+
274
+ declare function useUploadAsset(): UseMutationResult<Asset, FanappsError, UploadAssetInput>;
275
+
70
276
  declare function useArticles(filters?: ArticleFilters, options?: HookOptions): UseQueryResult<Paginated<Article>>;
71
277
 
72
278
  declare function useArticle(id: string | number | null | undefined, options?: HookOptions): UseQueryResult<Article>;
@@ -81,4 +287,4 @@ interface SubmitTriviaResponseInput {
81
287
  }
82
288
  declare function useSubmitTriviaResponse(): UseMutationResult<TriviaResponseResult, FanappsError, SubmitTriviaResponseInput>;
83
289
 
84
- export { Article, ArticleFilters, AuthStatus, AuthUser, CreatePushTargetInput, Entry, EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, FanappsError, FanappsProvider, type FanappsProviderProps, HookOptions, Locale, Paginated, PushTarget, StorageAdapter, type SubmitTriviaResponseInput, Trivia, TriviaResponseResult, type UseAuthResult, useArticle, useArticles, useAuth, useEntries, useEntry, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias };
290
+ export { type Article, type ArticleFilters, type ArticleStatus, type Asset, type AssetUploadFile, type AuthStatus, type AuthUser, type CreateEntryInput, type CreatePushTargetInput, type Entry, type EntryData, type EntryFilters, FanappsAuthError, FanappsClient, type FanappsClientOptions, type FanappsContextValue, FanappsError, FanappsProvider, type FanappsProviderProps, type HookOptions, type Locale, type Paginated, type PaginationLinks, type PaginationMeta, type PaginationParams, type PushTarget, StorageAdapter, type SubmitTriviaResponseInput, type Trivia, type TriviaAnswer, type TriviaResponseResult, type UpdateEntryInput, type UploadAssetInput, type UseAuthResult, useArticle, useArticles, useAuth, useCreateEntry, useDeleteEntry, useEntries, useEntry, useFanapps, useFanappsClient, useSubmitTriviaResponse, useTrivia, useTrivias, useUpdateEntry, useUploadAsset };