167 lines
4.7 KiB
JavaScript
167 lines
4.7 KiB
JavaScript
/**
|
|
* Session management for saving and replaying deployments
|
|
* @module nopy.session
|
|
*/
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
/**
|
|
* Saves a session to a JSON file
|
|
*
|
|
* @param session - The session to save
|
|
* @param filePath - Path to save the session file
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* saveSession(session, './my-deployment.nopysession.json');
|
|
* ```
|
|
*/
|
|
export function saveSession(session, filePath) {
|
|
const sessionToSave = {
|
|
...session,
|
|
};
|
|
const dir = path.dirname(filePath);
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
fs.writeFileSync(filePath, JSON.stringify(sessionToSave, null, 2), 'utf-8');
|
|
}
|
|
/**
|
|
* Loads a session from an MJS file
|
|
*
|
|
* @param filePath - Path to the MJS session file
|
|
* @returns The loaded session
|
|
*/
|
|
async function loadSessionFromMJS(filePath) {
|
|
const absolutePath = path.resolve(filePath);
|
|
const fileUrl = `file://${absolutePath}`;
|
|
try {
|
|
const module = (await import(fileUrl));
|
|
const session = module.default;
|
|
if (!session) {
|
|
throw new Error('MJS file must export a default object');
|
|
}
|
|
return session;
|
|
}
|
|
catch (error) {
|
|
throw new Error(`Failed to load MJS session: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
/**
|
|
* Loads a session from a JSON file
|
|
*
|
|
* @param filePath - Path to the JSON session file
|
|
* @returns The loaded session
|
|
*/
|
|
function loadSessionFromJSON(filePath) {
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
return JSON.parse(content);
|
|
}
|
|
/**
|
|
* Loads a session from a JSON or MJS file
|
|
*
|
|
* @param filePath - Path to the session file (.json or .mjs)
|
|
* @returns The loaded session
|
|
* @throws Error if file not found or invalid format
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const session = await loadSession('./deployment.nopysession.json');
|
|
* ```
|
|
*/
|
|
export async function loadSession(filePath) {
|
|
if (!fs.existsSync(filePath)) {
|
|
throw new Error(`Session file not found: ${filePath}`);
|
|
}
|
|
const ext = path.extname(filePath);
|
|
let session;
|
|
if (ext === '.mjs') {
|
|
session = await loadSessionFromMJS(filePath);
|
|
}
|
|
else if (ext === '.json') {
|
|
session = loadSessionFromJSON(filePath);
|
|
}
|
|
else {
|
|
throw new Error(`Unsupported session file format: ${ext}. Use .json or .mjs`);
|
|
}
|
|
// Validate required fields
|
|
if (!session.cubes || !Array.isArray(session.cubes)) {
|
|
throw new Error('Invalid session format: missing or invalid "cubes" field');
|
|
}
|
|
if (session.hosts && !Array.isArray(session.hosts)) {
|
|
throw new Error('Invalid session format: invalid "hosts" field');
|
|
}
|
|
if (!session.auth) {
|
|
throw new Error('Invalid session format: missing "auth" field');
|
|
}
|
|
return session;
|
|
}
|
|
/**
|
|
* Lists all session files in a directory
|
|
*
|
|
* @param dirPath - Directory to search for session files
|
|
* @returns Array of session file paths
|
|
*/
|
|
export function listSessions(dirPath = process.cwd()) {
|
|
if (!fs.existsSync(dirPath)) {
|
|
return [];
|
|
}
|
|
const files = fs.readdirSync(dirPath);
|
|
return files
|
|
.filter((file) => file.endsWith('.session.json') || file.endsWith('.session.mjs'))
|
|
.map((file) => path.join(dirPath, file));
|
|
}
|
|
/**
|
|
* Creates a session object from runtime data
|
|
*
|
|
* @param params - Session parameters
|
|
* @returns A NopySession object
|
|
*/
|
|
export function createSession(params) {
|
|
return {
|
|
name: params.name,
|
|
cubes: params.cubes,
|
|
hosts: params.hosts,
|
|
auth: params.auth,
|
|
env: params.env,
|
|
};
|
|
}
|
|
/**
|
|
* Filters out internal variables from cube variables
|
|
*
|
|
* Internal variables are those used by the prompts system
|
|
* and should not be saved in session files.
|
|
*
|
|
* @param variables - Variables object
|
|
* @returns Filtered variables without internal keys
|
|
*/
|
|
export function filterInternalVariables(variables) {
|
|
const internalKeys = ['customize'];
|
|
const filtered = {};
|
|
for (const [key, value] of Object.entries(variables)) {
|
|
if (!internalKeys.includes(key)) {
|
|
filtered[key] = value;
|
|
}
|
|
}
|
|
return filtered;
|
|
}
|
|
/**
|
|
* Separates environment variables from cube-specific variables
|
|
*
|
|
* @param allVariables - All variables including env and cube-specific
|
|
* @param envVariables - Known environment variables from config
|
|
* @returns Object with separate env and cube variables
|
|
*/
|
|
export function separateEnvAndCubeVariables(allVariables, envVariables) {
|
|
const env = {};
|
|
const cubeVars = {};
|
|
for (const [key, value] of Object.entries(allVariables)) {
|
|
if (key in envVariables) {
|
|
env[key] = value;
|
|
}
|
|
else {
|
|
cubeVars[key] = value;
|
|
}
|
|
}
|
|
return { env, cubeVars };
|
|
}
|