@zintrust/core 0.4.9 → 0.4.11
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 +1 -1
- package/src/boot/registry/registerRoute.d.ts +1 -1
- package/src/boot/registry/registerRoute.d.ts.map +1 -1
- package/src/boot/registry/registerRoute.js +7 -2
- package/src/cli/commands/RoutesCommand.d.ts.map +1 -1
- package/src/cli/commands/RoutesCommand.js +40 -1
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +78 -36
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +31 -15
- package/src/cli/utils/EnvFileLoader.d.ts +2 -1
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/cli/utils/EnvFileLoader.js +23 -7
- package/src/cli/utils/spawn.d.ts.map +1 -1
- package/src/cli/utils/spawn.js +11 -1
- package/src/index.js +3 -3
- package/src/microservices/ServiceManifest.d.ts +13 -0
- package/src/microservices/ServiceManifest.d.ts.map +1 -1
- package/src/microservices/ServiceManifest.js +27 -0
- package/src/runtime/OverrideValueMerge.d.ts.map +1 -1
- package/src/runtime/OverrideValueMerge.js +2 -1
- package/src/templates/project/basic/src/zintrust.runtime.ts.tpl +5 -1
- package/src/templates/project/basic/src/zintrust.runtime.wg.ts.tpl +5 -1
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type IRouter } from '../../routes/Router';
|
|
2
2
|
export declare const isCompiledJsModule: () => boolean;
|
|
3
3
|
export declare const tryImportOptional: <T>(modulePath: string) => Promise<T | undefined>;
|
|
4
4
|
export declare const tryImportOptionalR: <T>(modulePath: string) => Promise<T | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registerRoute.d.ts","sourceRoot":"","sources":["../../../../src/boot/registry/registerRoute.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"registerRoute.d.ts","sourceRoot":"","sources":["../../../../src/boot/registry/registerRoute.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAW3D,eAAO,MAAM,kBAAkB,QAAO,OAKrC,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,CAAC,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAMpF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,CAAC,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAOrF,CAAC;AA0FF,eAAO,MAAM,oBAAoB,GAC/B,kBAAkB,MAAM,EACxB,QAAQ,OAAO,KACd,OAAO,CAAC,IAAI,CAoBd,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { appConfig } from '../../config/index.js';
|
|
2
2
|
import Logger from '../../config/logger.js';
|
|
3
|
+
import { Router } from '../../routes/Router.js';
|
|
3
4
|
import { isObject } from '../../helper/index.js';
|
|
5
|
+
import { getServicePrefix } from '../../microservices/ServiceManifest.js';
|
|
4
6
|
import * as path from '../../node-singletons/path.js';
|
|
5
7
|
import { pathToFileURL } from '../../node-singletons/url.js';
|
|
6
8
|
import { detectRuntime } from '../../runtime/detectRuntime.js';
|
|
@@ -72,8 +74,11 @@ const registerManifestRoutes = async (router) => {
|
|
|
72
74
|
try {
|
|
73
75
|
// eslint-disable-next-line no-await-in-loop
|
|
74
76
|
const mod = await entry.loadRoutes();
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
const registerRoutes = isObject(mod) ? mod.registerRoutes : undefined;
|
|
78
|
+
if (typeof registerRoutes === 'function') {
|
|
79
|
+
Router.group(router, getServicePrefix(entry), (scopedRouter) => {
|
|
80
|
+
registerRoutes(scopedRouter);
|
|
81
|
+
});
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
84
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RoutesCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/RoutesCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"RoutesCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/RoutesCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA2VvF,eAAO,MAAM,aAAa;cACd,YAAY;EAatB,CAAC;AAEH,eAAe,aAAa,CAAC"}
|
|
@@ -6,6 +6,9 @@ import { BaseCommand } from '../BaseCommand.js';
|
|
|
6
6
|
import { Env } from '../../config/env.js';
|
|
7
7
|
import { Router } from '../../routes/Router.js';
|
|
8
8
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
9
|
+
import { isObject } from '../../helper/index.js';
|
|
10
|
+
import { getServicePrefix } from '../../microservices/ServiceManifest.js';
|
|
11
|
+
import { ProjectRuntime } from '../../runtime/ProjectRuntime.js';
|
|
9
12
|
const parseGroupBy = (value) => {
|
|
10
13
|
const raw = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
11
14
|
if (raw === '' || raw === 'group')
|
|
@@ -157,6 +160,40 @@ const renderTable = (rows) => {
|
|
|
157
160
|
console.log(bottom);
|
|
158
161
|
/* eslint-enable no-console */
|
|
159
162
|
};
|
|
163
|
+
const annotateManifestRoutes = (router, beforeCount, serviceId) => {
|
|
164
|
+
const routes = Router.getRoutes(router);
|
|
165
|
+
for (const route of routes.slice(beforeCount)) {
|
|
166
|
+
route.__zintrustServiceId = serviceId;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const getRouteServiceId = (route) => {
|
|
170
|
+
return route.__zintrustServiceId ?? '';
|
|
171
|
+
};
|
|
172
|
+
const registerManifestRoutes = async (router) => {
|
|
173
|
+
await ProjectRuntime.tryLoadNodeRuntime();
|
|
174
|
+
const serviceManifest = ProjectRuntime.getServiceManifest();
|
|
175
|
+
if (serviceManifest.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
for (const entry of serviceManifest) {
|
|
178
|
+
if (entry.monolithEnabled === false || typeof entry.loadRoutes !== 'function')
|
|
179
|
+
continue;
|
|
180
|
+
try {
|
|
181
|
+
const beforeCount = Router.getRoutes(router).length;
|
|
182
|
+
// eslint-disable-next-line no-await-in-loop
|
|
183
|
+
const mod = await entry.loadRoutes();
|
|
184
|
+
const registerRoutes = isObject(mod) ? mod.registerRoutes : undefined;
|
|
185
|
+
if (typeof registerRoutes === 'function') {
|
|
186
|
+
Router.group(router, getServicePrefix(entry), (scopedRouter) => {
|
|
187
|
+
registerRoutes(scopedRouter);
|
|
188
|
+
});
|
|
189
|
+
annotateManifestRoutes(router, beforeCount, entry.id);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Ignore broken optional service routes and keep listing what is available.
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
160
197
|
const buildRows = async (options) => {
|
|
161
198
|
const groupBy = parseGroupBy(options.groupBy);
|
|
162
199
|
const filterText = typeof options.filter === 'string' ? options.filter.trim().toLowerCase() : '';
|
|
@@ -174,12 +211,14 @@ const buildRows = async (options) => {
|
|
|
174
211
|
catch {
|
|
175
212
|
// routes/api.ts not found, continue with just core routes
|
|
176
213
|
}
|
|
214
|
+
await registerManifestRoutes(router);
|
|
177
215
|
const routes = Router.getRoutes(router);
|
|
178
216
|
const rows = routes.map((route) => {
|
|
179
217
|
const path = normalizePath(route.path);
|
|
218
|
+
const serviceId = getRouteServiceId(route);
|
|
180
219
|
let group = '';
|
|
181
220
|
if (groupBy === 'service') {
|
|
182
|
-
group = deriveService(path);
|
|
221
|
+
group = serviceId === '' ? deriveService(path) : serviceId;
|
|
183
222
|
}
|
|
184
223
|
else if (groupBy === 'group') {
|
|
185
224
|
group = deriveGroup(path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgtBvF,eAAO,MAAM,YAAY;cACb,YAAY;EA6BtB,CAAC"}
|
|
@@ -168,8 +168,19 @@ const resolveCacheEnabledPreference = (options) => {
|
|
|
168
168
|
return options.cache;
|
|
169
169
|
return undefined;
|
|
170
170
|
};
|
|
171
|
-
const
|
|
172
|
-
|
|
171
|
+
const findNearestPackageJsonDir = (cwd) => {
|
|
172
|
+
let current = path.resolve(cwd);
|
|
173
|
+
while (true) {
|
|
174
|
+
if (existsSync(path.join(current, 'package.json')))
|
|
175
|
+
return current;
|
|
176
|
+
const parent = path.dirname(current);
|
|
177
|
+
if (parent === current)
|
|
178
|
+
return undefined;
|
|
179
|
+
current = parent;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const readPackageJsonFromDir = (dir) => {
|
|
183
|
+
const packagePath = path.join(dir, 'package.json');
|
|
173
184
|
if (!existsSync(packagePath)) {
|
|
174
185
|
throw ErrorFactory.createCliError("Error: No ZinTrust app found. Run 'zin new <project>' or ensure package.json exists.");
|
|
175
186
|
}
|
|
@@ -181,6 +192,28 @@ const readPackageJson = (cwd) => {
|
|
|
181
192
|
throw ErrorFactory.createTryCatchError('Failed to read package.json', error);
|
|
182
193
|
}
|
|
183
194
|
};
|
|
195
|
+
const resolveStartContext = (cwd) => {
|
|
196
|
+
const projectRoot = findNearestPackageJsonDir(cwd) ?? cwd;
|
|
197
|
+
const packageDir = findNearestPackageJsonDir(cwd);
|
|
198
|
+
return {
|
|
199
|
+
cwd,
|
|
200
|
+
projectRoot,
|
|
201
|
+
...(packageDir === undefined ? {} : { packageJson: readPackageJsonFromDir(packageDir) }),
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
const requirePackageJson = (context) => {
|
|
205
|
+
if (context.packageJson !== undefined)
|
|
206
|
+
return context.packageJson;
|
|
207
|
+
throw ErrorFactory.createCliError("Error: No ZinTrust app found. Run 'zin new <project>' or ensure package.json exists.");
|
|
208
|
+
};
|
|
209
|
+
const buildStartEnv = (projectRoot) => ({
|
|
210
|
+
...process.env,
|
|
211
|
+
ZINTRUST_PROJECT_ROOT: projectRoot,
|
|
212
|
+
});
|
|
213
|
+
const ensureStartEnvLoaded = (context) => {
|
|
214
|
+
const extraCwds = context.cwd === context.projectRoot ? [] : [context.cwd];
|
|
215
|
+
EnvFileLoader.ensureLoaded({ cwd: context.projectRoot, extraCwds });
|
|
216
|
+
};
|
|
184
217
|
const isFrameworkRepo = (packageJson) => packageJson.name === '@zintrust/core';
|
|
185
218
|
const hasDevScript = (packageJson) => {
|
|
186
219
|
const scripts = packageJson.scripts;
|
|
@@ -263,14 +296,14 @@ const resolveNodeProdCommand = (cwd) => {
|
|
|
263
296
|
}
|
|
264
297
|
return { command: 'node', args: [compiled] };
|
|
265
298
|
};
|
|
266
|
-
const executeWranglerStart = async (cmd,
|
|
299
|
+
const executeWranglerStart = async (cmd, context, port, runtime, envName, wranglerConfig) => {
|
|
267
300
|
if (runtime !== undefined) {
|
|
268
301
|
throw ErrorFactory.createCliError('Error: --runtime is not supported with --wrangler (Wrangler controls Workers runtime).');
|
|
269
302
|
}
|
|
270
303
|
const normalizedConfig = typeof wranglerConfig === 'string' ? wranglerConfig.trim() : '';
|
|
271
|
-
const explicitConfigFullPath = normalizedConfig.length > 0 ? path.join(cwd, normalizedConfig) : undefined;
|
|
272
|
-
const configPath = explicitConfigFullPath ?? findWranglerConfig(cwd);
|
|
273
|
-
const entry = resolveWranglerEntry(cwd);
|
|
304
|
+
const explicitConfigFullPath = normalizedConfig.length > 0 ? path.join(context.cwd, normalizedConfig) : undefined;
|
|
305
|
+
const configPath = explicitConfigFullPath ?? findWranglerConfig(context.cwd);
|
|
306
|
+
const entry = resolveWranglerEntry(context.cwd);
|
|
274
307
|
if (explicitConfigFullPath !== undefined) {
|
|
275
308
|
if (existsSync(explicitConfigFullPath)) {
|
|
276
309
|
// ok
|
|
@@ -300,7 +333,7 @@ const executeWranglerStart = async (cmd, cwd, port, runtime, envName, wranglerCo
|
|
|
300
333
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
301
334
|
command: 'wrangler',
|
|
302
335
|
args: wranglerArgs,
|
|
303
|
-
env:
|
|
336
|
+
env: buildStartEnv(context.projectRoot),
|
|
304
337
|
});
|
|
305
338
|
process.exit(exitCode);
|
|
306
339
|
};
|
|
@@ -321,92 +354,98 @@ const ensureTmpRunnerFile = (cwd, filename, content) => {
|
|
|
321
354
|
}
|
|
322
355
|
return fullPath;
|
|
323
356
|
};
|
|
324
|
-
const executeDenoStart = async (cmd,
|
|
357
|
+
const executeDenoStart = async (cmd, context, mode, watchEnabled, _port, runtime) => {
|
|
325
358
|
if (runtime !== undefined) {
|
|
326
359
|
throw ErrorFactory.createCliError('Error: --runtime cannot be used with --deno.');
|
|
327
360
|
}
|
|
328
361
|
if (mode === 'testing') {
|
|
329
362
|
throw ErrorFactory.createCliError('Error: Cannot start server in testing mode. Use development or production.');
|
|
330
363
|
}
|
|
331
|
-
const startModuleSpecifier = resolveRuntimeStartModuleSpecifier(cwd);
|
|
332
|
-
const denoRunner = ensureTmpRunnerFile(cwd, 'zin-start-deno.ts', createDenoRunnerSource(startModuleSpecifier));
|
|
364
|
+
const startModuleSpecifier = resolveRuntimeStartModuleSpecifier(context.cwd);
|
|
365
|
+
const denoRunner = ensureTmpRunnerFile(context.cwd, 'zin-start-deno.ts', createDenoRunnerSource(startModuleSpecifier));
|
|
333
366
|
const args = [];
|
|
334
367
|
if (mode === 'development' && watchEnabled)
|
|
335
368
|
args.push('watch');
|
|
336
369
|
args.push(denoRunner);
|
|
337
370
|
cmd.info('Starting in Deno adapter mode...');
|
|
338
|
-
const exitCode = await SpawnUtil.spawnAndWait({
|
|
371
|
+
const exitCode = await SpawnUtil.spawnAndWait({
|
|
372
|
+
command: 'tsx',
|
|
373
|
+
args,
|
|
374
|
+
env: buildStartEnv(context.projectRoot),
|
|
375
|
+
});
|
|
339
376
|
process.exit(exitCode);
|
|
340
377
|
};
|
|
341
|
-
const executeLambdaStart = async (cmd,
|
|
378
|
+
const executeLambdaStart = async (cmd, context, mode, watchEnabled, _port, runtime) => {
|
|
342
379
|
if (runtime !== undefined) {
|
|
343
380
|
throw ErrorFactory.createCliError('Error: --runtime cannot be used with --lambda.');
|
|
344
381
|
}
|
|
345
382
|
if (mode === 'testing') {
|
|
346
383
|
throw ErrorFactory.createCliError('Error: Cannot start server in testing mode. Use development or production.');
|
|
347
384
|
}
|
|
348
|
-
const startModuleSpecifier = resolveRuntimeStartModuleSpecifier(cwd);
|
|
349
|
-
const lambdaRunner = ensureTmpRunnerFile(cwd, 'zin-start-lambda.ts', createLambdaRunnerSource(startModuleSpecifier));
|
|
385
|
+
const startModuleSpecifier = resolveRuntimeStartModuleSpecifier(context.cwd);
|
|
386
|
+
const lambdaRunner = ensureTmpRunnerFile(context.cwd, 'zin-start-lambda.ts', createLambdaRunnerSource(startModuleSpecifier));
|
|
350
387
|
const args = [];
|
|
351
388
|
if (mode === 'development' && watchEnabled)
|
|
352
389
|
args.push('watch');
|
|
353
390
|
args.push(lambdaRunner);
|
|
354
391
|
cmd.info('Starting in Lambda adapter mode...');
|
|
355
|
-
const exitCode = await SpawnUtil.spawnAndWait({
|
|
392
|
+
const exitCode = await SpawnUtil.spawnAndWait({
|
|
393
|
+
command: 'tsx',
|
|
394
|
+
args,
|
|
395
|
+
env: buildStartEnv(context.projectRoot),
|
|
396
|
+
});
|
|
356
397
|
process.exit(exitCode);
|
|
357
398
|
};
|
|
358
|
-
const executeNodeStart = async (cmd,
|
|
399
|
+
const executeNodeStart = async (cmd, context, mode, watchEnabled, _port) => {
|
|
359
400
|
if (mode === 'testing') {
|
|
360
401
|
throw ErrorFactory.createCliError('Error: Cannot start server in testing mode. Use --force to override (not supported).');
|
|
361
402
|
}
|
|
362
403
|
if (mode === 'development') {
|
|
363
404
|
if (!watchEnabled) {
|
|
364
405
|
cmd.warn('Watch mode disabled; starting once.');
|
|
365
|
-
const bootstrap = resolveBootstrapEntryTs(cwd);
|
|
406
|
+
const bootstrap = resolveBootstrapEntryTs(context.cwd);
|
|
366
407
|
const args = bootstrap === undefined ? ['src/index.ts'] : [bootstrap];
|
|
367
408
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
368
409
|
command: 'tsx',
|
|
369
410
|
args,
|
|
370
411
|
forwardSignals: false,
|
|
371
|
-
env:
|
|
412
|
+
env: buildStartEnv(context.projectRoot),
|
|
372
413
|
});
|
|
373
414
|
process.exit(exitCode);
|
|
374
415
|
}
|
|
375
|
-
const
|
|
376
|
-
const dev = resolveNodeDevCommand(cwd, packageJson);
|
|
416
|
+
const dev = resolveNodeDevCommand(context.cwd, requirePackageJson(context));
|
|
377
417
|
cmd.info('Starting in development mode (watch enabled)...');
|
|
378
418
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
379
419
|
command: dev.command,
|
|
380
420
|
args: dev.args,
|
|
381
421
|
forwardSignals: false,
|
|
382
|
-
env:
|
|
422
|
+
env: buildStartEnv(context.projectRoot),
|
|
383
423
|
});
|
|
384
424
|
process.exit(exitCode);
|
|
385
425
|
}
|
|
386
|
-
const prod = resolveNodeProdCommand(cwd);
|
|
426
|
+
const prod = resolveNodeProdCommand(context.cwd);
|
|
387
427
|
cmd.info('Starting in production mode...');
|
|
388
428
|
const exitCode = await SpawnUtil.spawnAndWait({
|
|
389
429
|
command: prod.command,
|
|
390
430
|
args: prod.args,
|
|
391
431
|
forwardSignals: false,
|
|
392
|
-
env:
|
|
432
|
+
env: buildStartEnv(context.projectRoot),
|
|
393
433
|
});
|
|
394
434
|
process.exit(exitCode);
|
|
395
435
|
};
|
|
396
|
-
const executeSplitStart = async (cmd,
|
|
436
|
+
const executeSplitStart = async (cmd, context, _options) => {
|
|
397
437
|
cmd.info('🚀 Starting in split mode (Producer + Consumer)...');
|
|
398
|
-
const
|
|
399
|
-
const webDev = resolveNodeDevCommand(cwd, packageJson);
|
|
438
|
+
const webDev = resolveNodeDevCommand(context.cwd, requirePackageJson(context));
|
|
400
439
|
// Producer Environment
|
|
401
440
|
const producerEnv = {
|
|
402
|
-
...
|
|
441
|
+
...buildStartEnv(context.projectRoot),
|
|
403
442
|
WORKER_ENABLED: 'false',
|
|
404
443
|
QUEUE_ENABLED: 'true',
|
|
405
444
|
RUNTIME_MODE: 'node-server',
|
|
406
445
|
};
|
|
407
446
|
// Consumer Environment
|
|
408
447
|
const consumerEnv = {
|
|
409
|
-
...
|
|
448
|
+
...buildStartEnv(context.projectRoot),
|
|
410
449
|
WORKER_ENABLED: 'true',
|
|
411
450
|
QUEUE_ENABLED: 'true',
|
|
412
451
|
RUNTIME_MODE: 'containers',
|
|
@@ -417,10 +456,10 @@ const executeSplitStart = async (cmd, cwd, _options) => {
|
|
|
417
456
|
};
|
|
418
457
|
// Resolve Consumer Command (zintrust worker:start-all)
|
|
419
458
|
// We try to use tsx against the source bin if possible
|
|
420
|
-
const workerArgs = existsSync(path.join(
|
|
459
|
+
const workerArgs = existsSync(path.join(context.projectRoot, 'bin/zin.ts'))
|
|
421
460
|
? ['bin/zin.ts', 'worker:start-all']
|
|
422
461
|
: ['dist/bin/zin.js', 'worker:start-all'];
|
|
423
|
-
const workerCommand = existsSync(path.join(
|
|
462
|
+
const workerCommand = existsSync(path.join(context.projectRoot, 'bin/zin.ts')) ? 'tsx' : 'node';
|
|
424
463
|
cmd.info('-------------------------------------------');
|
|
425
464
|
cmd.info('🔹 [Producer] Web Server starting...');
|
|
426
465
|
cmd.info('🔸 [Consumer] Worker Process starting...');
|
|
@@ -428,12 +467,14 @@ const executeSplitStart = async (cmd, cwd, _options) => {
|
|
|
428
467
|
const pProducer = SpawnUtil.spawnAndWait({
|
|
429
468
|
command: webDev.command,
|
|
430
469
|
args: webDev.args,
|
|
470
|
+
cwd: context.cwd,
|
|
431
471
|
env: producerEnv,
|
|
432
472
|
forwardSignals: true,
|
|
433
473
|
});
|
|
434
474
|
const pConsumer = SpawnUtil.spawnAndWait({
|
|
435
475
|
command: workerCommand,
|
|
436
476
|
args: workerArgs,
|
|
477
|
+
cwd: context.projectRoot,
|
|
437
478
|
env: consumerEnv,
|
|
438
479
|
forwardSignals: true,
|
|
439
480
|
});
|
|
@@ -441,7 +482,8 @@ const executeSplitStart = async (cmd, cwd, _options) => {
|
|
|
441
482
|
};
|
|
442
483
|
const executeStart = async (options, cmd) => {
|
|
443
484
|
const cwd = process.cwd();
|
|
444
|
-
|
|
485
|
+
const context = resolveStartContext(cwd);
|
|
486
|
+
ensureStartEnvLoaded(context);
|
|
445
487
|
const mode = resolveMode(options);
|
|
446
488
|
const port = resolvePort(options);
|
|
447
489
|
const runtime = resolveRuntime(options);
|
|
@@ -454,7 +496,7 @@ const executeStart = async (options, cmd) => {
|
|
|
454
496
|
if (variant === 'lambda')
|
|
455
497
|
effectiveRuntime = 'lambda';
|
|
456
498
|
if (mode === 'split') {
|
|
457
|
-
await executeSplitStart(cmd,
|
|
499
|
+
await executeSplitStart(cmd, context, options);
|
|
458
500
|
return;
|
|
459
501
|
}
|
|
460
502
|
assertCompatibleStartVariant(variant, configuredRuntime);
|
|
@@ -469,7 +511,7 @@ const executeStart = async (options, cmd) => {
|
|
|
469
511
|
const wranglerConfig = typeof options.wranglerConfig === 'string' && options.wranglerConfig.trim() !== ''
|
|
470
512
|
? options.wranglerConfig.trim()
|
|
471
513
|
: undefined;
|
|
472
|
-
await executeWranglerStart(cmd,
|
|
514
|
+
await executeWranglerStart(cmd, context, port, runtime, envName === '' ? undefined : envName, wranglerConfig);
|
|
473
515
|
return;
|
|
474
516
|
}
|
|
475
517
|
if (envName !== '') {
|
|
@@ -477,14 +519,14 @@ const executeStart = async (options, cmd) => {
|
|
|
477
519
|
}
|
|
478
520
|
const watchEnabled = resolveWatchPreference(options, mode);
|
|
479
521
|
if (variant === 'deno') {
|
|
480
|
-
await executeDenoStart(cmd,
|
|
522
|
+
await executeDenoStart(cmd, context, mode, watchEnabled, port, runtime);
|
|
481
523
|
return;
|
|
482
524
|
}
|
|
483
525
|
if (variant === 'lambda') {
|
|
484
|
-
await executeLambdaStart(cmd,
|
|
526
|
+
await executeLambdaStart(cmd, context, mode, watchEnabled, port, runtime);
|
|
485
527
|
return;
|
|
486
528
|
}
|
|
487
|
-
await executeNodeStart(cmd,
|
|
529
|
+
await executeNodeStart(cmd, context, mode, watchEnabled, port);
|
|
488
530
|
};
|
|
489
531
|
export const StartCommand = Object.freeze({
|
|
490
532
|
create() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ServiceScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"ServiceScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ServiceScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAUD;;GAEG;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAuB7F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAGnF;AAED;;GAEG;AAEH,wBAAgB,QAAQ,CACtB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,qBAAqB,CAAC,CAiDhC;AAgcD,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAC"}
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
import { FileGenerator } from '../scaffolding/FileGenerator.js';
|
|
6
6
|
import { Logger } from '../../config/logger.js';
|
|
7
7
|
import * as path from '../../node-singletons/path.js';
|
|
8
|
+
const coreModuleSpecifier = ['@zintrust', 'core'].join('/');
|
|
9
|
+
const coreStartModuleSpecifier = `${coreModuleSpecifier}/start`;
|
|
10
|
+
const serviceManifestImportExpression = "import('./bootstrap/service-manifest.ts').catch(() => import('./bootstrap/service-manifest.js'))";
|
|
11
|
+
const buildRouteImportExpression = (domain, serviceName) => `import('../services/${domain}/${serviceName}/routes/api.ts').catch(() => import('../services/${domain}/${serviceName}/routes/api.js'))`;
|
|
8
12
|
/**
|
|
9
13
|
* ServiceScaffolder generates microservices with all necessary files
|
|
10
14
|
*/
|
|
@@ -91,20 +95,22 @@ export function scaffold(projectRoot, options) {
|
|
|
91
95
|
function ensureProjectRuntimeFiles(projectRoot, options) {
|
|
92
96
|
const domain = options.domain ?? 'default';
|
|
93
97
|
const serviceId = `${domain}/${options.name}`;
|
|
98
|
+
const routeImportExpression = buildRouteImportExpression(domain, options.name);
|
|
94
99
|
const bootstrapDir = path.join(projectRoot, 'src', 'bootstrap');
|
|
95
100
|
FileGenerator.createDirectory(bootstrapDir);
|
|
96
101
|
const manifestPath = path.join(bootstrapDir, 'service-manifest.ts');
|
|
97
102
|
if (!FileGenerator.fileExists(manifestPath)) {
|
|
98
|
-
const initialManifest = `import type { ServiceManifestEntry } from '
|
|
103
|
+
const initialManifest = `import type { ServiceManifestEntry } from '${coreModuleSpecifier}';
|
|
99
104
|
|
|
100
105
|
export const serviceManifest: ReadonlyArray<ServiceManifestEntry> = [
|
|
101
106
|
{
|
|
102
107
|
id: '${serviceId}',
|
|
103
108
|
domain: '${domain}',
|
|
104
109
|
name: '${options.name}',
|
|
110
|
+
prefix: '${serviceId}',
|
|
105
111
|
port: ${options.port ?? 3001},
|
|
106
112
|
monolithEnabled: true,
|
|
107
|
-
loadRoutes: async () =>
|
|
113
|
+
loadRoutes: async () => ${routeImportExpression},
|
|
108
114
|
},
|
|
109
115
|
];
|
|
110
116
|
|
|
@@ -112,7 +118,9 @@ export default serviceManifest;
|
|
|
112
118
|
`;
|
|
113
119
|
FileGenerator.writeFile(manifestPath, initialManifest);
|
|
114
120
|
}
|
|
115
|
-
const runtimeModule = `
|
|
121
|
+
const runtimeModule = `const serviceManifestModule = await ${serviceManifestImportExpression};
|
|
122
|
+
|
|
123
|
+
const serviceManifest = serviceManifestModule.default ?? serviceManifestModule.serviceManifest ?? [];
|
|
116
124
|
|
|
117
125
|
export { serviceManifest };
|
|
118
126
|
|
|
@@ -128,6 +136,7 @@ export default Object.freeze({ serviceManifest });
|
|
|
128
136
|
function updateServiceManifest(projectRoot, options) {
|
|
129
137
|
const domain = options.domain ?? 'default';
|
|
130
138
|
const serviceId = `${domain}/${options.name}`;
|
|
139
|
+
const routeImportExpression = buildRouteImportExpression(domain, options.name);
|
|
131
140
|
const manifestPath = path.join(projectRoot, 'src', 'bootstrap', 'service-manifest.ts');
|
|
132
141
|
if (!FileGenerator.fileExists(manifestPath))
|
|
133
142
|
return;
|
|
@@ -139,9 +148,10 @@ function updateServiceManifest(projectRoot, options) {
|
|
|
139
148
|
id: '${serviceId}',
|
|
140
149
|
domain: '${domain}',
|
|
141
150
|
name: '${options.name}',
|
|
151
|
+
prefix: '${serviceId}',
|
|
142
152
|
port: ${options.port ?? 3001},
|
|
143
153
|
monolithEnabled: true,
|
|
144
|
-
loadRoutes: async () =>
|
|
154
|
+
loadRoutes: async () => ${routeImportExpression},
|
|
145
155
|
},
|
|
146
156
|
`;
|
|
147
157
|
const marker = '];';
|
|
@@ -234,7 +244,7 @@ function generateServiceIndex(options) {
|
|
|
234
244
|
* Auth: ${options.auth ?? 'api-key'}
|
|
235
245
|
*/
|
|
236
246
|
|
|
237
|
-
import { bootStandaloneService } from '
|
|
247
|
+
import { bootStandaloneService } from '${coreStartModuleSpecifier}';
|
|
238
248
|
|
|
239
249
|
await bootStandaloneService(import.meta.url, {
|
|
240
250
|
id: '${serviceId}',
|
|
@@ -244,7 +254,7 @@ await bootStandaloneService(import.meta.url, {
|
|
|
244
254
|
});
|
|
245
255
|
|
|
246
256
|
// Cloudflare Workers entry.
|
|
247
|
-
export { default } from '
|
|
257
|
+
export { default } from '${coreStartModuleSpecifier}';
|
|
248
258
|
`;
|
|
249
259
|
}
|
|
250
260
|
/**
|
|
@@ -255,7 +265,7 @@ function generateServiceRoutes(options) {
|
|
|
255
265
|
* ${options.name} Service Routes
|
|
256
266
|
*/
|
|
257
267
|
|
|
258
|
-
import { Router, type IRequest, type IResponse, type IRouter } from '
|
|
268
|
+
import { Router, type IRequest, type IResponse, type IRouter } from '${coreModuleSpecifier}';
|
|
259
269
|
|
|
260
270
|
export function registerRoutes(router: IRouter): void {
|
|
261
271
|
// Example route
|
|
@@ -326,8 +336,7 @@ function generateExampleController(options) {
|
|
|
326
336
|
* Example Controller for ${options.name} Service
|
|
327
337
|
*/
|
|
328
338
|
|
|
329
|
-
import { type IRequest, type IResponse, Controller } from '
|
|
330
|
-
|
|
339
|
+
import { type IRequest, type IResponse, Controller } from '${coreModuleSpecifier}';
|
|
331
340
|
const controller = Object.freeze({
|
|
332
341
|
...Controller,
|
|
333
342
|
|
|
@@ -389,7 +398,7 @@ function generateExampleModel(options) {
|
|
|
389
398
|
* Example Model for ${options.name} Service
|
|
390
399
|
*/
|
|
391
400
|
|
|
392
|
-
import { Model } from '
|
|
401
|
+
import { Model } from '${coreModuleSpecifier}';
|
|
393
402
|
|
|
394
403
|
export const Example = Model.define({
|
|
395
404
|
table: '${options.name}',
|
|
@@ -447,6 +456,8 @@ function getServiceConfig(options) {
|
|
|
447
456
|
*/
|
|
448
457
|
function generateServiceReadme(options) {
|
|
449
458
|
const config = getServiceConfig(options);
|
|
459
|
+
const serviceDir = `src/services/${config.domain}/${options.name}`;
|
|
460
|
+
const serviceId = `${config.domain}/${options.name}`;
|
|
450
461
|
return `# ${options.name} Service
|
|
451
462
|
|
|
452
463
|
Microservice for ${config.domain} domain.
|
|
@@ -460,14 +471,19 @@ Microservice for ${config.domain} domain.
|
|
|
460
471
|
## Getting Started
|
|
461
472
|
|
|
462
473
|
\`\`\`bash
|
|
463
|
-
# Start service
|
|
464
|
-
|
|
474
|
+
# Start this service from its service directory (Node)
|
|
475
|
+
cd ${serviceDir}
|
|
476
|
+
zin s
|
|
477
|
+
|
|
478
|
+
# Start this service with Cloudflare Workers dev
|
|
479
|
+
cd ${serviceDir}
|
|
480
|
+
zin s --wg
|
|
481
|
+
|
|
482
|
+
# List this service routes from the project root
|
|
483
|
+
MICROSERVICES=true SERVICES=${serviceId} zin routes
|
|
465
484
|
|
|
466
485
|
# Run tests
|
|
467
486
|
npm test
|
|
468
|
-
|
|
469
|
-
# Run migrations
|
|
470
|
-
npm run migrate
|
|
471
487
|
\`\`\`
|
|
472
488
|
|
|
473
489
|
## Environment Variables
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
type node_env = 'development' | 'production' | 'testing';
|
|
2
2
|
type LoadOptions = {
|
|
3
3
|
cwd?: string;
|
|
4
|
+
extraCwds?: string[];
|
|
4
5
|
overrideExisting?: boolean;
|
|
5
6
|
};
|
|
6
7
|
type LoadState = {
|
|
@@ -15,7 +16,7 @@ type CliOverrides = {
|
|
|
15
16
|
};
|
|
16
17
|
export declare const EnvFileLoader: Readonly<{
|
|
17
18
|
load: (options?: LoadOptions) => LoadState;
|
|
18
|
-
ensureLoaded: () => LoadState;
|
|
19
|
+
ensureLoaded: (options?: Omit<LoadOptions, "overrideExisting">) => LoadState;
|
|
19
20
|
applyCliOverrides: (overrides: CliOverrides) => void;
|
|
20
21
|
getState: () => LoadState;
|
|
21
22
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"AAQA,KAAK,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAmIzD,KAAK,WAAW,GAAG;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"AAQA,KAAK,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAmIzD,KAAK,WAAW,GAAG;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAkHF,eAAO,MAAM,aAAa;qBA7DH,WAAW,KAAQ,SAAS;6BAyBpB,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,KAAQ,SAAS;mCAG/C,YAAY,KAAG,IAAI;oBA+BpC,SAAS;EAO5B,CAAC"}
|
|
@@ -139,11 +139,7 @@ const filesLoader = (cwd, mode) => {
|
|
|
139
139
|
return files;
|
|
140
140
|
};
|
|
141
141
|
let cached;
|
|
142
|
-
const
|
|
143
|
-
if (cached !== undefined)
|
|
144
|
-
return cached;
|
|
145
|
-
const cwd = typeof options.cwd === 'string' && options.cwd !== '' ? options.cwd : process.cwd();
|
|
146
|
-
const overrideExisting = options.overrideExisting ?? true;
|
|
142
|
+
const loadFromCwd = (cwd, overrideExisting) => {
|
|
147
143
|
const mode = resolveAppMode(cwd);
|
|
148
144
|
const files = filesLoader(cwd, mode);
|
|
149
145
|
let baseApplied = false;
|
|
@@ -163,10 +159,30 @@ const load = (options = {}) => {
|
|
|
163
159
|
if (mode !== undefined) {
|
|
164
160
|
safeEnvSet('NODE_ENV', mode);
|
|
165
161
|
}
|
|
166
|
-
|
|
162
|
+
return { loadedFiles: files, mode };
|
|
163
|
+
};
|
|
164
|
+
const load = (options = {}) => {
|
|
165
|
+
if (cached !== undefined)
|
|
166
|
+
return cached;
|
|
167
|
+
const cwd = typeof options.cwd === 'string' && options.cwd !== '' ? options.cwd : process.cwd();
|
|
168
|
+
const extraCwds = Array.isArray(options.extraCwds)
|
|
169
|
+
? options.extraCwds.filter((value) => typeof value === 'string' && value.trim() !== '')
|
|
170
|
+
: [];
|
|
171
|
+
const overrideExisting = options.overrideExisting ?? true;
|
|
172
|
+
const roots = [cwd, ...extraCwds].filter((value, index, items) => items.indexOf(value) === index);
|
|
173
|
+
let mergedMode;
|
|
174
|
+
const loadedFiles = [];
|
|
175
|
+
for (let index = 0; index < roots.length; index += 1) {
|
|
176
|
+
const root = roots[index];
|
|
177
|
+
const state = loadFromCwd(root, index === 0 ? overrideExisting : true);
|
|
178
|
+
if (mergedMode === undefined && state.mode !== undefined)
|
|
179
|
+
mergedMode = state.mode;
|
|
180
|
+
loadedFiles.push(...state.loadedFiles);
|
|
181
|
+
}
|
|
182
|
+
cached = { loadedFiles, mode: mergedMode };
|
|
167
183
|
return cached;
|
|
168
184
|
};
|
|
169
|
-
const ensureLoaded = () => load({ overrideExisting: false });
|
|
185
|
+
const ensureLoaded = (options = {}) => load({ ...options, overrideExisting: false });
|
|
170
186
|
const applyCliOverrides = (overrides) => {
|
|
171
187
|
// Ensure base env is loaded first.
|
|
172
188
|
ensureLoaded();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/spawn.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/spawn.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA0CD,eAAO,MAAM,SAAS;wBACM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;EA+E7D,CAAC"}
|
package/src/cli/utils/spawn.js
CHANGED
|
@@ -29,6 +29,16 @@ const resolveLocalBin = (command, cwd) => {
|
|
|
29
29
|
}
|
|
30
30
|
return command;
|
|
31
31
|
};
|
|
32
|
+
const buildCommandNotFoundMessage = (command) => {
|
|
33
|
+
if (command === 'tsx') {
|
|
34
|
+
return [
|
|
35
|
+
"Error: 'tsx' not found on PATH.",
|
|
36
|
+
'Install it in the project with "npm install -D tsx".',
|
|
37
|
+
'If you want a machine-wide fallback, install it globally with "npm install -g tsx".',
|
|
38
|
+
].join(' ');
|
|
39
|
+
}
|
|
40
|
+
return `Error: '${command}' not found on PATH.`;
|
|
41
|
+
};
|
|
32
42
|
export const SpawnUtil = Object.freeze({
|
|
33
43
|
async spawnAndWait(input) {
|
|
34
44
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -87,7 +97,7 @@ export const SpawnUtil = Object.freeze({
|
|
|
87
97
|
catch (error) {
|
|
88
98
|
const code = error?.code;
|
|
89
99
|
if (code === 'ENOENT') {
|
|
90
|
-
throw ErrorFactory.createCliError(
|
|
100
|
+
throw ErrorFactory.createCliError(buildCommandNotFoundMessage(input.command));
|
|
91
101
|
}
|
|
92
102
|
throw ErrorFactory.createTryCatchError('Failed to spawn child process', error);
|
|
93
103
|
}
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.11
|
|
3
3
|
*
|
|
4
4
|
* ZinTrust Framework - Production-Grade TypeScript Backend
|
|
5
5
|
* Built for performance, type safety, and exceptional developer experience
|
|
6
6
|
*
|
|
7
7
|
* Build Information:
|
|
8
|
-
* Built: 2026-03-
|
|
8
|
+
* Built: 2026-03-23T13:29:47.237Z
|
|
9
9
|
* Node: >=20.0.0
|
|
10
10
|
* License: MIT
|
|
11
11
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Available at runtime for debugging and health checks
|
|
22
22
|
*/
|
|
23
23
|
export const ZINTRUST_VERSION = '0.1.41';
|
|
24
|
-
export const ZINTRUST_BUILD_DATE = '2026-03-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-03-23T13:29:47.153Z'; // Replaced during build
|
|
25
25
|
export { Application } from './boot/Application.js';
|
|
26
26
|
export { AwsSigV4 } from './common/index.js';
|
|
27
27
|
export { SignedRequest } from './security/SignedRequest.js';
|
|
@@ -3,6 +3,7 @@ export interface ServiceManifestEntry {
|
|
|
3
3
|
id: string;
|
|
4
4
|
domain: string;
|
|
5
5
|
name: string;
|
|
6
|
+
prefix?: string;
|
|
6
7
|
version?: string;
|
|
7
8
|
description?: string;
|
|
8
9
|
port?: number;
|
|
@@ -21,6 +22,12 @@ export interface ProjectRuntimeModule {
|
|
|
21
22
|
activeService?: ActiveServiceRuntime;
|
|
22
23
|
}
|
|
23
24
|
export declare const getServiceId: (domain: string, name: string) => string;
|
|
25
|
+
export declare const getDefaultServicePrefix: (domain: string, name: string) => string;
|
|
26
|
+
export declare const getServicePrefix: (args: {
|
|
27
|
+
prefix?: unknown;
|
|
28
|
+
domain?: unknown;
|
|
29
|
+
name?: unknown;
|
|
30
|
+
}) => string;
|
|
24
31
|
export declare const isCanonicalServiceId: (value: unknown) => value is string;
|
|
25
32
|
export declare const toCanonicalServiceId: (args: {
|
|
26
33
|
id?: unknown;
|
|
@@ -34,6 +41,12 @@ export declare const normalizeProjectRuntimeModule: (value: unknown) => ProjectR
|
|
|
34
41
|
export declare const serviceMatchesAllowList: (serviceId: string, serviceName: string, allowList: ReadonlyArray<string>) => boolean;
|
|
35
42
|
declare const _default: Readonly<{
|
|
36
43
|
getServiceId: (domain: string, name: string) => string;
|
|
44
|
+
getDefaultServicePrefix: (domain: string, name: string) => string;
|
|
45
|
+
getServicePrefix: (args: {
|
|
46
|
+
prefix?: unknown;
|
|
47
|
+
domain?: unknown;
|
|
48
|
+
name?: unknown;
|
|
49
|
+
}) => string;
|
|
37
50
|
isCanonicalServiceId: (value: unknown) => value is string;
|
|
38
51
|
toCanonicalServiceId: (args: {
|
|
39
52
|
id?: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceManifest.d.ts","sourceRoot":"","sources":["../../../src/microservices/ServiceManifest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACtD,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MAA6B,CAAC;AAE1F,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAI9D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM;IACzC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,KAAG,MAKH,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"ServiceManifest.d.ts","sourceRoot":"","sources":["../../../src/microservices/ServiceManifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { isArray, isFunction, isNonEmptyString, isObject } from '../helper/index.js';
|
|
2
2
|
export const getServiceId = (domain, name) => `${domain}/${name}`;
|
|
3
|
+
export const getDefaultServicePrefix = (domain, name) => `/${getServiceId(domain, name)}`;
|
|
4
|
+
const normalizeServicePrefix = (value) => {
|
|
5
|
+
const trimmed = value.trim();
|
|
6
|
+
if (trimmed === '' || trimmed === '/')
|
|
7
|
+
return '/';
|
|
8
|
+
const segments = trimmed
|
|
9
|
+
.split('/')
|
|
10
|
+
.map((segment) => segment.trim())
|
|
11
|
+
.filter((segment) => segment.length > 0);
|
|
12
|
+
if (segments.length === 0)
|
|
13
|
+
return '/';
|
|
14
|
+
return `/${segments.join('/')}`;
|
|
15
|
+
};
|
|
16
|
+
export const getServicePrefix = (args) => {
|
|
17
|
+
if (typeof args.prefix === 'string')
|
|
18
|
+
return normalizeServicePrefix(args.prefix);
|
|
19
|
+
const domain = isNonEmptyString(args.domain) ? args.domain : 'default';
|
|
20
|
+
const name = isNonEmptyString(args.name) ? args.name : 'unknown';
|
|
21
|
+
return getDefaultServicePrefix(domain, name);
|
|
22
|
+
};
|
|
3
23
|
export const isCanonicalServiceId = (value) => {
|
|
4
24
|
if (!isNonEmptyString(value))
|
|
5
25
|
return false;
|
|
@@ -22,6 +42,10 @@ export const isServiceManifestEntry = (value) => {
|
|
|
22
42
|
return false;
|
|
23
43
|
if (!isNonEmptyString(value['name']))
|
|
24
44
|
return false;
|
|
45
|
+
const prefix = value['prefix'];
|
|
46
|
+
if (prefix !== undefined && typeof prefix !== 'string') {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
25
49
|
const loadRoutes = value['loadRoutes'];
|
|
26
50
|
if (loadRoutes !== undefined && !isFunction(loadRoutes)) {
|
|
27
51
|
return false;
|
|
@@ -34,6 +58,7 @@ export const normalizeServiceManifest = (value) => {
|
|
|
34
58
|
return value.filter(isServiceManifestEntry).map((entry) => ({
|
|
35
59
|
...entry,
|
|
36
60
|
id: toCanonicalServiceId(entry),
|
|
61
|
+
prefix: getServicePrefix(entry),
|
|
37
62
|
monolithEnabled: entry.monolithEnabled !== false,
|
|
38
63
|
}));
|
|
39
64
|
};
|
|
@@ -72,6 +97,8 @@ export const serviceMatchesAllowList = (serviceId, serviceName, allowList) => {
|
|
|
72
97
|
};
|
|
73
98
|
export default Object.freeze({
|
|
74
99
|
getServiceId,
|
|
100
|
+
getDefaultServicePrefix,
|
|
101
|
+
getServicePrefix,
|
|
75
102
|
isCanonicalServiceId,
|
|
76
103
|
toCanonicalServiceId,
|
|
77
104
|
isServiceManifestEntry,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverrideValueMerge.d.ts","sourceRoot":"","sources":["../../../src/runtime/OverrideValueMerge.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,EAAE,UAAU,OAAO,KAAG,
|
|
1
|
+
{"version":3,"file":"OverrideValueMerge.d.ts","sourceRoot":"","sources":["../../../src/runtime/OverrideValueMerge.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,EAAE,UAAU,OAAO,KAAG,OAatE,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -6,7 +6,8 @@ export const mergeOverrideValues = (base, override) => {
|
|
|
6
6
|
const merged = { ...base };
|
|
7
7
|
for (const [key, value] of Object.entries(override)) {
|
|
8
8
|
const current = merged[key];
|
|
9
|
-
merged[key] =
|
|
9
|
+
merged[key] =
|
|
10
|
+
isObject(current) && isObject(value) ? mergeOverrideValues(current, value) : value;
|
|
10
11
|
}
|
|
11
12
|
return merged;
|
|
12
13
|
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
const serviceManifestModule = await import('./bootstrap/service-manifest.ts').catch(() =>
|
|
2
|
+
import('./bootstrap/service-manifest.js')
|
|
3
|
+
);
|
|
4
|
+
|
|
5
|
+
const serviceManifest = serviceManifestModule.default ?? serviceManifestModule.serviceManifest ?? [];
|
|
2
6
|
|
|
3
7
|
export { serviceManifest };
|
|
4
8
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
const serviceManifestModule = await import('./bootstrap/service-manifest.ts').catch(() =>
|
|
2
|
+
import('./bootstrap/service-manifest.js')
|
|
3
|
+
);
|
|
4
|
+
|
|
5
|
+
const serviceManifest = serviceManifestModule.default ?? serviceManifestModule.serviceManifest ?? [];
|
|
2
6
|
|
|
3
7
|
export { serviceManifest };
|
|
4
8
|
|