@rebasepro/firebase 0.0.1-canary.2 → 0.0.1-canary.eb08332

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.
Files changed (47) hide show
  1. package/README.md +97 -3
  2. package/dist/components/FirebaseLoginView.d.ts +3 -3
  3. package/dist/components/RebaseFirebaseApp.d.ts +2 -1
  4. package/dist/components/RebaseFirebaseAppProps.d.ts +9 -13
  5. package/dist/components/social_icons.d.ts +6 -6
  6. package/dist/hooks/index.d.ts +3 -1
  7. package/dist/hooks/useAppCheck.d.ts +2 -2
  8. package/dist/hooks/useBuildUserManagement.d.ts +78 -0
  9. package/dist/hooks/useFirebaseAccessGate.d.ts +44 -0
  10. package/dist/hooks/useFirebaseAuthController.d.ts +2 -2
  11. package/dist/hooks/useFirebaseRealTimeDBDelegate.d.ts +2 -2
  12. package/dist/hooks/useFirebaseStorageSource.d.ts +1 -1
  13. package/dist/hooks/{useFirestoreDataSource.d.ts → useFirestoreDriver.d.ts} +9 -9
  14. package/dist/index.es.js +2598 -2663
  15. package/dist/index.es.js.map +1 -1
  16. package/dist/index.umd.js +2704 -2702
  17. package/dist/index.umd.js.map +1 -1
  18. package/dist/types/auth.d.ts +2 -2
  19. package/dist/types/text_search.d.ts +3 -3
  20. package/dist/utils/algolia.d.ts +7 -6
  21. package/dist/utils/collections_firestore.d.ts +4 -4
  22. package/package.json +75 -65
  23. package/src/components/FirebaseLoginView.tsx +53 -50
  24. package/src/components/RebaseFirebaseApp.tsx +82 -56
  25. package/src/components/RebaseFirebaseAppProps.tsx +10 -24
  26. package/src/components/social_icons.tsx +8 -8
  27. package/src/hooks/index.ts +3 -1
  28. package/src/hooks/useAppCheck.ts +5 -5
  29. package/src/hooks/useBuildUserManagement.tsx +366 -0
  30. package/src/hooks/useFirebaseAccessGate.tsx +145 -0
  31. package/src/hooks/useFirebaseAuthController.ts +6 -8
  32. package/src/hooks/useFirebaseRealTimeDBDelegate.ts +70 -79
  33. package/src/hooks/useFirebaseStorageSource.ts +23 -25
  34. package/src/hooks/useFirestoreDriver.ts +812 -0
  35. package/src/hooks/useInitialiseFirebase.ts +2 -2
  36. package/src/types/auth.tsx +2 -2
  37. package/src/types/text_search.ts +3 -3
  38. package/src/utils/algolia.ts +6 -9
  39. package/src/utils/collections_firestore.ts +25 -29
  40. package/src/utils/database.ts +2 -2
  41. package/src/utils/local_text_search_controller.ts +12 -12
  42. package/src/utils/pinecone.ts +3 -3
  43. package/src/utils/rebase_search_controller.ts +23 -22
  44. package/src/utils/text_search_controller.ts +2 -2
  45. package/dist/social_icons.d.ts +0 -6
  46. package/src/hooks/useFirestoreDataSource.ts +0 -796
  47. package/src/social_icons.tsx +0 -135
@@ -2,27 +2,34 @@ import React from "react";
2
2
  import { GoogleAuthProvider } from "@firebase/auth";
3
3
 
4
4
  import {
5
- AppBar,
6
- CircularProgressCenter,
7
- Drawer,
8
5
  Rebase,
9
- RebaseRoute,
10
6
  ModeControllerProvider,
11
- PropertyConfig,
12
- Scaffold,
13
- SideDialogs,
14
7
  SnackbarProvider,
15
8
  useBrowserTitleAndIcon,
16
9
  useBuildLocalConfigurationPersistence,
17
10
  useBuildModeController,
18
11
  useBuildAdminModeController,
19
12
  AdminModeControllerProvider,
13
+ RebaseRoutes
14
+ } from "@rebasepro/app";
15
+ import {
16
+ AppBar,
17
+ Drawer,
18
+ Scaffold,
19
+ SideDialogs,
20
20
  useBuildCollectionRegistryController,
21
- useBuildCMSUrlController,
21
+ useBuildUrlController,
22
22
  useBuildNavigationStateController,
23
- useValidateAuthenticator
24
- } from "@rebasepro/core";
25
- import { Route, Routes, Outlet } from "react-router-dom";
23
+ CollectionRegistryContext,
24
+ UrlContext,
25
+ NavigationStateContext,
26
+ SidePanelProvider,
27
+ RebaseRoute
28
+ } from "@rebasepro/admin";
29
+ import { DEFAULT_DATA_SOURCE_KEY, Entity, PropertyConfig, RebaseContext } from "@rebasepro/types";
30
+ import { CenteredView, CircularProgressCenter } from "@rebasepro/ui";
31
+ import { buildRebaseData } from "@rebasepro/common";
32
+ import { Route, Outlet, Navigate } from "react-router-dom";
26
33
 
