@rebasepro/client-firebase 0.2.3 → 0.2.4
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/dist/components/RebaseFirebaseApp.d.ts +1 -1
- package/dist/components/RebaseFirebaseAppProps.d.ts +5 -4
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useAppCheck.d.ts +1 -1
- package/dist/hooks/useBuildUserManagement.d.ts +2 -7
- package/dist/hooks/useFirebaseAccessGate.d.ts +44 -0
- package/dist/hooks/useFirestoreDriver.d.ts +2 -2
- package/dist/index.es.js +159 -35
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +158 -34
- package/dist/index.umd.js.map +1 -1
- package/dist/utils/algolia.d.ts +7 -1
- package/package.json +7 -7
- package/src/components/FirebaseLoginView.tsx +1 -1
- package/src/components/RebaseFirebaseApp.tsx +9 -9
- package/src/components/RebaseFirebaseAppProps.tsx +5 -4
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAppCheck.ts +4 -4
- package/src/hooks/useBuildUserManagement.tsx +14 -22
- package/src/hooks/useFirebaseAccessGate.tsx +145 -0
- package/src/hooks/useFirebaseRealTimeDBDelegate.ts +17 -12
- package/src/hooks/useFirebaseStorageSource.ts +4 -4
- package/src/hooks/useFirestoreDriver.ts +27 -23
- package/src/hooks/useInitialiseFirebase.ts +2 -2
- package/src/utils/algolia.ts +4 -4
- package/src/utils/local_text_search_controller.ts +1 -1
- package/src/utils/rebase_search_controller.ts +14 -14
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DataDriver, DeleteEntityProps, Entity, EntityCollection, EntityReference, FetchCollectionProps, FetchEntityProps, FilterCombination, FilterValues, GeoPoint, ListenCollectionProps, ListenEntityProps, SaveEntityProps, WhereFilterOp } from "@rebasepro/types";
|
|
2
|
+
import { User } from "@firebase/auth";
|
|
2
3
|
import {
|
|
3
4
|
collection as collectionClause,
|
|
4
5
|
CollectionReference,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
vector,
|
|
28
29
|
where as whereClause
|
|
29
30
|
} from "@firebase/firestore";
|
|
31
|
+
import type { FieldValue } from "@firebase/firestore";
|
|
30
32
|
import { FirebaseApp } from "@firebase/app";
|
|
31
33
|
import { FirestoreTextSearchController, FirestoreTextSearchControllerBuilder } from "../types/text_search";
|
|
32
34
|
import { useCallback, useEffect, useRef } from "react";
|
|
@@ -477,7 +479,7 @@ export function useFirestoreDriver({
|
|
|
477
479
|
} else {
|
|
478
480
|
documentReference = doc(collectionReference);
|
|
479
481
|
}
|
|
480
|
-
return setDoc(documentReference, values, { merge: true })
|
|
482
|
+
return setDoc(documentReference, values as Record<string, unknown>, { merge: true })
|
|
481
483
|
.then(() => {
|
|
482
484
|
return {
|
|
483
485
|
id: documentReference.id,
|
|
@@ -524,7 +526,7 @@ export function useFirestoreDriver({
|
|
|
524
526
|
checkUniqueField: useCallback(async (
|
|
525
527
|
path: string,
|
|
526
528
|
name: string,
|
|
527
|
-
value:
|
|
529
|
+
value: unknown,
|
|
528
530
|
entityId?: string | number,
|
|
529
531
|
collection?: EntityCollection<any>
|
|
530
532
|
): Promise<boolean> => {
|
|
@@ -618,7 +620,7 @@ const createEntityFromDocument = <M extends Record<string, any>>(
|
|
|
618
620
|
docSnap: DocumentSnapshot,
|
|
619
621
|
databaseId?: string
|
|
620
622
|
): Entity<M> => {
|
|
621
|
-
const values = firestoreToCMSModel(docSnap.data());
|
|
623
|
+
const values = firestoreToCMSModel(docSnap.data()) as M;
|
|
622
624
|
const path = getCMSPathFromFirestorePath(docSnap.ref.path);
|
|
623
625
|
return {
|
|
624
626
|
id: docSnap.id,
|
|
@@ -638,16 +640,16 @@ const createEntityFromDocument = <M extends Record<string, any>>(
|
|
|
638
640
|
* @param data
|
|
639
641
|
* @group Firestore
|
|
640
642
|
*/
|
|
641
|
-
export function firestoreToCMSModel(data:
|
|
643
|
+
export function firestoreToCMSModel(data: unknown): unknown {
|
|
642
644
|
if (data === null || data === undefined) return null;
|
|
643
|
-
if (deleteField().isEqual(data)) {
|
|
645
|
+
if (typeof data === "object" && data !== null && "isEqual" in data && typeof (data as FieldValue).isEqual === "function" && deleteField().isEqual(data as FieldValue)) {
|
|
644
646
|
return undefined;
|
|
645
647
|
}
|
|
646
|
-
if (serverTimestamp().isEqual(data)) {
|
|
648
|
+
if (typeof data === "object" && data !== null && "isEqual" in data && typeof (data as FieldValue).isEqual === "function" && serverTimestamp().isEqual(data as FieldValue)) {
|
|
647
649
|
return null;
|
|
648
650
|
}
|
|
649
|
-
if (data instanceof Timestamp || (typeof data.toDate === "function" && data.toDate() instanceof Date)) {
|
|
650
|
-
return data.toDate();
|
|
651
|
+
if (data instanceof Timestamp || (typeof data === "object" && data !== null && "toDate" in data && typeof (data as Record<string, unknown>).toDate === "function" && ((data as Record<string, unknown>).toDate as () => unknown)() instanceof Date)) {
|
|
652
|
+
return (data as { toDate: () => Date }).toDate();
|
|
651
653
|
}
|
|
652
654
|
if (data instanceof Date) {
|
|
653
655
|
return data;
|
|
@@ -655,9 +657,9 @@ export function firestoreToCMSModel(data: any): any {
|
|
|
655
657
|
if (typeof data === "object" && "__type__" in data && data.__type__ === "__vector__") {
|
|
656
658
|
return data; // already translated
|
|
657
659
|
}
|
|
658
|
-
if (data instanceof VectorValue || (typeof data === "object" && data !== null && typeof data.toArray === "function" && data.constructor?.name === "VectorValue")) {
|
|
660
|
+
if (data instanceof VectorValue || (typeof data === "object" && data !== null && "toArray" in data && typeof (data as Record<string, unknown>).toArray === "function" && (data as { constructor?: { name?: string } }).constructor?.name === "VectorValue")) {
|
|
659
661
|
return { __type__: "__vector__",
|
|
660
|
-
value: data.toArray() };
|
|
662
|
+
value: (data as { toArray: () => number[] }).toArray() };
|
|
661
663
|
}
|
|
662
664
|
|
|
663
665
|
if (data instanceof FirestoreGeoPoint) {
|
|
@@ -674,9 +676,9 @@ databaseId });
|
|
|
674
676
|
return data.map(firestoreToCMSModel).filter(v => v !== undefined);
|
|
675
677
|
}
|
|
676
678
|
if (typeof data === "object") {
|
|
677
|
-
const result: Record<string,
|
|
679
|
+
const result: Record<string, unknown> = {};
|
|
678
680
|
for (const key of Object.keys(data)) {
|
|
679
|
-
const childValue = firestoreToCMSModel(data[key]);
|
|
681
|
+
const childValue = firestoreToCMSModel((data as Record<string, unknown>)[key]);
|
|
680
682
|
if (childValue !== undefined)
|
|
681
683
|
result[key] = childValue;
|
|
682
684
|
}
|
|
@@ -696,24 +698,26 @@ function getCMSPathFromFirestorePath(fsPath: string): string {
|
|
|
696
698
|
}
|
|
697
699
|
|
|
698
700
|
|
|
699
|
-
export function cmsToFirestoreModel(data:
|
|
701
|
+
export function cmsToFirestoreModel(data: unknown, firestore: Firestore, inArray = false): unknown {
|
|
700
702
|
if (data === undefined) {
|
|
701
703
|
return deleteField();
|
|
702
704
|
} else if (data === null) {
|
|
703
705
|
return null;
|
|
704
706
|
} else if (Array.isArray(data)) {
|
|
705
|
-
return data.filter(v => v !== undefined).map(v => cmsToFirestoreModel(v, firestore, true));
|
|
706
|
-
} else if (data.isEntityReference && data.isEntityReference()) {
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
707
|
+
return (data as unknown[]).filter(v => v !== undefined).map(v => cmsToFirestoreModel(v, firestore, true));
|
|
708
|
+
} else if (typeof data === "object" && data !== null && "isEntityReference" in data && typeof (data as Record<string, unknown>).isEntityReference === "function" && (data as { isEntityReference: () => boolean }).isEntityReference()) {
|
|
709
|
+
const entityRef = data as EntityReference;
|
|
710
|
+
const targetFirestore = entityRef.databaseId ? getFirestore(firestore.app, entityRef.databaseId) : firestore;
|
|
711
|
+
return doc(targetFirestore, entityRef.path, entityRef.id);
|
|
712
|
+
} else if (data && typeof data === "object" && "__type" in data && (data as Record<string, unknown>).__type === "relation" && "path" in data && "id" in data) {
|
|
713
|
+
const rel = data as { path: string; id: string | number };
|
|
714
|
+
return doc(firestore, rel.path, String(rel.id));
|
|
711
715
|
} else if (data instanceof GeoPoint) {
|
|
712
716
|
return new FirestoreGeoPoint(data.latitude, data.longitude);
|
|
713
717
|
} else if (data instanceof Date) {
|
|
714
718
|
return Timestamp.fromDate(data);
|
|
715
|
-
} else if (data && typeof data === "object" && "__type__" in data && data.__type__ === "__vector__") {
|
|
716
|
-
return vector(data.value || []);
|
|
719
|
+
} else if (data && typeof data === "object" && "__type__" in data && (data as Record<string, unknown>).__type__ === "__vector__") {
|
|
720
|
+
return vector((data as { value?: number[] }).value || []);
|
|
717
721
|
} else if (data && typeof data === "object") {
|
|
718
722
|
return Object.entries(data)
|
|
719
723
|
.map(([key, v]) => {
|
|
@@ -729,7 +733,7 @@ export function cmsToFirestoreModel(data: any, firestore: Firestore, inArray = f
|
|
|
729
733
|
return data;
|
|
730
734
|
}
|
|
731
735
|
|
|
732
|
-
function currentTime():
|
|
736
|
+
function currentTime(): unknown {
|
|
733
737
|
return serverTimestamp();
|
|
734
738
|
}
|
|
735
739
|
|
|
@@ -774,7 +778,7 @@ function buildTextSearchControllerWithLocalSearch({
|
|
|
774
778
|
search: async (props: {
|
|
775
779
|
searchString: string,
|
|
776
780
|
path: string,
|
|
777
|
-
currentUser?:
|
|
781
|
+
currentUser?: User,
|
|
778
782
|
databaseId?: string
|
|
779
783
|
}) => {
|
|
780
784
|
const search = await textSearchController.search(props);
|
|
@@ -71,9 +71,9 @@ export function useInitialiseFirebase({
|
|
|
71
71
|
setConfigError(undefined);
|
|
72
72
|
setFirebaseConfigLoading(false);
|
|
73
73
|
setFirebaseApp(initialisedFirebaseApp);
|
|
74
|
-
} catch (e:
|
|
74
|
+
} catch (e: unknown) {
|
|
75
75
|
console.error("Error initialising Firebase", e);
|
|
76
|
-
setConfigError(hostingError + "\n" + (e.message
|
|
76
|
+
setConfigError(hostingError + "\n" + (e instanceof Error ? e.message : JSON.stringify(e)));
|
|
77
77
|
}
|
|
78
78
|
}, [name]);
|
|
79
79
|
|
package/src/utils/algolia.ts
CHANGED
|
@@ -8,17 +8,17 @@ import { buildExternalSearchController } from "./text_search_controller";
|
|
|
8
8
|
* @param query
|
|
9
9
|
* @group Firebase
|
|
10
10
|
*/
|
|
11
|
-
export function performAlgoliaTextSearch(client:
|
|
11
|
+
export function performAlgoliaTextSearch(client: { searchSingleIndex: (params: Record<string, unknown>) => Promise<{ hits: Array<{ objectID: string }> }> }, indexName: string, query: string): Promise<readonly string[]> {
|
|
12
12
|
|
|
13
13
|
console.debug("Performing Algolia query", client, query);
|
|
14
14
|
|
|
15
15
|
return client.searchSingleIndex({
|
|
16
16
|
indexName,
|
|
17
17
|
searchParams: { query }
|
|
18
|
-
}).then(({ hits }
|
|
19
|
-
return hits.map((hit
|
|
18
|
+
}).then(({ hits }) => {
|
|
19
|
+
return hits.map((hit) => hit.objectID);
|
|
20
20
|
})
|
|
21
|
-
.catch((err:
|
|
21
|
+
.catch((err: unknown) => {
|
|
22
22
|
console.error(err);
|
|
23
23
|
return [];
|
|
24
24
|
});
|
|
@@ -103,7 +103,7 @@ export const localSearchControllerBuilder: FirestoreTextSearchControllerBuilder
|
|
|
103
103
|
return (a.score ?? 0) - (b.score ?? 0);
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
|
-
return searchResult.map((e
|
|
106
|
+
return searchResult.map((e) => e.item.id);
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
return {
|
|
@@ -96,7 +96,7 @@ export function buildRebaseSearchController(
|
|
|
96
96
|
const extensionInstanceId = options?.extensionInstanceId || "typesense-search";
|
|
97
97
|
|
|
98
98
|
let searchConfig: SearchConfig | null = null;
|
|
99
|
-
let typesenseClient:
|
|
99
|
+
let typesenseClient: unknown = null;
|
|
100
100
|
let initPromise: Promise<void> | null = null;
|
|
101
101
|
|
|
102
102
|
return ({ firebaseApp }: { firebaseApp: FirebaseApp }): FirestoreTextSearchController => {
|
|
@@ -131,12 +131,12 @@ export function buildRebaseSearchController(
|
|
|
131
131
|
if (options?.collections && options.collections.length > 0) {
|
|
132
132
|
searchConfig.collectionsToIndex = options.collections;
|
|
133
133
|
}
|
|
134
|
-
} catch (error:
|
|
134
|
+
} catch (error: unknown) {
|
|
135
135
|
console.error("Failed to get search config from extension:", error);
|
|
136
136
|
throw new Error(
|
|
137
137
|
"Failed to initialize Rebase Search. " +
|
|
138
138
|
"Make sure the rebase-search extension is installed and configured. " +
|
|
139
|
-
`Error: ${error.message
|
|
139
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -253,11 +253,11 @@ export function buildRebaseSearchController(
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
try {
|
|
256
|
-
const collection = await typesenseClient.collections(collectionName).retrieve();
|
|
256
|
+
const collection = await (typesenseClient as Record<string, Function>).collections(collectionName).retrieve();
|
|
257
257
|
|
|
258
258
|
// Extract string fields from the schema
|
|
259
|
-
const stringFields = collection.fields
|
|
260
|
-
.filter((f
|
|
259
|
+
const stringFields = (collection.fields as Array<{ type: string; name: string }>)
|
|
260
|
+
.filter((f) => {
|
|
261
261
|
// Include string and string[] types, exclude internal fields
|
|
262
262
|
const isStringType = f.type === "string" ||
|
|
263
263
|
f.type === "string[]" ||
|
|
@@ -266,12 +266,12 @@ export function buildRebaseSearchController(
|
|
|
266
266
|
const isNotInternal = !f.name.startsWith("_") && f.name !== ".*";
|
|
267
267
|
return isStringType && isNotInternal;
|
|
268
268
|
})
|
|
269
|
-
.map((f
|
|
269
|
+
.map((f) => f.name);
|
|
270
270
|
|
|
271
271
|
schemaCache.set(collectionName, stringFields);
|
|
272
272
|
return stringFields;
|
|
273
|
-
} catch (error:
|
|
274
|
-
if (error.httpStatus === 404) {
|
|
273
|
+
} catch (error: unknown) {
|
|
274
|
+
if (error instanceof Error && "httpStatus" in error && (error as Record<string, unknown>).httpStatus === 404) {
|
|
275
275
|
throw new Error(
|
|
276
276
|
`Collection "${collectionName}" not found in Typesense. ` +
|
|
277
277
|
"Make sure the collection has been indexed. Try running the backfill function."
|
|
@@ -322,7 +322,7 @@ export function buildRebaseSearchController(
|
|
|
322
322
|
const queryBy = searchableFields.join(",");
|
|
323
323
|
|
|
324
324
|
try {
|
|
325
|
-
const searchParams:
|
|
325
|
+
const searchParams: Record<string, unknown> = {
|
|
326
326
|
q: props.searchString,
|
|
327
327
|
query_by: queryBy,
|
|
328
328
|
per_page: 100,
|
|
@@ -335,18 +335,18 @@ export function buildRebaseSearchController(
|
|
|
335
335
|
searchParams.filter_by = parentFilter;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
const result = await typesenseClient
|
|
338
|
+
const result = await (typesenseClient as Record<string, Function>)
|
|
339
339
|
.collections(collectionName)
|
|
340
340
|
.documents()
|
|
341
341
|
.search(searchParams);
|
|
342
342
|
|
|
343
343
|
// Extract document IDs from hits
|
|
344
|
-
const ids = result.hits?.map((hit
|
|
344
|
+
const ids = (result.hits as Array<{ document: { id: string } }> | undefined)?.map((hit) => hit.document.id) ?? [];
|
|
345
345
|
|
|
346
346
|
return ids as readonly string[];
|
|
347
|
-
} catch (error:
|
|
347
|
+
} catch (error: unknown) {
|
|
348
348
|
// Parse error message for user-friendly display
|
|
349
|
-
const message = error.message
|
|
349
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
350
350
|
throw new Error(`Search failed: ${message}`);
|
|
351
351
|
}
|
|
352
352
|
};
|