UNPKG

pulse-ai-utils

Version:

Utility functions and helpers for AI-powered applications

121 lines 6.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadServiceAccount = loadServiceAccount; function loadServiceAccount() { const fs = require('fs'); const path = require('path'); // 1) Via environment variable (raw JSON string) if (process.env.FIREBASE_SERVICE_ACCOUNT_JSON) { try { // The environment variable may contain escaped JSON (e.g., from shell export) let jsonString = process.env.FIREBASE_SERVICE_ACCOUNT_JSON; // Remove any BOM (Byte Order Mark) characters that might be present jsonString = jsonString.replace(/^\uFEFF/, ''); // Trim any leading/trailing whitespace jsonString = jsonString.trim(); // If it starts and ends with quotes, remove them if (jsonString.startsWith('"') && jsonString.endsWith('"')) { jsonString = jsonString.slice(1, -1); } // Try parsing the JSON directly first (handles pretty-printed JSON) try { return JSON.parse(jsonString); } catch (directParseError) { console.log('Direct JSON parse failed, trying cleanup:', directParseError.message); } // Handle control characters in the JSON string // First, escape any literal newlines and other control characters to make valid JSON jsonString = jsonString .replace(/\n/g, '\\n') // escape literal newlines .replace(/\r/g, '\\r') // escape literal carriage returns .replace(/\t/g, '\\t') // escape literal tabs .replace(/\b/g, '\\b') // escape literal backspace .replace(/\f/g, '\\f') // escape literal form feed .replace(/\v/g, '\\v'); // escape literal vertical tab // Then handle escaped sequences if they exist if (jsonString.includes('\\\\')) { jsonString = jsonString .replace(/\\\\n/g, '\\n') // fix double-escaped newlines .replace(/\\\\r/g, '\\r') // fix double-escaped carriage returns .replace(/\\\\t/g, '\\t') // fix double-escaped tabs .replace(/\\\\"/g, '\\"') // fix double-escaped quotes .replace(/\\\\'/g, "\\'") // fix double-escaped single quotes .replace(/\\\\b/g, '\\b') // fix double-escaped backspace .replace(/\\\\f/g, '\\f') // fix double-escaped form feed .replace(/\\\\v/g, '\\v') // fix double-escaped vertical tab .replace(/\\\\\//g, '\\/') // fix double-escaped forward slash .replace(/\\\\\\/g, '\\\\'); // fix triple-escaped backslash } // Try to parse the JSON return JSON.parse(jsonString); } catch (error) { console.error('Failed to parse FIREBASE_SERVICE_ACCOUNT_JSON:', error.message); console.error('JSON string length:', process.env.FIREBASE_SERVICE_ACCOUNT_JSON?.length); console.error('First 200 chars:', process.env.FIREBASE_SERVICE_ACCOUNT_JSON?.substring(0, 200)); // Debug: Check for invisible characters at the beginning const jsonStr = process.env.FIREBASE_SERVICE_ACCOUNT_JSON; if (jsonStr) { console.error('First 10 char codes:', jsonStr.substring(0, 10).split('').map(c => c.charCodeAt(0))); } // Try a different approach - Base64 decode if it looks like base64 if (jsonStr && !jsonStr.startsWith('{') && /^[A-Za-z0-9+/]+=*$/.test(jsonStr)) { try { console.log('Attempting base64 decode...'); const decoded = Buffer.from(jsonStr, 'base64').toString('utf8'); return JSON.parse(decoded); } catch (b64Error) { console.error('Base64 decode also failed:', b64Error.message); } } // Try removing all non-printable characters except newlines and tabs that should be escaped try { console.log('Attempting to clean non-printable characters...'); let cleanJson = jsonStr.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''); cleanJson = cleanJson .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') .replace(/\t/g, '\\t'); return JSON.parse(cleanJson); } catch (cleanError) { console.error('Cleaned JSON parse also failed:', cleanError.message); } throw new Error(`Invalid FIREBASE_SERVICE_ACCOUNT_JSON format: ${error.message}`); } } // 2) Via path from env variable if (process.env.FIREBASE_SERVICE_ACCOUNT_PATH) { try { return JSON.parse(fs.readFileSync(process.env.FIREBASE_SERVICE_ACCOUNT_PATH, 'utf8')); } catch (err) { /* ignore and continue to fallbacks */ } } // 3) <project-root>/configs/firebase-service-account.json (works from any CWD) const rootPath = path.resolve(process.cwd(), 'configs', 'firebase-service-account.json'); try { return JSON.parse(fs.readFileSync(rootPath, 'utf8')); } catch (_) { /* ignore */ } // 4) ../../configs/firebase-service-account.json relative to compiled dir (dist or src) const fallbackPath = path.resolve(__dirname, '..', '..', 'configs', 'firebase-service-account.json'); try { return JSON.parse(fs.readFileSync(fallbackPath, 'utf8')); } catch (_) { /* ignore */ } // In test mode, we skip Firebase initialization entirely, so this shouldn't be called if (process.env.NODE_ENV === 'test') { console.warn('loadServiceAccount called in test mode - this should not happen with proper lazy loading'); throw new Error('Firebase service account should not be loaded in test mode'); } throw new Error('Unable to locate firebase-service-account.json. Provide it via FIREBASE_SERVICE_ACCOUNT_JSON, FIREBASE_SERVICE_ACCOUNT_PATH or place the file under <project-root>/configs.'); } //# sourceMappingURL=load-service-account.js.map