27
34
  import { RebaseFirebaseAppProps } from "./RebaseFirebaseAppProps";
28
35
  import { FirebaseLoginView } from "./FirebaseLoginView";
@@ -30,10 +37,12 @@ import {
30
37
  useAppCheck,
31
38
  useFirebaseAuthController,
32
39
  useFirebaseStorageSource,
33
- useFirestoreDataSource,
40
+ useFirestoreDriver,
34
41
  useInitialiseFirebase,
42
+ useBuildUserManagement,
43
+ useFirebaseAccessGate
35
44
  } from "../hooks";
36
- import { CenteredView } from "@rebasepro/ui";
45
+
37
46
  import { FirebaseAuthController } from "../types";
38
47
 
39
48
  const DEFAULT_SIGN_IN_OPTIONS = [
@@ -61,7 +70,7 @@ export function RebaseFirebaseApp({
61
70
  name,
62
71
  logo,
63
72
  logoDark,
64
- authenticator,
73
+ accessGate,
65
74
  collections,
66
75
  views,
67
76
  adminViews,
@@ -81,8 +90,7 @@ export function RebaseFirebaseApp({
81
90
  autoOpenDrawer,
82
91
  firestoreIndexesBuilder,
83
92
  components,
84
- localTextSearchEnabled = false,
85
- userManagement
93
+ localTextSearchEnabled = false
86
94
  }: RebaseFirebaseAppProps) {
87
95
 
88
96
  /**
@@ -94,7 +102,8 @@ export function RebaseFirebaseApp({
94
102
  .map(pc => ({
95
103
  [pc.key]: pc
96
104
  }))
97
- .reduce((a, b) => ({ ...a, ...b }), {});
105
+ .reduce((a, b) => ({ ...a,
106
+ ...b }), {});
98
107
 
99
108
  const {
100
109
  firebaseApp,
@@ -133,7 +142,7 @@ export function RebaseFirebaseApp({
133
142
  */
134
143
  const userConfigPersistence = useBuildLocalConfigurationPersistence();
135
144
 
136
- const firestoreDelegate = useFirestoreDataSource({
145
+ const firestoreDelegate = useFirestoreDriver({
137
146
  firebaseApp,
138
147
  textSearchControllerBuilder: textSearchControllerBuilder,
139
148
  firestoreIndexesBuilder: firestoreIndexesBuilder,
@@ -148,16 +157,16 @@ export function RebaseFirebaseApp({
148
157
  });
149
158
 
150
159
  /**
151
- * Validate authenticator
160
+ * Validate access gate
152
161
  */
153
162
  const {
154
163
  authLoading,
155
164
  canAccessMainView,
156
165
  notAllowedError
157
- } = useValidateAuthenticator({
166
+ } = useFirebaseAccessGate({
158
167
  authController,
159
- authenticator,
160
- dataSource: firestoreDelegate,
168
+ accessGate,
169
+ data: buildRebaseData(firestoreDelegate),
161
170
  storageSource
162
171
  });
163
172
 
@@ -165,28 +174,33 @@ export function RebaseFirebaseApp({
165
174
  userConfigPersistence
166
175
  });
167
176
 
168
- const cmsUrlController = useBuildCMSUrlController({
177
+ const urlController = useBuildUrlController({
169
178
  basePath: basePath ?? "/",
170
179
  baseCollectionPath: baseCollectionPath ?? "/c",
171
180
  collectionRegistryController
172
181
  });
173
182
 
183
+ const defaultUserManagement = useBuildUserManagement({
184
+ authController,
185
+ dataSourceDelegate: firestoreDelegate
186
+ });
187
+
188
+
174
189
  const navigationStateController = useBuildNavigationStateController({
175
190
  collections,
176
191
  views,
177
192
  adminViews,
178
193
  authController,
179
- dataSource: firestoreDelegate,
194
+ data: buildRebaseData(firestoreDelegate),
180
195
  plugins,
181
196
  collectionRegistryController,
182
- cmsUrlController,
183
- adminMode: adminModeController.mode,
184
- userManagement: userManagement as any
197
+ urlController,
198
+ adminMode: adminModeController.mode
185
199
  });
186
200
 
187
201
  if (firebaseConfigLoading || !firebaseApp || loading) {
188
202
  return <>
189
- <CircularProgressCenter />
203
+ <CircularProgressCenter/>
190
204
  </>;
191
205
  }
192
206
 
@@ -199,17 +213,21 @@ export function RebaseFirebaseApp({
199
213
  <ModeControllerProvider value={modeController}>
200
214
  <AdminModeControllerProvider value={adminModeController}>
201
215
 
202
- <Rebase
203
- authController={authController}
204
- collectionRegistryController={collectionRegistryController}
205
- cmsUrlController={cmsUrlController}
206
- navigationStateController={navigationStateController}
207
- userConfigPersistence={userConfigPersistence}
216
+ <CollectionRegistryContext.Provider value={collectionRegistryController}>
217
+ <UrlContext.Provider value={urlController}>
218
+ <NavigationStateContext.Provider value={navigationStateController}>
219
+ <Rebase
220
+ authController={authController}
221
+ userConfigPersistence={userConfigPersistence}
208
222
  dateTimeFormat={dateTimeFormat}
209
- dataSource={firestoreDelegate}
223
+ dataSources={[{
224
+ key: DEFAULT_DATA_SOURCE_KEY,
225
+ engine: "firestore",
226
+ transport: "direct",
227
+ driver: firestoreDelegate
228
+ }]}
210
229
  storageSource={storageSource}
211
- userManagement={userManagement}
212
- entityLinkBuilder={({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
230
+ entityLinkBuilder={({ entity }: { entity: Entity<any> }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
213
231
  locale={locale}
214
232
  onAnalyticsEvent={onAnalyticsEvent}
215
233
  plugins={plugins}
@@ -217,11 +235,11 @@ export function RebaseFirebaseApp({
217
235
  {({
218
236
  context,
219
237
  loading
220
- }) => {
238
+ }: { context: RebaseContext, loading: boolean }) => {
221
239
 
222
240
  let component;
223
241
  if (loading || authLoading) {
224
- component = <CircularProgressCenter size={"large"} />;
242
+ component = <CircularProgressCenter size={"large"}/>;
225
243
  } else {
226
244
  const usedLogo = modeController.mode === "dark" && logoDark ? logoDark : logo;
227
245
  if (!canAccessMainView) {
@@ -233,32 +251,40 @@ export function RebaseFirebaseApp({
233
251
  signInOptions={signInOptions ?? DEFAULT_SIGN_IN_OPTIONS}
234
252
  firebaseApp={firebaseApp}
235
253
  authController={authController}
236
- notAllowedError={notAllowedError} />
254
+ notAllowedError={notAllowedError instanceof Error ? notAllowedError : typeof notAllowedError === "string" ? notAllowedError : undefined}/>
237
255
  );
238
256
  } else {
257
+ const firstCollectionEntry = navigationStateController.topLevelNavigation?.navigationEntries.find(e => e.type === "collection");
258
+ const fallbackRoute = firstCollectionEntry ? <Navigate to={urlController.buildUrlCollectionPath(firstCollectionEntry.id)} replace /> : <CenteredView>No home page or collections provided.</CenteredView>;
259
+
239
260
  component = (
240
- <Routes>
241
- <Route element={
242
- <Scaffold
243
- logo={usedLogo}
244
- autoOpenDrawer={autoOpenDrawer}>
245
- <AppBar title={name} logo={usedLogo} />
246
- <Drawer />
247
- <Outlet />
248
- <SideDialogs />
249
- </Scaffold>
250
- }>
251
- {components?.HomePage && <Route path="/" element={<components.HomePage />} />}
252
- <Route path="/c/*" element={<RebaseRoute />} />
253
- </Route>
254
- </Routes>
261
+ <SidePanelProvider>
262
+ <RebaseRoutes>
263
+ <Route element={
264
+ <Scaffold
265
+ logo={usedLogo}
266
+ autoOpenDrawer={autoOpenDrawer}>
267
+ <AppBar title={name} logo={usedLogo}/>
268
+ <Drawer/>
269
+ <Outlet/>
270
+ <SideDialogs/>
271
+ </Scaffold>
272
+ }>
273
+ <Route path="/" element={components?.HomePage ? <components.HomePage/> : fallbackRoute}/>
274
+ <Route path="/c/*" element={<RebaseRoute/>}/>
275
+ </Route>
276
+ </RebaseRoutes>
277
+ </SidePanelProvider>
255
278
  );
256
279
  }
257
280
  }
258
281
 
259
282
  return component;
260
283
  }}
261
- </Rebase>
284
+ </Rebase>
285
+ </NavigationStateContext.Provider>
286
+ </UrlContext.Provider>
287
+ </CollectionRegistryContext.Provider>
262
288
  </AdminModeControllerProvider>
263
289
  </ModeControllerProvider>
264
290
  </SnackbarProvider>
@@ -1,17 +1,8 @@
1
1
  import React from "react";
2
2
 
3
- import {
4
- Authenticator,
5
- CMSAnalyticsEvent,
6
- CMSView,
7
- CMSViewsBuilder,
8
- EntityCollection,
9
- EntityCollectionsBuilder,
10
- RebasePlugin,
11
- Locale,
12
- PropertyConfig
13
- } from "@rebasepro/core";
14
- import { UserManagementDelegate } from "@rebasepro/types";
3
+ import { AnalyticsEvent, AppView, AppViewsBuilder, CollectionConfig, CollectionConfigsBuilder, RebasePlugin, Locale, PropertyConfig } from "@rebasepro/types";
4
+ import { FirebaseAccessGate } from "../hooks/useFirebaseAccessGate";
5
+
15
6
  import { FirebaseApp } from "@firebase/app";
16
7
  import { FirebaseLoginViewProps } from "./FirebaseLoginView";
17
8
  import {
@@ -51,19 +42,19 @@ export type RebaseFirebaseAppProps = {
51
42
  * Each of the navigation entries in this field
52
43
  * generates an entry in the main menu.
53
44
  */
54
- collections?: EntityCollection[] | EntityCollectionsBuilder;
45
+ collections?: CollectionConfig[] | CollectionConfigsBuilder;
55
46
 
56
47
  /**
57
48
  * Custom additional views created by the developer, added to the main
58
49
  * navigation
59
50
  */
60
- views?: CMSView[] | CMSViewsBuilder;
51
+ views?: AppView[] | AppViewsBuilder;
61
52
 
62
53
  /**
63
54
  * Custom additional views created by the developer, added to the admin
64
55
  * navigation
65
56
  */
66
- adminViews?: CMSView[] | CMSViewsBuilder;
57
+ adminViews?: AppView[] | AppViewsBuilder;
67
58
 
68
59
  /**
69
60
  * Record of custom form fields to be used in the CMS.
@@ -74,12 +65,12 @@ export type RebaseFirebaseAppProps = {
74
65
 
75
66
  /**
76
67
  * Do the users need to log in to access the CMS.
77
- * You can specify an Authenticator function to discriminate which users can
78
- * access the CMS or not.
68
+ * You can specify a {@link FirebaseAccessGate} function to discriminate
69
+ * which users can access the CMS or not.
79
70
  * If not specified, authentication is enabled but no user restrictions
80
71
  * apply
81
72
  */
82
- authenticator?: boolean | Authenticator<FirebaseUserWrapper>;
73
+ accessGate?: boolean | FirebaseAccessGate<FirebaseUserWrapper>;
83
74
 
84
75
  /**
85
76
  * List of sign in options that will be displayed in the login
@@ -146,7 +137,7 @@ export type RebaseFirebaseAppProps = {
146
137
  /**
147
138
  * Callback used to get analytics events from the CMS
148
139
  */
149
- onAnalyticsEvent?: (event: CMSAnalyticsEvent, data?: object) => void;
140
+ onAnalyticsEvent?: (event: AnalyticsEvent, data?: object) => void;
150
141
 
151
142
  /**
152
143
  * Use plugins to modify the behaviour of the CMS.
@@ -170,11 +161,6 @@ export type RebaseFirebaseAppProps = {
170
161
 
171
162
  components?: ComponentsRegistry;
172
163
 
173
- /**
174
- * Delegate for user and role management. Provides the admin views if specified.
175
- */
176
- userManagement?: UserManagementDelegate;
177
-
178
164
  };
179
165
 
180
166
  export type ComponentsRegistry = {
@@ -2,8 +2,8 @@ export const googleIcon = (mode: "light" | "dark") => <>
2
2
  <svg
3
3
  xmlns="http://www.w3.org/2000/svg"
4
4
  viewBox="0 0 64 64"
5
- width={32}
6
- height={32}
5
+ width={24}
6
+ height={24}
7
7
  >
8
8
  <linearGradient
9
9
  id="95yY7w43Oj6n2vH63j6HJb"
@@ -80,7 +80,7 @@ export const googleIcon = (mode: "light" | "dark") => <>
80
80
  </svg>
81
81
  </>;
82
82
 
83
- export const appleIcon = (mode: "light" | "dark") => <svg width={32} height={32}
83
+ export const appleIcon = (mode: "light" | "dark") => <svg width={24} height={24}
84
84
  viewBox="0 0 56 56"
85
85
  style={{ transform: "scale(2.8)" }}
86
86
  version="1.1"
@@ -97,8 +97,8 @@ export const githubIcon = (mode: "light" | "dark") => <svg
97
97
  fill={mode === "light" ? "#1c1e21" : "white"}
98
98
  role="img"
99
99
  viewBox="0 0 24 24"
100
- width={28}
101
- height={28}
100
+ width={24}
101
+ height={24}
102
102
  xmlns="http://www.w3.org/2000/svg">
103
103
  <path
104
104
  d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
@@ -107,7 +107,7 @@ export const githubIcon = (mode: "light" | "dark") => <svg
107
107
 
108
108
  export const facebookIcon = (mode: "light" | "dark") => <svg
109
109
  xmlns="http://www.w3.org/2000/svg"
110
- width={28} height={28}
110
+ width={24} height={24}
111
111
  viewBox="0 0 90 90">
112
112
  <g>
113
113
  <path
@@ -117,7 +117,7 @@ export const facebookIcon = (mode: "light" | "dark") => <svg
117
117
  </svg>;
118
118
 
119
119
  export const microsoftIcon = (mode: "light" | "dark") => <svg
120
- xmlns="http://www.w3.org/2000/svg" width={28} height={28}
120
+ xmlns="http://www.w3.org/2000/svg" width={24} height={24}
121
121
  viewBox="0 0 480 480">
122
122
  <g>
123
123
  <path
@@ -127,7 +127,7 @@ export const microsoftIcon = (mode: "light" | "dark") => <svg
127
127
  </svg>;
128
128
 
129
129
  export const twitterIcon = (mode: "light" | "dark") => <svg
130
- xmlns="http://www.w3.org/2000/svg" width={28} height={28}
130
+ xmlns="http://www.w3.org/2000/svg" width={24} height={24}
131
131
  viewBox="0 0 24 24">
132
132
  <path fill={mode === "light" ? "#00acee" : "white"}
133
133
  d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
@@ -2,6 +2,8 @@ export * from "./useFirebaseAuthController";
2
2
  export * from "./useFirebaseStorageSource";
3
3
  export * from "./useInitialiseFirebase";
4
4
  export * from "./useAppCheck";
5
- export * from "./useFirestoreDataSource";
5
+ export * from "./useFirestoreDriver";
6
6
  export * from "./useFirebaseRealTimeDBDelegate";
7
7
  export * from "./useRecaptcha";
8
+ export * from "./useBuildUserManagement";
9
+ export * from "./useFirebaseAccessGate";
@@ -15,7 +15,7 @@ export interface InitializeAppCheckProps {
15
15
  export interface InitializeAppCheckResult {
16
16
  loading: boolean;
17
17
  appCheckVerified?: boolean;
18
- error?: any;
18
+ error?: unknown;
19
19
  }
20
20
 
21
21
  /**
@@ -25,7 +25,7 @@ export interface InitializeAppCheckResult {
25
25
  */
26
26
  export function useAppCheck({
27
27
  firebaseApp,
28
- options,
28
+ options
29
29
  }: InitializeAppCheckProps): InitializeAppCheckResult {
30
30
  if (options?.debugToken) {
31
31
  Object.assign(window, {
@@ -35,7 +35,7 @@ export function useAppCheck({
35
35
 
36
36
  const [appCheckLoading, setAppCheckLoading] = React.useState<boolean>(false);
37
37
  const [appCheckVerified, setAppCheckVerified] = React.useState<boolean | undefined>(undefined);
38
- const [error, setError] = React.useState<any>();
38
+ const [error, setError] = React.useState<unknown>();
39
39
 
40
40
  const initialCheck = useRef<boolean>(false);
41
41
 
@@ -51,9 +51,9 @@ export function useAppCheck({
51
51
  setAppCheckVerified(true);
52
52
  console.debug("App Check success.");
53
53
  }
54
- } catch (e: any) {
54
+ } catch (e: unknown) {
55
55
  console.error("App Check error:", e);
56
- setError(e.message);
56
+ setError(e instanceof Error ? e.message : String(e));
57
57
  }
58
58
  }, [options?.forceRefresh]);
59
59