commandkit 0.1.6 โ 0.1.7-dev.20231212150647
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -9
- package/bin/build.mjs +86 -0
- package/bin/common.mjs +102 -0
- package/bin/development.mjs +163 -0
- package/bin/index.mjs +39 -0
- package/bin/parse-env.mjs +61 -0
- package/bin/production.mjs +83 -0
- package/dist/index.d.mts +288 -67
- package/dist/index.d.ts +288 -67
- package/dist/index.js +290 -128
- package/dist/index.mjs +289 -126
- package/package.json +56 -47
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/underctrl-io/commandkit/master/apps/docs/public/ckit_logo.
|
|
2
|
+
<img src="https://raw.githubusercontent.com/underctrl-io/commandkit/master/apps/docs/public/ckit_logo.svg" width="60%" />
|
|
3
3
|
<br />
|
|
4
4
|
<a href="https://ctrl.lol/discord"><img src="https://img.shields.io/discord/1055188344188973066?color=5865F2&logo=discord&logoColor=white" alt="support server" /></a>
|
|
5
5
|
<a href="https://www.npmjs.com/package/commandkit"><img src="https://img.shields.io/npm/v/commandkit?maxAge=3600" alt="npm version" /></a>
|
|
@@ -14,12 +14,12 @@ CommandKit is a library that makes it easy to handle commands and events in your
|
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
17
|
+
- Beginner friendly ๐
|
|
18
|
+
- Slash + context menu commands support โ
|
|
19
|
+
- Multiple dev guilds, users, & roles support ๐ค
|
|
20
|
+
- Automatic command updates ๐ค
|
|
21
|
+
- REST registration behaviour ๐
|
|
22
|
+
- And much more! ๐งช
|
|
23
23
|
|
|
24
24
|
## Documentation
|
|
25
25
|
|
|
@@ -99,8 +99,11 @@ new CommandKit({
|
|
|
99
99
|
// Array of developer role IDs (used for devOnly commands)
|
|
100
100
|
devRoleIds: ['1234567890', '0987654321'],
|
|
101
101
|
|
|
102
|
-
//
|
|
102
|
+
// Disable CommandKit's built-in validations
|
|
103
103
|
skipBuiltInValidations: true,
|
|
104
|
+
|
|
105
|
+
// Update command registration/reload behaviour to register all commands at once
|
|
106
|
+
bulkRegister: true,
|
|
104
107
|
});
|
|
105
108
|
|
|
106
109
|
client.login('YOUR_TOKEN_HERE');
|
|
@@ -108,4 +111,4 @@ client.login('YOUR_TOKEN_HERE');
|
|
|
108
111
|
|
|
109
112
|
## Support and Suggestions
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
Submit any queries or suggestions in our [Discord community](https://ctrl.lol/discord).
|
package/bin/build.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { appendFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { build } from 'tsup';
|
|
6
|
+
import { Colors, erase, findCommandKitConfig, panic, write } from './common.mjs';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
|
|
9
|
+
export async function bootstrapProductionBuild(config) {
|
|
10
|
+
const {
|
|
11
|
+
sourcemap = false,
|
|
12
|
+
minify = false,
|
|
13
|
+
outDir = 'dist',
|
|
14
|
+
antiCrash = true,
|
|
15
|
+
src,
|
|
16
|
+
main,
|
|
17
|
+
} = await findCommandKitConfig(config);
|
|
18
|
+
|
|
19
|
+
const status = ora('Creating optimized production build...\n').start();
|
|
20
|
+
const start = performance.now();
|
|
21
|
+
|
|
22
|
+
erase(outDir);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await build({
|
|
26
|
+
clean: true,
|
|
27
|
+
format: ['esm'],
|
|
28
|
+
dts: false,
|
|
29
|
+
skipNodeModulesBundle: true,
|
|
30
|
+
minify,
|
|
31
|
+
shims: true,
|
|
32
|
+
banner: {
|
|
33
|
+
js: '/* Optimized production build generated by CommandKit */',
|
|
34
|
+
},
|
|
35
|
+
sourcemap,
|
|
36
|
+
keepNames: true,
|
|
37
|
+
outDir,
|
|
38
|
+
silent: true,
|
|
39
|
+
entry: [src, '!dist', '!.commandkit', `!${outDir}`],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await injectShims(outDir, main, antiCrash);
|
|
43
|
+
|
|
44
|
+
status.succeed(
|
|
45
|
+
Colors.green(`Build completed in ${(performance.now() - start).toFixed(2)}ms!`),
|
|
46
|
+
);
|
|
47
|
+
write(
|
|
48
|
+
Colors.green(
|
|
49
|
+
`\nRun ${Colors.magenta(`commandkit start`)} ${Colors.green('to start your bot.')}`,
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
} catch (e) {
|
|
53
|
+
status.fail(`Build failed after ${(performance.now() - start).toFixed(2)}ms!`);
|
|
54
|
+
panic(e);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function injectShims(outDir, main, antiCrash) {
|
|
59
|
+
const path = join(process.cwd(), outDir, main);
|
|
60
|
+
|
|
61
|
+
const antiCrashScript = antiCrash
|
|
62
|
+
? [
|
|
63
|
+
'\n\n// --- CommandKit Anti-Crash Monitor ---',
|
|
64
|
+
';(()=>{',
|
|
65
|
+
" 'use strict';",
|
|
66
|
+
" // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process",
|
|
67
|
+
' // instead of using it as a means to resume operation.',
|
|
68
|
+
' // But it exists here due to compatibility reasons with discord bot ecosystem.',
|
|
69
|
+
" const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';",
|
|
70
|
+
' if (!process.eventNames().includes(e1)) // skip if it is already handled',
|
|
71
|
+
' process.on(e1, (e) => {',
|
|
72
|
+
' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));',
|
|
73
|
+
' })',
|
|
74
|
+
' if (!process.eventNames().includes(e2)) // skip if it is already handled',
|
|
75
|
+
' process.on(e2, (r) => {',
|
|
76
|
+
' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));',
|
|
77
|
+
' });',
|
|
78
|
+
'})();',
|
|
79
|
+
'// --- CommandKit Anti-Crash Monitor ---\n',
|
|
80
|
+
].join('\n')
|
|
81
|
+
: '';
|
|
82
|
+
|
|
83
|
+
const finalScript = [antiCrashScript].join('\n');
|
|
84
|
+
|
|
85
|
+
return appendFile(path, finalScript);
|
|
86
|
+
}
|
package/bin/common.mjs
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { rimrafSync } from 'rimraf';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const resetColor = '\x1b[0m';
|
|
8
|
+
|
|
9
|
+
export const Colors = {
|
|
10
|
+
reset: (text) => `${text}${resetColor}`,
|
|
11
|
+
bright: (text) => `\x1b[1m${text}${resetColor}`,
|
|
12
|
+
dim: (text) => `\x1b[2m${text}${resetColor}`,
|
|
13
|
+
underscore: (text) => `\x1b[4m${text}${resetColor}`,
|
|
14
|
+
blink: (text) => `\x1b[5m${text}${resetColor}`,
|
|
15
|
+
reverse: (text) => `\x1b[7m${text}${resetColor}`,
|
|
16
|
+
hidden: (text) => `\x1b[8m${text}${resetColor}`,
|
|
17
|
+
|
|
18
|
+
black: (text) => `\x1b[30m${text}${resetColor}`,
|
|
19
|
+
red: (text) => `\x1b[31m${text}${resetColor}`,
|
|
20
|
+
green: (text) => `\x1b[32m${text}${resetColor}`,
|
|
21
|
+
yellow: (text) => `\x1b[33m${text}${resetColor}`,
|
|
22
|
+
blue: (text) => `\x1b[34m${text}${resetColor}`,
|
|
23
|
+
magenta: (text) => `\x1b[35m${text}${resetColor}`,
|
|
24
|
+
cyan: (text) => `\x1b[36m${text}${resetColor}`,
|
|
25
|
+
white: (text) => `\x1b[37m${text}${resetColor}`,
|
|
26
|
+
|
|
27
|
+
bgBlack: (text) => `\x1b[40m${text}${resetColor}`,
|
|
28
|
+
bgRed: (text) => `\x1b[41m${text}${resetColor}`,
|
|
29
|
+
bgGreen: (text) => `\x1b[42m${text}${resetColor}`,
|
|
30
|
+
bgYellow: (text) => `\x1b[43m${text}${resetColor}`,
|
|
31
|
+
bgBlue: (text) => `\x1b[44m${text}${resetColor}`,
|
|
32
|
+
bgMagenta: (text) => `\x1b[45m${text}${resetColor}`,
|
|
33
|
+
bgCyan: (text) => `\x1b[46m${text}${resetColor}`,
|
|
34
|
+
bgWhite: (text) => `\x1b[47m${text}${resetColor}`,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function write(message) {
|
|
38
|
+
process.stdout.write(message);
|
|
39
|
+
process.stdout.write('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @returns {never}
|
|
44
|
+
*/
|
|
45
|
+
export function panic(message) {
|
|
46
|
+
write(Colors.red(`Error: ${message}`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function findPackageJSON() {
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const target = join(cwd, 'package.json');
|
|
53
|
+
|
|
54
|
+
if (!fs.existsSync(target)) {
|
|
55
|
+
panic('Could not find package.json in current directory.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return JSON.parse(fs.readFileSync(target, 'utf8'));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const possibleFileNames = [
|
|
62
|
+
'commandkit.json',
|
|
63
|
+
'commandkit.config.json',
|
|
64
|
+
'commandkit.js',
|
|
65
|
+
'commandkit.config.js',
|
|
66
|
+
'commandkit.mjs',
|
|
67
|
+
'commandkit.config.mjs',
|
|
68
|
+
'commandkit.cjs',
|
|
69
|
+
'commandkit.config.cjs',
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
export async function findCommandKitConfig(src) {
|
|
73
|
+
const cwd = process.cwd();
|
|
74
|
+
const locations = src ? [join(cwd, src)] : possibleFileNames.map((name) => join(cwd, name));
|
|
75
|
+
|
|
76
|
+
for (const location of locations) {
|
|
77
|
+
try {
|
|
78
|
+
return await loadConfigInner(location);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
panic('Could not locate commandkit config.');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function loadConfigInner(target) {
|
|
88
|
+
const isJSON = target.endsWith('.json');
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @type {import('..').CommandKitConfig}
|
|
92
|
+
*/
|
|
93
|
+
const config = await import(`file://${target}`, {
|
|
94
|
+
assert: isJSON ? { type: 'json' } : undefined,
|
|
95
|
+
}).then((conf) => conf.default || conf);
|
|
96
|
+
|
|
97
|
+
return config;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function erase(dir) {
|
|
101
|
+
rimrafSync(dir);
|
|
102
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { config as dotenv } from 'dotenv';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { build } from 'tsup';
|
|
5
|
+
import { Colors, erase, findCommandKitConfig, panic, write } from './common.mjs';
|
|
6
|
+
import { parseEnv } from './parse-env.mjs';
|
|
7
|
+
import child_process from 'node:child_process';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
|
|
10
|
+
const RESTARTING_MSG_PATTERN = /^Restarting '|".+'|"\n?$/;
|
|
11
|
+
const FAILED_RUNNING_PATTERN = /^Failed running '.+'|"\n?$/;
|
|
12
|
+
|
|
13
|
+
export async function bootstrapDevelopmentServer(opts) {
|
|
14
|
+
const {
|
|
15
|
+
src,
|
|
16
|
+
main,
|
|
17
|
+
watch = Boolean(opts.noWatch),
|
|
18
|
+
nodeOptions = [],
|
|
19
|
+
envExtra = true,
|
|
20
|
+
clearRestartLogs = true,
|
|
21
|
+
outDir,
|
|
22
|
+
} = await findCommandKitConfig(opts.config);
|
|
23
|
+
|
|
24
|
+
if (!src) {
|
|
25
|
+
panic('Could not find src in commandkit.json');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!main) {
|
|
29
|
+
panic('Could not find main in commandkit.json');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const watchMode = watch;
|
|
33
|
+
const status = ora(Colors.green('Starting a development server...\n')).start();
|
|
34
|
+
const start = performance.now();
|
|
35
|
+
|
|
36
|
+
if (watchMode && !nodeOptions.includes('--watch')) {
|
|
37
|
+
nodeOptions.push('--watch');
|
|
38
|
+
} else if (!watchMode && nodeOptions.includes('--watch')) {
|
|
39
|
+
nodeOptions.splice(nodeOptions.indexOf('--watch'), 1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!nodeOptions.includes('--enable-source-maps')) {
|
|
43
|
+
nodeOptions.push('--enable-source-maps');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
erase('.commandkit');
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await build({
|
|
50
|
+
clean: true,
|
|
51
|
+
format: ['esm'],
|
|
52
|
+
dts: false,
|
|
53
|
+
skipNodeModulesBundle: true,
|
|
54
|
+
minify: false,
|
|
55
|
+
shims: true,
|
|
56
|
+
sourcemap: 'inline',
|
|
57
|
+
keepNames: true,
|
|
58
|
+
outDir: '.commandkit',
|
|
59
|
+
silent: true,
|
|
60
|
+
entry: [src, '!dist', '!.commandkit', `!${outDir}`].filter(Boolean),
|
|
61
|
+
watch: watchMode,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
status.succeed(
|
|
65
|
+
Colors.green(`Dev server started in ${(performance.now() - start).toFixed(2)}ms!\n`),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (watchMode) write(Colors.cyan('Watching for file changes...\n'));
|
|
69
|
+
|
|
70
|
+
const processEnv = {};
|
|
71
|
+
|
|
72
|
+
const env = dotenv({
|
|
73
|
+
path: join(process.cwd(), '.env'),
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
processEnv,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (envExtra) {
|
|
79
|
+
parseEnv(processEnv);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (env.error) {
|
|
83
|
+
write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (env.parsed) {
|
|
87
|
+
write(Colors.blue('[DOTENV] Loaded .env file!'));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @type {child_process.ChildProcessWithoutNullStreams}
|
|
92
|
+
*/
|
|
93
|
+
const ps = child_process.spawn(
|
|
94
|
+
'node',
|
|
95
|
+
[...nodeOptions, join(process.cwd(), '.commandkit', main)],
|
|
96
|
+
{
|
|
97
|
+
env: {
|
|
98
|
+
...process.env,
|
|
99
|
+
...processEnv,
|
|
100
|
+
NODE_ENV: 'development',
|
|
101
|
+
// @ts-expect-error
|
|
102
|
+
COMMANDKIT_DEV: true,
|
|
103
|
+
// @ts-expect-error
|
|
104
|
+
COMMANDKIT_PRODUCTION: false,
|
|
105
|
+
},
|
|
106
|
+
cwd: process.cwd(),
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
let isLastLogRestarting = false,
|
|
111
|
+
hasStarted = false;
|
|
112
|
+
|
|
113
|
+
ps.stdout.on('data', (data) => {
|
|
114
|
+
const message = data.toString();
|
|
115
|
+
|
|
116
|
+
if (FAILED_RUNNING_PATTERN.test(message)) {
|
|
117
|
+
write(Colors.cyan('Failed running the bot, waiting for changes...'));
|
|
118
|
+
isLastLogRestarting = false;
|
|
119
|
+
if (!hasStarted) hasStarted = true;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (clearRestartLogs && !RESTARTING_MSG_PATTERN.test(message)) {
|
|
124
|
+
write(message);
|
|
125
|
+
isLastLogRestarting = false;
|
|
126
|
+
} else {
|
|
127
|
+
if (isLastLogRestarting || !hasStarted) {
|
|
128
|
+
if (!hasStarted) hasStarted = true;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
write(Colors.cyan('โ Restarting the bot...'));
|
|
132
|
+
isLastLogRestarting = true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!hasStarted) hasStarted = true;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
ps.stderr.on('data', (data) => {
|
|
139
|
+
const message = data.toString();
|
|
140
|
+
|
|
141
|
+
if (
|
|
142
|
+
message.includes(
|
|
143
|
+
'ExperimentalWarning: Watch mode is an experimental feature and might change at any time',
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
return;
|
|
147
|
+
|
|
148
|
+
write(Colors.red(message));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
ps.on('close', (code) => {
|
|
152
|
+
write('\n');
|
|
153
|
+
process.exit(code ?? 0);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
ps.on('error', (err) => {
|
|
157
|
+
panic(err);
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
status.fail(`Error occurred after ${(performance.now() - start).toFixed(2)}ms!\n`);
|
|
161
|
+
panic(e.stack ?? e);
|
|
162
|
+
}
|
|
163
|
+
}
|
package/bin/index.mjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// @ts-check
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { bootstrapDevelopmentServer } from './development.mjs';
|
|
7
|
+
import { bootstrapProductionServer } from './production.mjs';
|
|
8
|
+
import { bootstrapProductionBuild } from './build.mjs';
|
|
9
|
+
|
|
10
|
+
const program = new Command('commandkit');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.command('dev')
|
|
14
|
+
.description('Start your bot in development mode.')
|
|
15
|
+
.option('-c, --config <path>', 'Path to your commandkit config file.', './commandkit.js')
|
|
16
|
+
.action(() => {
|
|
17
|
+
const options = program.opts();
|
|
18
|
+
bootstrapDevelopmentServer(options);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command('start')
|
|
23
|
+
.description('Start your bot in production mode after running the build command.')
|
|
24
|
+
.option('-c, --config <path>', 'Path to your commandkit.json file.', './commandkit.js')
|
|
25
|
+
.action(() => {
|
|
26
|
+
const options = program.opts();
|
|
27
|
+
bootstrapProductionServer(options.config);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
program
|
|
31
|
+
.command('build')
|
|
32
|
+
.description('Build your project for production usage.')
|
|
33
|
+
.option('-c, --config <path>', 'Path to your commandkit.json file.', './commandkit.json')
|
|
34
|
+
.action(() => {
|
|
35
|
+
const options = program.opts();
|
|
36
|
+
bootstrapProductionBuild(options.config);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program.parse();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
|
|
5
|
+
const valuesMap = {
|
|
6
|
+
true: true,
|
|
7
|
+
false: false,
|
|
8
|
+
null: null,
|
|
9
|
+
undefined: undefined,
|
|
10
|
+
__UUIDv4__: () => randomUUID(),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const VALUE_PREFIXES = {
|
|
14
|
+
JSON: 'JSON::',
|
|
15
|
+
DATE: 'DATE::',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function catcher(fn) {
|
|
19
|
+
try {
|
|
20
|
+
fn();
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function parseEnv(src) {
|
|
28
|
+
for (const key in src) {
|
|
29
|
+
const value = src[key];
|
|
30
|
+
|
|
31
|
+
if (typeof value !== 'string') continue;
|
|
32
|
+
|
|
33
|
+
if (value.startsWith(VALUE_PREFIXES.JSON)) {
|
|
34
|
+
catcher(() => (src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, ''))));
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (value.startsWith(VALUE_PREFIXES.DATE)) {
|
|
39
|
+
src[key] = new Date(value.replace(VALUE_PREFIXES.DATE, ''));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (value.includes(',')) {
|
|
44
|
+
src[key] = value.split(',').map((v) => v.trim());
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (/^[0-9]+n$/.test(value)) {
|
|
49
|
+
src[key] = BigInt(value);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (value in valuesMap) {
|
|
54
|
+
src[key] =
|
|
55
|
+
typeof valuesMap[value] === 'function' ? valuesMap[value]() : valuesMap[value];
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return src;
|
|
61
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { config as dotenv } from 'dotenv';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { Colors, findCommandKitConfig, panic, write } from './common.mjs';
|
|
6
|
+
import { parseEnv } from './parse-env.mjs';
|
|
7
|
+
import child_process from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
export async function bootstrapProductionServer(config) {
|
|
10
|
+
const {
|
|
11
|
+
main,
|
|
12
|
+
outDir = 'dist',
|
|
13
|
+
envExtra = true,
|
|
14
|
+
sourcemap,
|
|
15
|
+
} = await findCommandKitConfig(config);
|
|
16
|
+
|
|
17
|
+
if (!existsSync(join(process.cwd(), outDir, main))) {
|
|
18
|
+
panic('Could not find production build, maybe run `commandkit build` first?');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const processEnv = {};
|
|
23
|
+
|
|
24
|
+
const env = dotenv({
|
|
25
|
+
path: join(process.cwd(), '.env'),
|
|
26
|
+
// @ts-expect-error
|
|
27
|
+
processEnv,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (envExtra) {
|
|
31
|
+
parseEnv(processEnv);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (env.error) {
|
|
35
|
+
write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (env.parsed) {
|
|
39
|
+
write(Colors.blue('[DOTENV] Loaded .env file!'));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @type {child_process.ChildProcessWithoutNullStreams}
|
|
44
|
+
*/
|
|
45
|
+
const ps = child_process.spawn(
|
|
46
|
+
'node',
|
|
47
|
+
[sourcemap ? '--enable-source-maps' : '', join(process.cwd(), outDir, main)].filter(
|
|
48
|
+
Boolean,
|
|
49
|
+
),
|
|
50
|
+
{
|
|
51
|
+
env: {
|
|
52
|
+
...process.env,
|
|
53
|
+
...processEnv,
|
|
54
|
+
NODE_ENV: 'production',
|
|
55
|
+
// @ts-expect-error
|
|
56
|
+
COMMANDKIT_DEV: false,
|
|
57
|
+
// @ts-expect-error
|
|
58
|
+
COMMANDKIT_PROD: true,
|
|
59
|
+
},
|
|
60
|
+
cwd: process.cwd(),
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
ps.stdout.on('data', (data) => {
|
|
65
|
+
write(data.toString());
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
ps.stderr.on('data', (data) => {
|
|
69
|
+
write(Colors.red(data.toString()));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
ps.on('close', (code) => {
|
|
73
|
+
write('\n');
|
|
74
|
+
process.exit(code ?? 0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
ps.on('error', (err) => {
|
|
78
|
+
panic(err);
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
panic(e);
|
|
82
|
+
}
|
|
83
|
+
}
|