From 568053a1beca73729581571b16ae70e2aa5b8e29 Mon Sep 17 00:00:00 2001 From: Steven Le Date: Tue, 1 Jul 2025 21:25:40 -0700 Subject: [PATCH] feat(root-cms): add storageConfig for cross-project buckets --- .changeset/storage-bucket-project.md | 4 ++++ docs/root.config.ts | 6 ++++++ examples/blog/root.config.ts | 6 ++++++ examples/cms/root.config.ts | 6 ++++++ packages/root-cms/core/app.tsx | 2 ++ packages/root-cms/core/plugin.ts | 24 ++++++++++++++++-------- packages/root-cms/signin/signin.tsx | 1 + packages/root-cms/ui/ui.tsx | 13 +++++++++++-- 8 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 .changeset/storage-bucket-project.md diff --git a/.changeset/storage-bucket-project.md b/.changeset/storage-bucket-project.md new file mode 100644 index 00000000..d280f9be --- /dev/null +++ b/.changeset/storage-bucket-project.md @@ -0,0 +1,4 @@ +--- +"@blinkk/root-cms": minor +--- +feat: add `storageConfig` option to support storage buckets in a different Firebase project. diff --git a/docs/root.config.ts b/docs/root.config.ts index 10358ac6..ac9b496f 100644 --- a/docs/root.config.ts +++ b/docs/root.config.ts @@ -42,6 +42,12 @@ export default defineConfig({ projectId: 'rootjs-dev', storageBucket: 'rootjs-dev.appspot.com', }, + storageConfig: { + apiKey: 'AIzaSyDIoi6zECKeyJoCduYEmV5j9PIF-wbpaPo', + authDomain: 'rootjs-dev.firebaseapp.com', + projectId: 'rootjs-dev', + storageBucket: 'rootjs-dev.appspot.com', + }, gapi: { apiKey: process.env.GAPI_API_KEY, clientId: process.env.GAPI_CLIENT_ID, diff --git a/examples/blog/root.config.ts b/examples/blog/root.config.ts index 6b530cda..0da20938 100644 --- a/examples/blog/root.config.ts +++ b/examples/blog/root.config.ts @@ -64,6 +64,12 @@ export default defineConfig({ appId: '1:636169634531:web:7b8fe398f10e5d9c4e7bd6', measurementId: 'G-5JTQHSPWBB', }, + storageConfig: { + apiKey: 'AIzaSyDIoi6zECKeyJoCduYEmV5j9PIF-wbpaPo', + authDomain: 'rootjs-dev.firebaseapp.com', + projectId: 'rootjs-dev', + storageBucket: 'rootjs-dev.appspot.com', + }, gapi: { apiKey: process.env.GAPI_API_KEY, clientId: process.env.GAPI_CLIENT_ID, diff --git a/examples/cms/root.config.ts b/examples/cms/root.config.ts index 82e06971..54499b86 100644 --- a/examples/cms/root.config.ts +++ b/examples/cms/root.config.ts @@ -34,6 +34,12 @@ export default defineConfig({ projectId: 'rootjs-dev', storageBucket: 'rootjs-dev.appspot.com', }, + storageConfig: { + apiKey: 'AIzaSyDIoi6zECKeyJoCduYEmV5j9PIF-wbpaPo', + authDomain: 'rootjs-dev.firebaseapp.com', + projectId: 'rootjs-dev', + storageBucket: 'rootjs-dev.appspot.com', + }, gapi: { apiKey: process.env.GAPI_API_KEY, clientId: process.env.GAPI_CLIENT_ID, diff --git a/packages/root-cms/core/app.tsx b/packages/root-cms/core/app.tsx index 9ec6365d..0a148ab1 100644 --- a/packages/root-cms/core/app.tsx +++ b/packages/root-cms/core/app.tsx @@ -106,6 +106,7 @@ export async function renderApp( }, }, firebaseConfig: cmsConfig.firebaseConfig, + storageConfig: cmsConfig.storageConfig, gapi: cmsConfig.gapi, collections: collections, sidebar: cmsConfig.sidebar, @@ -220,6 +221,7 @@ export async function renderSignIn( const ctx = { name: options.cmsConfig.name || options.cmsConfig.id || '', firebaseConfig: options.cmsConfig.firebaseConfig, + storageConfig: options.cmsConfig.storageConfig, }; const mainHtml = renderToString(); let html = `\n${mainHtml}`; diff --git a/packages/root-cms/core/plugin.ts b/packages/root-cms/core/plugin.ts index 94d92539..f836916e 100644 --- a/packages/root-cms/core/plugin.ts +++ b/packages/root-cms/core/plugin.ts @@ -59,6 +59,15 @@ export interface CMSSidebarTool { iframeUrl?: string; } +export interface CMSFirebaseConfig { + [key: string]: string | undefined; + apiKey: string; + authDomain: string; + projectId: string; + storageBucket: string; + databaseId?: string; +} + export type CMSPluginOptions = { /** * The ID of the project. Data will be stored under the namespace @@ -76,14 +85,13 @@ export type CMSPluginOptions = { * Firebase config object, which can be obtained in the Firebase Console by * going to "Project Settings". */ - firebaseConfig: { - [key: string]: string | undefined; - apiKey: string; - authDomain: string; - projectId: string; - storageBucket: string; - databaseId?: string; - }; + firebaseConfig: CMSFirebaseConfig; + + /** + * Optional Firebase config used for interacting with a storage bucket that + * exists in a different Firebase project. + */ + storageConfig?: CMSFirebaseConfig; /** * GAPI credentials. Include if using Google Drive and Google Sheets features. diff --git a/packages/root-cms/signin/signin.tsx b/packages/root-cms/signin/signin.tsx index b97910fb..9744add6 100644 --- a/packages/root-cms/signin/signin.tsx +++ b/packages/root-cms/signin/signin.tsx @@ -11,6 +11,7 @@ declare global { __ROOT_CTX: { name: string; firebaseConfig: Record; + storageConfig?: Record; }; firebase: { app: FirebaseApp; diff --git a/packages/root-cms/ui/ui.tsx b/packages/root-cms/ui/ui.tsx index 1eae0ea0..f08182c7 100644 --- a/packages/root-cms/ui/ui.tsx +++ b/packages/root-cms/ui/ui.tsx @@ -1,7 +1,7 @@ import {MantineProvider} from '@mantine/core'; import {ModalsProvider} from '@mantine/modals'; import {NotificationsProvider} from '@mantine/notifications'; -import {initializeApp} from 'firebase/app'; +import {initializeApp, getApp} from 'firebase/app'; import {User, getAuth} from 'firebase/auth'; import {initializeFirestore} from 'firebase/firestore'; import {getStorage} from 'firebase/storage'; @@ -66,6 +66,7 @@ declare global { }; }; firebaseConfig: Record; + storageConfig?: Record; gapi?: { apiKey: string; clientId: string; @@ -169,6 +170,14 @@ function loginRedirect() { } const app = initializeApp(window.__ROOT_CTX.firebaseConfig); +let storageApp = app; +if (window.__ROOT_CTX.storageConfig) { + try { + storageApp = initializeApp(window.__ROOT_CTX.storageConfig, 'storage'); + } catch (err) { + storageApp = getApp('storage'); + } +} const databaseId = window.__ROOT_CTX.firebaseConfig.databaseId || '(default)'; // const db = getFirestore(app); // NOTE(stevenle): the firestore web channel rpc sometimes has issues in @@ -184,7 +193,7 @@ const db = initializeFirestore( databaseId ); const auth = getAuth(app); -const storage = getStorage(app); +const storage = getStorage(storageApp); auth.onAuthStateChanged((user) => { if (!user) { loginRedirect();