@puls-atlas/cli
Version:
The Puls Atlas CLI tool for managing Atlas projects
95 lines • 3.85 kB
JavaScript
import fs from 'fs';
import path from 'path';
import jwt from 'jsonwebtoken';
import { selectProject } from '../../utils/firebase.js';
import { logger } from '../../utils/logger.js';
import { getSecret } from '../../utils/secrets.js';
import { normalizeOptionalString } from '../../utils/value.js';
export const DEFAULT_DEVELOPER_TOKEN_EXPIRES_IN = '12h';
export const DEVELOPER_TOKEN_FILE_MODE = 0o600;
const normalizeDeveloperTokenExpiresIn = value => normalizeOptionalString(value) ?? DEFAULT_DEVELOPER_TOKEN_EXPIRES_IN;
const normalizeDeveloperTokenOutputPath = value => normalizeOptionalString(value);
export const canPrintDeveloperTokenToStdout = stdout => stdout?.isTTY === true;
export const createDeveloperToken = (email, projectId, privateKey, options = {}) => jwt.sign({}, privateKey, {
audience: projectId,
expiresIn: normalizeDeveloperTokenExpiresIn(options.expiresIn),
issuer: projectId,
subject: email
});
export const createDeveloperTokenEnvContent = (email, token) => `REACT_APP_API_LOGIN=${email}\nREACT_APP_API_TOKEN=${token}\n`;
export const writeDeveloperTokenEnvFile = (filePath, email, token) => {
const resolvedPath = path.resolve(process.cwd(), filePath);
fs.mkdirSync(path.dirname(resolvedPath), {
recursive: true
});
fs.writeFileSync(resolvedPath, createDeveloperTokenEnvContent(email, token), {
encoding: 'utf8',
mode: DEVELOPER_TOKEN_FILE_MODE
});
fs.chmodSync(resolvedPath, DEVELOPER_TOKEN_FILE_MODE);
return resolvedPath;
};
export default async (email, options = {}, dependencies = {}) => {
const loggerImpl = dependencies.logger ?? logger;
const selectProjectImpl = dependencies.selectProject ?? selectProject;
const getSecretImpl = dependencies.getSecret ?? getSecret;
const stdout = dependencies.stdout ?? process.stdout;
const writeDeveloperTokenEnvFileImpl = dependencies.writeDeveloperTokenEnvFile ?? writeDeveloperTokenEnvFile;
const expiresIn = normalizeDeveloperTokenExpiresIn(options.expiresIn);
const writeEnvPath = normalizeDeveloperTokenOutputPath(options.writeEnv);
const spinner = loggerImpl.spinner('Generating developer token...');
try {
if (!writeEnvPath && !canPrintDeveloperTokenToStdout(stdout)) {
throw new Error('Refusing to print a developer token to non-interactive stdout. ' + 'Use --write-env <path> instead.');
}
const {
projectId
} = await selectProjectImpl('.firebaserc', {
environment: 'development'
});
const privateKey = await getSecretImpl('puls-atlas-api-key', 'latest', projectId);
const token = createDeveloperToken(email, projectId, privateKey, {
expiresIn
});
let resolvedWriteEnvPath = null;
spinner.succeed(writeEnvPath ? 'Developer token generated and saved.' : 'Developer token generated.');
loggerImpl.break();
if (writeEnvPath) {
resolvedWriteEnvPath = writeDeveloperTokenEnvFileImpl(writeEnvPath, email, token);
loggerImpl.summary('Developer token saved', [{
label: 'Path',
tone: 'accent',
value: resolvedWriteEnvPath
}, {
label: 'REACT_APP_API_LOGIN',
tone: 'accent',
value: email
}, {
label: 'Expires in',
tone: 'accent',
value: expiresIn
}]);
} else {
loggerImpl.summary('Copy paste the following into your app/.env.local file', [{
label: 'REACT_APP_API_LOGIN',
tone: 'accent',
value: email
}, {
label: 'REACT_APP_API_TOKEN',
tone: 'accent',
value: token
}]);
}
loggerImpl.break();
loggerImpl.warning(`WARNING: make sure to keep this token private. It expires in ${expiresIn}.`);
return {
expiresIn,
projectId,
token,
writeEnvPath: resolvedWriteEnvPath
};
} catch (error) {
spinner.fail(error.message);
return null;
}
};