@rebasepro/client-firebase 0.2.1 → 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.
@@ -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: any,
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: any): any {
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, any> = {};
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: any, firestore: Firestore, inArray = false): any {
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 targetFirestore = data.databaseId ? getFirestore(firestore.app, data.databaseId) : firestore;
708
- return doc(targetFirestore, data.path, data.id);
709
- } else if (data && typeof data === "object" && data.__type === "relation" && data.path && data.id) {
710
- return doc(firestore, data.path, String(data.id));
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(): any {
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?: any,
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: any) {
74
+ } catch (e: unknown) {
75
75
  console.error("Error initialising Firebase", e);
76
- setConfigError(hostingError + "\n" + (e.message ?? JSON.stringify(e)));
76
+ setConfigError(hostingError + "\n" + (e instanceof Error ? e.message : JSON.stringify(e)));
77
77
  }
78
78
  }, [name]);
79
79
 
@@ -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: any, indexName: string, query: string): Promise<readonly string[]> {
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 }: any) => {
19
- return hits.map((hit: any) => hit.objectID as string);
18
+ }).then(({ hits }) => {
19
+ return hits.map((hit) => hit.objectID);
20
20
  })
21
- .catch((err: any) => {
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: any) => e.item.id);
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: any = null;
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: any) {
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 || error}`
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: any) => {
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: any) => f.name);
269
+ .map((f) => f.name);
270
270
 
271
271
  schemaCache.set(collectionName, stringFields);
272
272
  return stringFields;
273
- } catch (error: any) {
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: any = {
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: any) => hit.document.id) ?? [];
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: any) {
347
+ } catch (error: unknown) {
348
348
  // Parse error message for user-friendly display
349
- const message = error.message || error.toString();
349
+ const message = error instanceof Error ? error.message : String(error);
350
350
  throw new Error(`Search failed: ${message}`);
351
351
  }
352
352
  };