Skip to content

Commit

Permalink
Making postinstall.mjs more robust
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesdaniels committed Dec 5, 2024
1 parent 6470299 commit cd6d61a
Showing 1 changed file with 70 additions and 26 deletions.
96 changes: 70 additions & 26 deletions packages/util/postinstall.mjs
Original file line number Diff line number Diff line change
@@ -1,41 +1,85 @@
import { writeFile } from "fs/promises";

let firebaseConfig = {};
if (process.env.FIREBASE_CONFIG?.startsWith("{")) {
// TODO probably want a more robust yaml parse
firebaseConfig = Object.fromEntries(process.env.FIREBASE_CONFIG.match(/[^(\:\{\},)]+\:[^(,})]+/g).map(it => {
const parts = it.split(":");
return [parts[0], parts.slice(1).join(":")]
}));
}
import { writeFile, readFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
import { isAbsolute, join } from "node:path";

const projectId = firebaseConfig.projectId;
const appId = firebaseConfig.appId;
const apiKey = firebaseConfig.apiKey;
async function getWebConfig() {
let configFromEnvironment = undefined;
// $FIREBASE_WEBAPP_CONFIG can be either a JSON representation of FirebaseOptions or the path
// to a filename
if (process.env.FIREBASE_WEBAPP_CONFIG) {
if (process.env.FIREBASE_WEBAPP_CONFIG.startsWith("{")) {
try {
configFromEnvironment = JSON.parse(process.env.FIREBASE_WEBAPP_CONFIG);
} catch(e) {
console.error("FIREBASE_WEBAPP_CONFIG could not be parsed.", e);
}
} else {
const fileName = process.env.FIREBASE_WEBAPP_CONFIG;
const fileURL = pathToFileURL(isAbsolute(fileName) ? fileName : join(process.cwd(), fileName));
const fileContents = await readFile(fileURL, "utf-8").catch((err) => {
console.error(err);
return undefined;
});
if (fileContents) {
try {
configFromEnvironment = JSON.parse(fileContents);
} catch(e) {
console.error(`Contents of ${fileName} could not be parsed.`, e);
}
}
}
}

const config = projectId && appId && apiKey && await (await fetch(
`https://firebase.googleapis.com/v1alpha/projects/${projectId}/apps/${appId}/webConfig`,
{ headers: { "x-goog-api-key": apiKey } }
)).json();
// In Firebase App Hosting the config provided to the environment variable is up-to-date and
// "complete" we should not reach out to the webConfig endpoint to freshen it
if (process.env.X_GOOGLE_TARGET_PLATFORM === "fah") {
return configFromEnvironment;
}

if (config) {
config.apiKey = apiKey;
if (!configFromEnvironment) {
return undefined;
}
const projectId = configFromEnvironment.projectId || "-";
const appId = configFromEnvironment.appId;
const apiKey = configFromEnvironment.apiKey;
if (!appId || !apiKey) {
console.error("appId and apiKey are needed");
return undefined;
}
const response = await fetch(
`https://firebase.googleapis.com/v1alpha/projects/${projectId}/apps/${appId}/webConfig`,
{ headers: { "x-goog-api-key": apiKey } }
);
if (!response.ok) {
// TODO add sensible error
console.error("yikes.");
return undefined;
}
const json = await response.json().catch(() => {
// TODO add sensible error
console.error("also yikes.");
return undefined;
});
return { ...json, apiKey };
}

let emulatorHosts = {
const config = await getWebConfig();

const emulatorHosts = {
// TODO: remote config, functions, and data connect emulators?
firestore: process.env.FIRESTORE_EMULATOR_HOST,
database: process.env.FIREBASE_DATABASE_EMULATOR_HOST,
storage: process.env.FIREBASE_STORAGE_EMULATOR_HOST,
auth: process.env.FIREBASE_AUTH_EMULATOR_HOST,
};

if (!Object.values(emulatorHosts).filter(it => it).length) {
emulatorHosts = undefined;
}
const anyEmulatorHosts = Object.values(emulatorHosts).filter(it => it).length > 0;

const defaults = (config || emulatorHosts) && { config, emulatorHosts };
// getDefaults() will use this object, rather than fallback to other autoinit suppliers, if it's
// truthy—if we've done nothing here, make it falsy.
const defaults = (config || anyEmulatorHosts) ? { config, emulatorHosts } : undefined;

await Promise.all([
writeFile("./defaults.js", `module.exports = ${JSON.stringify(defaults)}`),
writeFile("./defaults.mjs", `export default ${JSON.stringify(defaults)}`),
writeFile(join(import.meta.dirname, "defaults.js"), `module.exports = ${JSON.stringify(defaults)}`),
writeFile(join(import.meta.dirname, "defaults.mjs"), `export default ${JSON.stringify(defaults)}`),
]);

0 comments on commit cd6d61a

Please sign in to comment.