0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(cli): init

This commit is contained in:
Olyno 2022-09-27 11:15:01 +08:00 committed by Gao Sun
parent 44d9177161
commit 0c6462dbda
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
4 changed files with 187 additions and 0 deletions

View file

@ -0,0 +1,51 @@
{
"name": "create-logto",
"version": "1.0.0",
"description": "Logto creation to getting started.",
"author": "Silverhand Inc. <contact@silverhand.io>",
"homepage": "https://github.com/logto-io/logto#readme",
"license": "MPL-2.0",
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/logto-io/logto.git"
},
"bin": "./lib/index.js",
"scripts": {
"precommit": "lint-staged",
"build": "rimraf lib && tsc",
"dev": "tsc --watch --preserveWatchOutput --incremental",
"lint": "eslint --ext .ts src",
"lint:report": "pnpm lint --format json --output-file report.json",
"prepack": "pnpm build"
},
"engines": {
"node": "^16.0.0"
},
"bugs": {
"url": "https://github.com/logto-io/logto/issues"
},
"dependencies": {
"axios": "^0.27.2",
"decompress": "^4.2.1",
"prompts": "^2.4.2"
},
"devDependencies": {
"@silverhand/eslint-config": "1.0.0",
"@silverhand/ts-config": "1.0.0",
"@types/axios": "^0.14.0",
"@types/decompress": "^4.2.4",
"@types/prompts": "^2.0.14",
"eslint": "^8.21.0",
"lint-staged": "^13.0.0",
"prettier": "^2.7.1",
"rimraf": "^3.0.2",
"typescript": "^4.7.4"
},
"eslintConfig": {
"extends": "@silverhand"
},
"prettier": "@silverhand/eslint-config/.prettierrc"
}

View file

@ -0,0 +1,31 @@
import { execSync } from 'child_process';
import { createWriteStream } from 'fs';
import axios from 'axios';
export const isVersionGreaterThan = (version: string, targetMajor: number) =>
Number(version.split('.')[0]) >= targetMajor;
export const trimV = (version: string) => (version.startsWith('v') ? version.slice(1) : version);
export const safeExecSync = (command: string) => {
try {
return execSync(command, { encoding: 'utf8', stdio: 'pipe' });
} catch {}
};
export const downloadFile = async (url: string, destination: string) => {
const file = createWriteStream(destination);
const response = await axios.get(url, { responseType: 'stream' });
response.data.pipe(file);
return new Promise((resolve, reject) => {
file.on('error', (error) => {
reject(error.message);
});
file.on('finish', () => {
file.close();
resolve(file);
});
});
};

View file

@ -0,0 +1,95 @@
import { execSync } from 'child_process';
import { existsSync } from 'fs';
import { unlink } from 'fs/promises';
import path from 'path';
import decompress from 'decompress';
import prompt from 'prompts';
import { downloadFile, isVersionGreaterThan, safeExecSync, trimV } from './functions';
const DIRECTORY = 'logto';
const NODE_MAJOR_VERSION = 16;
const POSTGRES_MAJOR_VERSION = 14;
async function main() {
const nodeVersion = execSync('node -v', { encoding: 'utf8', stdio: 'pipe' });
const pgOutput = safeExecSync('postgres --version') ?? '';
const pgArray = pgOutput.split(' ');
const pgVersion = pgArray[pgArray.length - 1]!;
if (!isVersionGreaterThan(trimV(nodeVersion), NODE_MAJOR_VERSION)) {
throw new Error(`Logto requires NodeJS >= ${NODE_MAJOR_VERSION}.0.0.`);
}
let response;
try {
response = await prompt(
[
{
name: 'instancePath',
message: 'Where should we create your logto instance?',
type: 'text',
initial: './' + DIRECTORY,
format: (value: string) => path.resolve(value.trim()),
validate: (value: string) =>
existsSync(value) ? 'That path already exists, please try another.' : true,
},
{
name: 'hasPostgresUrl',
message: `Logto requires PostgreSQL >= ${POSTGRES_MAJOR_VERSION}.0.0 but cannot find in the current environment. Do you have a remote PostgreSQL instance ready?`,
type: !isVersionGreaterThan(trimV(pgVersion), POSTGRES_MAJOR_VERSION) ? 'confirm' : null,
initial: true,
},
{
name: 'postgresUrl',
message: 'What is the URL of your PostgreSQL instance?',
type: (_, data) => (data.hasPostgresUrl ? 'text' : null),
format: (value: string) => value.trim(),
validate: (value: string) =>
(value &&
Boolean(
/^(?:([^\s#/:?]+):\/{2})?(?:([^\s#/?@]+)@)?([^\s#/?]+)?(?:\/([^\s#?]*))?(?:\?([^\s#]+))?\S*$/.test(
value
)
)) ||
'Please enter a valid connection URL.',
},
{
name: 'startInstance',
message: 'Would you like to start Logto now?',
type: 'confirm',
initial: true,
},
],
{
onCancel: () => {
throw new Error('Operation cancelled');
},
}
);
} catch (error: any) {
console.log(error.message);
return;
}
const startCommand = `cd ${response.instancePath} && npm start`;
const tarFileLocation = path.resolve('./logto.tar.gz');
await downloadFile(
'https://github.com/logto-io/logto/releases/latest/download/logto.tar.gz',
tarFileLocation
);
await decompress(tarFileLocation, response.instancePath);
await unlink(tarFileLocation);
if (response.startInstance) {
execSync(startCommand, { stdio: 'inherit' });
} else {
console.log(`You can use ${startCommand} to start Logto. Happy hacking!`);
}
}
main();

View file

@ -0,0 +1,10 @@
{
"extends": "@silverhand/ts-config/tsconfig.base",
"compilerOptions": {
"outDir": "lib",
"declaration": true
},
"include": [
"src"
]
}