Spaces:
Runtime error
Runtime error
File size: 4,289 Bytes
7e49c4d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | import { initializeApp, cert, getApps } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import logger from './logger.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let serviceAccount = null;
// 1. Try environment variable
if (process.env.FIREBASE_SERVICE_ACCOUNT) {
try {
serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
logger.info('Firebase credentials loaded from FIREBASE_SERVICE_ACCOUNT environment variable.');
} catch (err) {
logger.error('Failed to parse FIREBASE_SERVICE_ACCOUNT environment variable:', {
error: err.message || err,
});
}
}
// 2. Try local firebase-key.json
const keyPath = path.resolve(__dirname, '../../firebase-key.json');
if (!serviceAccount && fs.existsSync(keyPath)) {
try {
const rawKey = fs.readFileSync(keyPath, 'utf8');
serviceAccount = JSON.parse(rawKey);
logger.info('Firebase credentials loaded from firebase-key.json.');
} catch (err) {
logger.error('Failed to load firebase-key.json:', { error: err.message || err });
}
}
let db;
if (serviceAccount && process.env.NODE_ENV !== 'test') {
try {
if (getApps().length === 0) {
initializeApp({
credential: cert(serviceAccount),
});
}
db = getFirestore();
logger.info('EcoGuide Connected to Firebase Firestore');
} catch (err) {
logger.error('Firebase initialization failed:', { error: err.message || err });
}
}
if (!db) {
// Safe mock db for testing or local development fallback
logger.info('EcoGuide Running with IN-MEMORY / MOCK Firestore');
// Minimal Firestore mock interface
class MockDoc {
constructor(data, id) {
this.id = id;
this._data = data;
this.exists = !!data;
}
data() {
return this._data || null;
}
}
class MockQuerySnapshot {
constructor(docs) {
this.docs = docs;
this.empty = docs.length === 0;
}
}
class MockCollection {
constructor(name, parentDoc = null) {
this.name = name;
this.parentDoc = parentDoc;
}
doc(id) {
const self = this;
return {
id,
get: async () => {
// Access the globally mocked store
const path = self.getPath(id);
const data = mockStore[path];
return new MockDoc(data, id);
},
set: async (data) => {
const path = self.getPath(id);
mockStore[path] = { ...data };
},
update: async (data) => {
const path = self.getPath(id);
mockStore[path] = { ...(mockStore[path] || {}), ...data };
},
delete: async () => {
const path = self.getPath(id);
delete mockStore[path];
},
collection: (subName) => {
return new MockCollection(subName, { path: self.getPath(id) });
},
};
}
getPath(docId) {
if (this.parentDoc) {
return `${this.parentDoc.path}/${this.name}/${docId}`;
}
return `${this.name}/${docId}`;
}
async get() {
const prefix = this.parentDoc ? `${this.parentDoc.path}/${this.name}/` : `${this.name}/`;
const matchedDocs = [];
for (const [key, val] of Object.entries(mockStore)) {
if (key.startsWith(prefix)) {
const parts = key.slice(prefix.length).split('/');
if (parts.length === 1) {
matchedDocs.push(new MockDoc(val, parts[0]));
}
}
}
return new MockQuerySnapshot(matchedDocs);
}
where(field, op, value) {
const self = this;
return {
get: async () => {
const snapshot = await self.get();
const filtered = snapshot.docs.filter((doc) => {
const val = doc.data()?.[field];
if (op === '==') return val === value;
return false;
});
return new MockQuerySnapshot(filtered);
},
};
}
}
// Global in-memory storage for the mock Firestore
const mockStore = {};
db = {
collection: (name) => new MockCollection(name),
_mockStore: mockStore, // Expose for testing
};
}
export default db;
|