firebase-os 1.1.7 → 1.1.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-os",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "A complete Firebase-powered admin OS — one React component.",
5
5
  "type": "module",
6
6
  "main": "dist/firebase-os.cjs.js",
@@ -60,14 +60,20 @@ for (const file of cssFiles) {
60
60
  }
61
61
  }
62
62
 
63
- // ── 2. Patch main.tsx — remove the import './index.css' line ────────────────
63
+ // ── 2. Rewrite main.tsx — import library + theme CSS at the entry point ─────
64
64
  const mainPath = path.join(srcDir, 'main.tsx');
65
65
  if (fs.existsSync(mainPath)) {
66
66
  const mainContent = fs.readFileSync(mainPath, 'utf8');
67
- // Only write if it still has the problematic Vite imports
68
- if (mainContent.includes("import './index.css'") || mainContent.includes('import "./index.css"')) {
67
+ // Rewrite if it has the default Vite CSS import OR if it doesn't have our library CSS
68
+ if (mainContent.includes("import './index.css'") || mainContent.includes('import "./index.css"') || !mainContent.includes('firebase-os')) {
69
69
  const clean = `import { StrictMode } from 'react'
70
70
  import { createRoot } from 'react-dom/client'
71
+
72
+ // Firebase OS — compiled library styles (Tailwind utilities, components, layouts)
73
+ import 'firebase-os/styles.css'
74
+ // Firebase OS — local theme overrides (CSS variables, data-theme, custom styles)
75
+ import './firebase-os/theme.css'
76
+
71
77
  import App from './App.tsx'
72
78
 
73
79
  createRoot(document.getElementById('root')!).render(
@@ -77,7 +83,7 @@ createRoot(document.getElementById('root')!).render(
77
83
  )
78
84
  `;
79
85
  fs.writeFileSync(mainPath, clean);
80
- console.log(' ✓ Patched main.tsx (removed Vite CSS import)');
86
+ console.log(' ✓ Patched main.tsx with Firebase OS styles');
81
87
  }
82
88
  }
83
89
 
@@ -120,9 +126,9 @@ if (fs.existsSync(sourceHomePath)) {
120
126
  }
121
127
 
122
128
  // ── 4. Write App.tsx with Hybrid Overrides Wired Up ───────────────────────
129
+ // Note: CSS imports are in main.tsx (entry point) for correct load ordering.
123
130
  const appPath = path.join(srcDir, 'App.tsx');
124
131
  const appContent = `import { FirebaseOS } from 'firebase-os';
125
- import './firebase-os/theme.css';
126
132
 
127
133
  // Local Hybrid Overrides
128
134
  import { Home } from './firebase-os/Home';
@@ -191,32 +197,46 @@ const viteConfigPath = path.join(consumerRoot, 'vite.config.ts');
191
197
  if (fs.existsSync(viteConfigPath)) {
192
198
  let viteConfig = fs.readFileSync(viteConfigPath, 'utf8');
193
199
  if (!viteConfig.includes('@tailwindcss/vite')) {
194
- viteConfig = "import tailwindcss from '@tailwindcss/vite';\n" + viteConfig;
195
- viteConfig = viteConfig.replace('plugins: [', 'plugins: [\n tailwindcss(),');
200
+ // Build the patched file with real newlines (not escaped \n literals)
201
+ const importLine = "import tailwindcss from '@tailwindcss/vite';";
202
+ viteConfig = importLine + '\n' + viteConfig;
203
+ viteConfig = viteConfig.replace(
204
+ 'plugins: [',
205
+ 'plugins: [\n tailwindcss(),'
206
+ );
196
207
  fs.writeFileSync(viteConfigPath, viteConfig);
197
208
  console.log(' ✓ Patched vite.config.ts to enable Tailwind CSS v4');
198
209
  }
199
210
  }
200
211
 
201
- // ── 6. Create .env file with placeholders ──────────────────────────────────
212
+ // ── 6. Create .env file with empty placeholders ────────────────────────────
202
213
  const envPath = path.join(consumerRoot, '.env');
203
214
  if (!fs.existsSync(envPath)) {
204
215
  const envContent = `# 🔥 Firebase OS Configuration
205
- # Paste your Firebase Web App configuration here.
206
- # You can find these in your Firebase Console -> Project Settings -> General -> Your Apps
207
-
208
- VITE_FIREBASE_API_KEY=your_api_key_here
209
- VITE_FIREBASE_AUTH_DOMAIN=your_project_id.firebaseapp.com
210
- VITE_FIREBASE_PROJECT_ID=your_project_id
211
- VITE_FIREBASE_STORAGE_BUCKET=your_project_id.firebasestorage.app
212
- VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
213
- VITE_FIREBASE_APP_ID=your_app_id
214
-
215
- # Comma-separated list of admin emails
216
- VITE_ADMIN_EMAILS=admin@example.com
216
+ # Fill in each value below with your Firebase Web App credentials.
217
+ # Find them in Firebase Console -> Project Settings -> General -> Your Apps
218
+ # Leave values empty until you are ready — the app will show a Setup page.
219
+ # After filling them in, restart the dev server (npm run dev).
220
+
221
+ # Your Firebase API Key (e.g. AIzaSyD...)
222
+ VITE_FIREBASE_API_KEY=
223
+ # Your Firebase Auth Domain (e.g. myproject.firebaseapp.com)
224
+ VITE_FIREBASE_AUTH_DOMAIN=
225
+ # Your Firebase Project ID (e.g. myproject)
226
+ VITE_FIREBASE_PROJECT_ID=
227
+ # Your Firebase Storage Bucket (e.g. myproject.firebasestorage.app)
228
+ VITE_FIREBASE_STORAGE_BUCKET=
229
+ # Your Firebase Messaging Sender ID (e.g. 123456789012)
230
+ VITE_FIREBASE_MESSAGING_SENDER_ID=
231
+ # Your Firebase App ID (e.g. 1:123456789012:web:abcdef123456)
232
+ VITE_FIREBASE_APP_ID=
233
+
234
+ # Comma-separated list of admin email addresses (these users get admin role on first registration)
235
+ # Example: you@email.com,colleague@email.com
236
+ VITE_ADMIN_EMAILS=
217
237
  `;
218
238
  fs.writeFileSync(envPath, envContent);
219
- console.log(' ✓ Created .env template');
239
+ console.log(' ✓ Created .env template (fill in your Firebase credentials)');
220
240
  }
221
241
 
222
242
  console.log('\n[firebase-os] 🎉 Hybrid Setup complete! You now have full control over styling and configs.\n');
@@ -53,8 +53,14 @@ export interface FirebaseOSProps {
53
53
  export function FirebaseOS(props: FirebaseOSProps) {
54
54
  // If the consumer passed firebaseConfig as props, initialize Firebase
55
55
  // before any child component tries to use auth/db/storage.
56
- if (props.firebaseConfig) {
57
- initializeFirebase(props.firebaseConfig);
56
+ // Guard: only initialize when real credentials are present (not empty strings).
57
+ const fc = props.firebaseConfig;
58
+ const hasRealConfig = fc &&
59
+ fc.apiKey && fc.apiKey.trim() !== '' &&
60
+ fc.projectId && fc.projectId.trim() !== '';
61
+
62
+ if (hasRealConfig) {
63
+ initializeFirebase(fc);
58
64
  }
59
65
 
60
66
  const config: FirebaseOSConfig = {
@@ -60,21 +60,22 @@ function getEnvVal(key: string): string {
60
60
  // Environment key status
61
61
  export function getEnvStatus() {
62
62
  const missing: string[] = [];
63
+ const empty: string[] = [];
63
64
  for (const { key, label } of REQUIRED_KEYS) {
64
65
  const v = getEnvVal(key);
65
- if (!v || v.trim() === '') {
66
- console.log('Missing key:', key, v);
66
+ if (!v) {
67
67
  missing.push(label);
68
- } else {
69
- console.log('Found key:', key, v);
68
+ } else if (v.trim() === '') {
69
+ empty.push(label);
70
70
  }
71
71
  }
72
72
 
73
73
  const adminEmails = getEnvVal('VITE_ADMIN_EMAILS');
74
74
  const missingAdminEmails = !adminEmails || adminEmails.trim() === '';
75
75
 
76
- console.log('Setup complete?', missing.length === 0, missing);
77
- return { allSet: missing.length === 0, missing, missingAdminEmails };
76
+ // Combine missing + empty for the overall check
77
+ const allMissing = [...missing, ...empty];
78
+ return { allSet: allMissing.length === 0, missing: allMissing, empty, missingAdminEmails };
78
79
  }
79
80
 
80
81
  export function isSetupComplete(): boolean {
@@ -171,7 +172,7 @@ export function Setup({ standalone }: SetupProps) {
171
172
  return window.matchMedia('(prefers-color-scheme: dark)').matches;
172
173
  });
173
174
 
174
- const [verifyResult, setVerifyResult] = useState<{ missing: string[]; missingAdminEmails?: boolean } | null>(null);
175
+ const [verifyResult, setVerifyResult] = useState<{ missing: string[]; empty?: string[]; missingAdminEmails?: boolean } | null>(null);
175
176
  const [isVerifying, setIsVerifying] = useState(false);
176
177
 
177
178
  // Only manage the data-theme attribute and favicon when standalone (no ThemeContext)
@@ -199,7 +200,7 @@ export function Setup({ standalone }: SetupProps) {
199
200
  setVerifyResult(null);
200
201
  setTimeout(() => {
201
202
  const status = getEnvStatus();
202
- setVerifyResult({ missing: status.missing, missingAdminEmails: status.missingAdminEmails });
203
+ setVerifyResult({ missing: status.missing, empty: status.empty, missingAdminEmails: status.missingAdminEmails });
203
204
  if (status.allSet) {
204
205
  setTimeout(() => { window.location.href = '/'; }, 1800);
205
206
  }
@@ -232,8 +233,8 @@ export function Setup({ standalone }: SetupProps) {
232
233
  className="glass-panel border border-[var(--panel-border)] rounded-3xl p-6 md:p-10 shadow-2xl relative overflow-hidden bg-background flex flex-col"
233
234
  >
234
235
  {/* Panel header with support buttons */}
235
- <div className="flex flex-col gap-4 mb-8 pb-6 border-b border-[var(--panel-border)]/50 relative z-10">
236
- <div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
236
+ <div className="mb-8 pb-6 border-b border-[var(--panel-border)]/50 relative z-10">
237
+ <div className="flex items-start justify-between gap-4">
237
238
  <div>
238
239
  <h2 className="text-xl font-extrabold text-foreground tracking-tight">Firebase Configuration</h2>
239
240
  <p className="text-[14px] font-medium text-foreground/50 mt-2 leading-relaxed">
@@ -285,7 +286,12 @@ export function Setup({ standalone }: SetupProps) {
285
286
  <div className="w-8 h-8 rounded-full bg-red-500/10 border border-red-500/20 flex items-center justify-center shrink-0">
286
287
  <AlertCircle className="w-4 h-4 text-red-500" />
287
288
  </div>
288
- <span className="font-bold text-foreground/70">Missing values — update <code className="text-accent text-[12px]">.env</code> and restart dev server</span>
289
+ <span className="font-bold text-foreground/70">
290
+ {verifyResult.empty && verifyResult.empty.length > 0
291
+ ? <>These values are <span className="text-red-500">empty</span> — fill them in your <code className="text-accent text-[12px]">.env</code> file and restart the dev server</>
292
+ : <>Missing values — update <code className="text-accent text-[12px]">.env</code> and restart dev server</>
293
+ }
294
+ </span>
289
295
  </div>
290
296
  <div className="flex flex-wrap gap-1.5 ml-10">
291
297
  {verifyResult.missing.map(m => (