@iexec/iapp
Version:
A CLI to guide you through the process of building an iExec iApp
106 lines (95 loc) • 3.06 kB
text/typescript
import { readFile, writeFile } from 'node:fs/promises';
import { z } from 'zod';
import { fromError } from 'zod-validation-error';
import {
CHAINS_CONFIGURATIONS,
CONFIG_FILE,
DEFAULT_CHAIN,
LEGACY_TEMPLATE_NAMES,
SUPPORTED_CHAINS,
TEMPLATES,
} from '../config/config.js';
type IAppConfig = {
defaultChain: string;
projectName?: string;
template?: string;
dockerhubUsername?: string;
dockerhubAccessToken?: string;
walletPrivateKey?: string;
walletFileName?: string;
appSecret?: string | null;
};
const chainNameSchema = z.enum(SUPPORTED_CHAINS as [string, ...[string]]);
export const projectNameSchema = z
.string()
.min(2, 'Must contain at least 2 characters') // docker image name constraint
.refine(
(value) => !/(^\s)|(\s$)/.test(value),
'Should not start or end with space'
)
.refine(
(value) => /^[a-zA-Z0-9- ]+$/.test(value ?? ''),
'Only letters, numbers, spaces, and hyphens are allowed'
);
const dockerImageNameSchema = z
.string()
.refine(
(value) => /^[a-z0-9-]+$/.test(value ?? ''),
'Invalid docker image name'
);
const jsonConfigFileSchema = z.object({
defaultChain: chainNameSchema.default(DEFAULT_CHAIN),
projectName: projectNameSchema,
template: z
.enum(
Object.keys(TEMPLATES).concat(LEGACY_TEMPLATE_NAMES) as [
string,
...[string],
]
)
.default('JavaScript'),
dockerhubUsername: z.string().optional(),
dockerhubAccessToken: z.string().optional(),
walletPrivateKey: z.string().optional(),
walletFileName: z.string().optional(),
appSecret: z.string().optional().nullable(), // can be null or string (null means do no use secret)
});
// transform the projectName into a suitable docker image name (no space, lowercase only)
export function projectNameToImageName(projectName = '') {
const imageName = projectName.toLowerCase().replaceAll(' ', '-');
return dockerImageNameSchema.parse(imageName);
}
// Read JSON configuration file
export async function readIAppConfig(): Promise<IAppConfig> {
const configContent = await readFile(CONFIG_FILE, 'utf8').catch(() => {
throw Error(
`Failed to read \`${CONFIG_FILE}\` file. Are you in your iApp project folder?`
);
});
let configAsObject;
try {
configAsObject = JSON.parse(configContent);
} catch {
throw Error(
`Failed to read \`${CONFIG_FILE}\` file, JSON seems to be invalid.`
);
}
try {
return jsonConfigFileSchema.parse(configAsObject);
} catch (err) {
const validationError = fromError(err);
const errorMessage = `Failed to read \`${CONFIG_FILE}\` file: ${validationError.toString()}`;
throw Error(errorMessage);
}
}
// Utility function to write the iApp JSON configuration file
export async function writeIAppConfig(config: IAppConfig) {
await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
}
export function getChainConfig(name: string) {
const conf = CHAINS_CONFIGURATIONS[name];
if (!conf) {
throw Error(`Unsupported chain ${name}`);
}
return { name, ...conf };
}