firebase-os 1.1.6 → 1.1.8

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.6",
3
+ "version": "1.1.8",
4
4
  "description": "A complete Firebase-powered admin OS — one React component.",
5
5
  "type": "module",
6
6
  "main": "dist/firebase-os.cjs.js",
@@ -191,32 +191,46 @@ const viteConfigPath = path.join(consumerRoot, 'vite.config.ts');
191
191
  if (fs.existsSync(viteConfigPath)) {
192
192
  let viteConfig = fs.readFileSync(viteConfigPath, 'utf8');
193
193
  if (!viteConfig.includes('@tailwindcss/vite')) {
194
- viteConfig = "import tailwindcss from '@tailwindcss/vite';\\n" + viteConfig;
195
- viteConfig = viteConfig.replace('plugins: [', 'plugins: [\\n tailwindcss(),');
194
+ // Build the patched file with real newlines (not escaped \n literals)
195
+ const importLine = "import tailwindcss from '@tailwindcss/vite';";
196
+ viteConfig = importLine + '\n' + viteConfig;
197
+ viteConfig = viteConfig.replace(
198
+ 'plugins: [',
199
+ 'plugins: [\n tailwindcss(),'
200
+ );
196
201
  fs.writeFileSync(viteConfigPath, viteConfig);
197
202
  console.log(' ✓ Patched vite.config.ts to enable Tailwind CSS v4');
198
203
  }
199
204
  }
200
205
 
201
- // ── 6. Create .env file with placeholders ──────────────────────────────────
206
+ // ── 6. Create .env file with empty placeholders ────────────────────────────
202
207
  const envPath = path.join(consumerRoot, '.env');
203
208
  if (!fs.existsSync(envPath)) {
204
209
  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
210
+ # Fill in each value below with your Firebase Web App credentials.
211
+ # Find them in Firebase Console -> Project Settings -> General -> Your Apps
212
+ # Leave values empty until you are ready — the app will show a Setup page.
213
+ # After filling them in, restart the dev server (npm run dev).
214
+
215
+ # Your Firebase API Key (e.g. AIzaSyD...)
216
+ VITE_FIREBASE_API_KEY=
217
+ # Your Firebase Auth Domain (e.g. myproject.firebaseapp.com)
218
+ VITE_FIREBASE_AUTH_DOMAIN=
219
+ # Your Firebase Project ID (e.g. myproject)
220
+ VITE_FIREBASE_PROJECT_ID=
221
+ # Your Firebase Storage Bucket (e.g. myproject.firebasestorage.app)
222
+ VITE_FIREBASE_STORAGE_BUCKET=
223
+ # Your Firebase Messaging Sender ID (e.g. 123456789012)
224
+ VITE_FIREBASE_MESSAGING_SENDER_ID=
225
+ # Your Firebase App ID (e.g. 1:123456789012:web:abcdef123456)
226
+ VITE_FIREBASE_APP_ID=
227
+
228
+ # Comma-separated list of admin email addresses (these users get admin role on first registration)
229
+ # Example: you@email.com,colleague@email.com
230
+ VITE_ADMIN_EMAILS=
217
231
  `;
218
232
  fs.writeFileSync(envPath, envContent);
219
- console.log(' ✓ Created .env template');
233
+ console.log(' ✓ Created .env template (fill in your Firebase credentials)');
220
234
  }
221
235
 
222
236
  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
  }
@@ -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 => (