@lark-apaas/coding-template-nestjs-react-fullstack 0.1.36-alpha.20260904132704 → 0.1.36-alpha.20260904234124

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-template-nestjs-react-fullstack",
3
- "version": "0.1.36-alpha.20260904132704",
3
+ "version": "0.1.36-alpha.20260904234124",
4
4
  "description": "NestJS + React fullstack template for miaoda coding",
5
5
  "type": "module",
6
6
  "files": [
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "scripts": {
12
12
  "dev": "./scripts/dev.sh",
13
- "dev:server": "NODE_ENV=development nest start --watch",
13
+ "dev:server": "NODE_ENV=development node scripts/nest-type-check.cjs",
14
14
  "dev:client": "NODE_ENV=development vite --config vite.config.ts",
15
15
  "gen:db-schema": "npx -y @lark-apaas/db-schema-sync@latest --output server/database/schema.ts --export-custom-types",
16
16
  "gen:openapi": "echo 'UNSUPPORTED, SKIP'",
@@ -5,7 +5,6 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
  const { spawn, execSync } = require('child_process');
7
7
  const readline = require('readline');
8
- const { buildNestServerArgs } = require('./nest-type-check.cjs');
9
8
 
10
9
  // ── Project root ──────────────────────────────────────────────────────────────
11
10
  const PROJECT_ROOT = path.resolve(__dirname, '..');
@@ -32,10 +31,9 @@ loadEnv();
32
31
 
33
32
  // ── Configuration ─────────────────────────────────────────────────────────────
34
33
  const LOG_DIR = process.env.LOG_DIR || 'logs';
35
- const MAX_RESTART_COUNT =
36
- process.env.MAX_RESTART_COUNT != null && process.env.MAX_RESTART_COUNT !== ''
37
- ? parseInt(process.env.MAX_RESTART_COUNT, 10)
38
- : Infinity;
34
+ const MAX_RESTART_COUNT = process.env.MAX_RESTART_COUNT != null && process.env.MAX_RESTART_COUNT !== ''
35
+ ? parseInt(process.env.MAX_RESTART_COUNT, 10)
36
+ : Infinity;
39
37
  const RESTART_DELAY = parseInt(process.env.RESTART_DELAY, 10) || 2;
40
38
  const MAX_DELAY = 8;
41
39
  const SERVER_PORT = process.env.SERVER_PORT || '3000';
@@ -52,37 +50,26 @@ const devLogFd = fs.openSync(devLogPath, 'a');
52
50
  function timestamp() {
53
51
  const now = new Date();
54
52
  return (
55
- now.getFullYear() +
56
- '-' +
57
- String(now.getMonth() + 1).padStart(2, '0') +
58
- '-' +
59
- String(now.getDate()).padStart(2, '0') +
60
- ' ' +
61
- String(now.getHours()).padStart(2, '0') +
62
- ':' +
63
- String(now.getMinutes()).padStart(2, '0') +
64
- ':' +
53
+ now.getFullYear() + '-' +
54
+ String(now.getMonth() + 1).padStart(2, '0') + '-' +
55
+ String(now.getDate()).padStart(2, '0') + ' ' +
56
+ String(now.getHours()).padStart(2, '0') + ':' +
57
+ String(now.getMinutes()).padStart(2, '0') + ':' +
65
58
  String(now.getSeconds()).padStart(2, '0')
66
59
  );
67
60
  }
68
61
 
69
62
  /** Write to terminal + dev.std.log */
70
63
  function writeOutput(msg) {
71
- try {
72
- process.stdout.write(msg);
73
- } catch {}
74
- try {
75
- fs.writeSync(devStdLogFd, msg);
76
- } catch {}
64
+ try { process.stdout.write(msg); } catch {}
65
+ try { fs.writeSync(devStdLogFd, msg); } catch {}
77
66
  }
78
67
 
79
68
  /** Structured event log → terminal + dev.std.log + dev.log */
80
69
  function logEvent(level, name, message) {
81
70
  const msg = `[${timestamp()}] [${level}] [${name}] ${message}\n`;
82
71
  writeOutput(msg);
83
- try {
84
- fs.writeSync(devLogFd, msg);
85
- } catch {}
72
+ try { fs.writeSync(devLogFd, msg); } catch {}
86
73
  }
87
74
 
88
75
  // ── Process group management ──────────────────────────────────────────────────
@@ -94,16 +81,11 @@ function killProcessGroup(pid, signal) {
94
81
 
95
82
  function killOrphansByPort(port) {
96
83
  try {
97
- const pids = execSync(`lsof -ti :${port}`, {
98
- encoding: 'utf8',
99
- timeout: 5000,
100
- }).trim();
84
+ const pids = execSync(`lsof -ti :${port}`, { encoding: 'utf8', timeout: 5000 }).trim();
101
85
  if (pids) {
102
86
  const pidList = pids.split('\n').filter(Boolean);
103
87
  for (const p of pidList) {
104
- try {
105
- process.kill(parseInt(p, 10), 'SIGKILL');
106
- } catch {}
88
+ try { process.kill(parseInt(p, 10), 'SIGKILL'); } catch {}
107
89
  }
108
90
  return pidList;
109
91
  }
@@ -146,23 +128,14 @@ function startProcess({ name, command, args, cleanupPort }) {
146
128
  entry.child = child;
147
129
 
148
130
  const startTime = Date.now();
149
- logEvent(
150
- 'INFO',
151
- name,
152
- `Process started (PGID: ${child.pid}): ${command} ${args.join(' ')}`,
153
- );
131
+ logEvent('INFO', name, `Process started (PGID: ${child.pid}): ${command} ${args.join(' ')}`);
154
132
 
155
133
  // Pipe stdout and stderr through readline for timestamped logging
156
134
  const pipeLines = (stream) => {
157
- const rl = readline.createInterface({
158
- input: stream,
159
- crlfDelay: Infinity,
160
- });
135
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
161
136
  rl.on('line', (line) => {
162
137
  const msg = `[${timestamp()}] [${name}] ${line}\n`;
163
- try {
164
- fs.writeSync(logFd, msg);
165
- } catch {}
138
+ try { fs.writeSync(logFd, msg); } catch {}
166
139
  writeOutput(msg);
167
140
  });
168
141
  };
@@ -191,11 +164,7 @@ function startProcess({ name, command, args, cleanupPort }) {
191
164
  if (cleanupPort) {
192
165
  const orphans = killOrphansByPort(cleanupPort);
193
166
  if (orphans.length > 0) {
194
- logEvent(
195
- 'WARN',
196
- name,
197
- `Killed orphan processes on port ${cleanupPort}: ${orphans.join(' ')}`,
198
- );
167
+ logEvent('WARN', name, `Killed orphan processes on port ${cleanupPort}: ${orphans.join(' ')}`);
199
168
  await sleep(500);
200
169
  }
201
170
  }
@@ -205,38 +174,21 @@ function startProcess({ name, command, args, cleanupPort }) {
205
174
  const runDuration = (Date.now() - startTime) / 1000;
206
175
  if (runDuration >= 60) {
207
176
  restartCount = 0;
208
- logEvent(
209
- 'INFO',
210
- name,
211
- `Ran for ${Math.round(runDuration)}s, resetting restart counter`,
212
- );
177
+ logEvent('INFO', name, `Ran for ${Math.round(runDuration)}s, resetting restart counter`);
213
178
  } else {
214
179
  restartCount++;
215
180
  }
216
181
  if (restartCount >= MAX_RESTART_COUNT) {
217
- logEvent(
218
- 'ERROR',
219
- name,
220
- `Max restart count (${MAX_RESTART_COUNT}) reached, giving up`,
221
- );
182
+ logEvent('ERROR', name, `Max restart count (${MAX_RESTART_COUNT}) reached, giving up`);
222
183
  break;
223
184
  }
224
185
 
225
- const delay = Math.min(
226
- RESTART_DELAY * (1 << Math.max(0, restartCount - 1)),
227
- MAX_DELAY,
228
- );
229
- logEvent(
230
- 'WARN',
231
- name,
232
- `Process exited with code ${exitCode}, restarting (${restartCount}/${MAX_RESTART_COUNT}) in ${delay}s...`,
233
- );
186
+ const delay = Math.min(RESTART_DELAY * (1 << Math.max(0, restartCount - 1)), MAX_DELAY);
187
+ logEvent('WARN', name, `Process exited with code ${exitCode}, restarting (${restartCount}/${MAX_RESTART_COUNT}) in ${delay}s...`);
234
188
  await sleep(delay * 1000);
235
189
  }
236
190
 
237
- try {
238
- fs.closeSync(logFd);
239
- } catch {}
191
+ try { fs.closeSync(logFd); } catch {}
240
192
  };
241
193
 
242
194
  return run();
@@ -266,11 +218,7 @@ async function cleanup() {
266
218
  // Force kill any remaining
267
219
  for (const entry of managedProcesses) {
268
220
  if (entry.pid) {
269
- logEvent(
270
- 'WARN',
271
- 'main',
272
- `Force killing process group (PGID: ${entry.pid})`,
273
- );
221
+ logEvent('WARN', 'main', `Force killing process group (PGID: ${entry.pid})`);
274
222
  killProcessGroup(entry.pid, 'SIGKILL');
275
223
  }
276
224
  }
@@ -281,12 +229,8 @@ async function cleanup() {
281
229
 
282
230
  logEvent('INFO', 'main', 'All processes stopped');
283
231
 
284
- try {
285
- fs.closeSync(devStdLogFd);
286
- } catch {}
287
- try {
288
- fs.closeSync(devLogFd);
289
- } catch {}
232
+ try { fs.closeSync(devStdLogFd); } catch {}
233
+ try { fs.closeSync(devLogFd); } catch {}
290
234
 
291
235
  process.exit(0);
292
236
  }
@@ -313,22 +257,17 @@ async function main() {
313
257
  // Initialize action plugins
314
258
  writeOutput('\n🔌 Initializing action plugins...\n');
315
259
  try {
316
- execSync('fullstack-cli action-plugin init', {
317
- cwd: PROJECT_ROOT,
318
- stdio: 'inherit',
319
- });
260
+ execSync('fullstack-cli action-plugin init', { cwd: PROJECT_ROOT, stdio: 'inherit' });
320
261
  writeOutput('✅ Action plugins initialized\n\n');
321
262
  } catch {
322
- writeOutput(
323
- '⚠️ Action plugin initialization failed, continuing anyway...\n\n',
324
- );
263
+ writeOutput('⚠️ Action plugin initialization failed, continuing anyway...\n\n');
325
264
  }
326
265
 
327
266
  // Start server and client
328
267
  const serverPromise = startProcess({
329
268
  name: 'server',
330
269
  command: 'npm',
331
- args: buildNestServerArgs({ projectRoot: PROJECT_ROOT, env: process.env }),
270
+ args: ['run', 'dev:server'],
332
271
  cleanupPort: SERVER_PORT,
333
272
  });
334
273
 
@@ -2,25 +2,26 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const { spawn } = require('child_process');
5
6
 
6
7
  const TYPE_CHECK_ENV = 'MIAODA_NEST_TYPE_CHECK_ENABLED';
7
8
  const DISABLED_CONFIG_RELATIVE_PATH = 'logs/nest-cli.type-check-disabled.json';
8
9
 
9
10
  /**
10
- * Build the npm arguments used to launch Nest in development.
11
+ * Build the Nest CLI arguments used to launch the development server.
11
12
  *
12
13
  * Missing or malformed values deliberately preserve the project's existing
13
14
  * nest-cli.json behavior. The platform injects an exact true/false value;
14
15
  * exact true forces the checker on, while exact false writes a narrow runtime
15
16
  * config override so the checked-in project config is never mutated.
16
17
  */
17
- function buildNestServerArgs({ projectRoot, env = process.env }) {
18
+ function buildNestCliArgs({ projectRoot, env = process.env }) {
18
19
  const enabled = env[TYPE_CHECK_ENV];
19
20
  if (enabled === 'true') {
20
- return ['run', 'dev:server', '--', '--type-check'];
21
+ return ['start', '--watch', '--type-check'];
21
22
  }
22
23
  if (enabled !== 'false') {
23
- return ['run', 'dev:server'];
24
+ return ['start', '--watch'];
24
25
  }
25
26
 
26
27
  const sourcePath = path.join(projectRoot, 'nest-cli.json');
@@ -47,7 +48,38 @@ function buildNestServerArgs({ projectRoot, env = process.env }) {
47
48
  );
48
49
  fs.renameSync(temporaryPath, runtimePath);
49
50
 
50
- return ['run', 'dev:server', '--', '--config', DISABLED_CONFIG_RELATIVE_PATH];
51
+ return ['start', '--watch', '--config', DISABLED_CONFIG_RELATIVE_PATH];
51
52
  }
52
53
 
53
- module.exports = { buildNestServerArgs };
54
+ function runNestServer({ projectRoot = path.resolve(__dirname, '..'), env = process.env } = {}) {
55
+ const executable = path.join(
56
+ projectRoot,
57
+ 'node_modules',
58
+ '.bin',
59
+ process.platform === 'win32' ? 'nest.cmd' : 'nest',
60
+ );
61
+ const child = spawn(executable, buildNestCliArgs({ projectRoot, env }), {
62
+ cwd: projectRoot,
63
+ env,
64
+ stdio: 'inherit',
65
+ });
66
+
67
+ child.once('error', (error) => {
68
+ console.error(`[nest-type-check] failed to start Nest CLI: ${error.message}`);
69
+ process.exitCode = 1;
70
+ });
71
+ child.once('exit', (code, signal) => {
72
+ if (signal) {
73
+ process.kill(process.pid, signal);
74
+ return;
75
+ }
76
+ process.exitCode = code ?? 1;
77
+ });
78
+ return child;
79
+ }
80
+
81
+ if (require.main === module) {
82
+ runNestServer();
83
+ }
84
+
85
+ module.exports = { buildNestCliArgs, runNestServer };