@zintrust/core 0.4.12 → 0.4.14
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.map +1 -1
- package/src/boot/registry/registerRoute.js +59 -7
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +119 -9
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +4 -1
- package/src/cli/utils/EnvFileLoader.d.ts +2 -0
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/cli/utils/EnvFileLoader.js +85 -24
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +13 -0
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +21 -1
- package/src/index.js +3 -3
- package/src/microservices/ServiceManifest.d.ts +1 -0
- package/src/microservices/ServiceManifest.d.ts.map +1 -1
- package/src/microservices/ServiceManifest.js +5 -0
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +5 -2
- package/src/orm/DatabaseConnectionRegistry.d.ts +8 -0
- package/src/orm/DatabaseConnectionRegistry.d.ts.map +1 -0
- package/src/orm/DatabaseConnectionRegistry.js +13 -0
- package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -1
- package/src/orm/DatabaseRuntimeRegistration.js +4 -2
- package/src/runtime/ProjectBootstrap.d.ts +6 -0
- package/src/runtime/ProjectBootstrap.d.ts.map +1 -0
- package/src/runtime/ProjectBootstrap.js +43 -0
- package/src/runtime/ProjectRuntime.d.ts.map +1 -1
- package/src/runtime/ProjectRuntime.js +5 -2
- package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/CloudflareAdapter.js +8 -2
- package/src/start.d.ts.map +1 -1
- package/src/start.js +65 -4
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAc3D,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;AAiKF,eAAO,MAAM,oBAAoB,GAC/B,kBAAkB,MAAM,EACxB,QAAQ,OAAO,KACd,OAAO,CAAC,IAAI,CAqBd,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { appConfig } from '../../config/index.js';
|
|
2
2
|
import Logger from '../../config/logger.js';
|
|
3
3
|
import { Router } from '../../routes/Router.js';
|
|
4
|
-
import { isObject } from '../../helper/index.js';
|
|
5
|
-
import { getServicePrefix } from '../../microservices/ServiceManifest.js';
|
|
4
|
+
import { isNonEmptyString, isObject } from '../../helper/index.js';
|
|
6
5
|
import * as path from '../../node-singletons/path.js';
|
|
7
6
|
import { pathToFileURL } from '../../node-singletons/url.js';
|
|
8
7
|
import { detectRuntime } from '../../runtime/detectRuntime.js';
|
|
@@ -63,23 +62,75 @@ const registerAppRoutes = async (resolvedBasePath, router) => {
|
|
|
63
62
|
mod.registerRoutes(router);
|
|
64
63
|
}
|
|
65
64
|
};
|
|
65
|
+
const getProjectRoot = () => {
|
|
66
|
+
const fromEnv = process.env?.['ZINTRUST_PROJECT_ROOT'] ?? '';
|
|
67
|
+
if (fromEnv.trim() !== '')
|
|
68
|
+
return fromEnv.trim();
|
|
69
|
+
return process.cwd();
|
|
70
|
+
};
|
|
71
|
+
const resolveManifestServiceEnvDir = (projectRoot, entry) => {
|
|
72
|
+
const configRoot = entry.configRoot;
|
|
73
|
+
if (isNonEmptyString(configRoot)) {
|
|
74
|
+
return path.dirname(path.join(projectRoot, configRoot));
|
|
75
|
+
}
|
|
76
|
+
return path.join(projectRoot, 'src', 'services', entry.domain, entry.name);
|
|
77
|
+
};
|
|
78
|
+
const resolveServicePrefix = (entry) => {
|
|
79
|
+
const prefix = entry.prefix;
|
|
80
|
+
if (isNonEmptyString(prefix)) {
|
|
81
|
+
const segments = prefix
|
|
82
|
+
.split('/')
|
|
83
|
+
.map((segment) => segment.trim())
|
|
84
|
+
.filter((segment) => segment !== '');
|
|
85
|
+
return segments.length === 0 ? '/' : `/${segments.join('/')}`;
|
|
86
|
+
}
|
|
87
|
+
return `/${entry.domain}/${entry.name}`;
|
|
88
|
+
};
|
|
89
|
+
const ensureManifestServiceEnvLoaded = async (entry) => {
|
|
90
|
+
if (isCloudflare)
|
|
91
|
+
return;
|
|
92
|
+
const { EnvFileLoader } = await import('../../cli/utils/EnvFileLoader.js');
|
|
93
|
+
const projectRoot = getProjectRoot();
|
|
94
|
+
const envPath = resolveManifestServiceEnvDir(projectRoot, entry);
|
|
95
|
+
EnvFileLoader.ensureLoaded({
|
|
96
|
+
cwd: projectRoot,
|
|
97
|
+
includeCwd: true,
|
|
98
|
+
envPaths: [envPath],
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
const registerLoadedRoutes = (router, entry, registerRoutes, activeService) => {
|
|
102
|
+
const servicePrefix = resolveServicePrefix(entry);
|
|
103
|
+
if (activeService?.id === entry.id) {
|
|
104
|
+
registerRoutes(router);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
Router.group(router, servicePrefix, (scopedRouter) => {
|
|
108
|
+
registerRoutes(scopedRouter);
|
|
109
|
+
});
|
|
110
|
+
};
|
|
66
111
|
const registerManifestRoutes = async (router) => {
|
|
67
112
|
await ProjectRuntime.tryLoadNodeRuntime();
|
|
68
113
|
const serviceManifest = ProjectRuntime.getServiceManifest();
|
|
69
114
|
if (serviceManifest.length === 0)
|
|
70
115
|
return;
|
|
116
|
+
const activeService = ProjectRuntime.getActiveService();
|
|
117
|
+
if (activeService !== undefined && isCloudflare)
|
|
118
|
+
return;
|
|
71
119
|
for (const entry of serviceManifest) {
|
|
72
120
|
if (entry.monolithEnabled === false || typeof entry.loadRoutes !== 'function') {
|
|
73
121
|
continue;
|
|
74
122
|
}
|
|
123
|
+
if (activeService !== undefined && activeService.id !== entry.id) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
75
126
|
try {
|
|
127
|
+
// eslint-disable-next-line no-await-in-loop
|
|
128
|
+
await ensureManifestServiceEnvLoaded(entry);
|
|
76
129
|
// eslint-disable-next-line no-await-in-loop
|
|
77
130
|
const mod = await entry.loadRoutes();
|
|
78
131
|
const registerRoutes = isObject(mod) ? mod.registerRoutes : undefined;
|
|
79
132
|
if (typeof registerRoutes === 'function') {
|
|
80
|
-
|
|
81
|
-
registerRoutes(scopedRouter);
|
|
82
|
-
});
|
|
133
|
+
registerLoadedRoutes(router, entry, registerRoutes, activeService);
|
|
83
134
|
}
|
|
84
135
|
}
|
|
85
136
|
catch (error) {
|
|
@@ -104,14 +155,15 @@ const registerGlobalRoutes = (router) => {
|
|
|
104
155
|
};
|
|
105
156
|
export const registerMasterRoutes = async (resolvedBasePath, router) => {
|
|
106
157
|
try {
|
|
158
|
+
const activeService = ProjectRuntime.getActiveService();
|
|
107
159
|
if (isCloudflare) {
|
|
108
160
|
registerGlobalRoutes(router);
|
|
109
161
|
}
|
|
110
|
-
if (!isCloudflare) {
|
|
162
|
+
if (!isCloudflare && activeService === undefined) {
|
|
111
163
|
await registerAppRoutes(resolvedBasePath, router);
|
|
112
164
|
}
|
|
113
165
|
await registerManifestRoutes(router);
|
|
114
|
-
if (router.routes.length === 0) {
|
|
166
|
+
if (router.routes.length === 0 && activeService === undefined) {
|
|
115
167
|
await registerFrameworkRoutes(resolvedBasePath, router);
|
|
116
168
|
}
|
|
117
169
|
// Always register core framework routes (health, metrics, doc) after app routes
|
|
@@ -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;AA21BvF,eAAO,MAAM,YAAY;cACb,YAAY;EAmCtB,CAAC"}
|
|
@@ -2,11 +2,16 @@ import { BaseCommand } from '../BaseCommand.js';
|
|
|
2
2
|
import { createDenoRunnerSource, createLambdaRunnerSource } from '../commands/runner/index.js';
|
|
3
3
|
import { EnvFileLoader } from '../utils/EnvFileLoader.js';
|
|
4
4
|
import { SpawnUtil } from '../utils/spawn.js';
|
|
5
|
+
import { generateUuid } from '../../common/utility.js';
|
|
5
6
|
import { readEnvString } from '../../common/ExternalServiceUtils.js';
|
|
6
7
|
import * as Common from '../../common/index.js';
|
|
7
8
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
8
|
-
import {
|
|
9
|
+
import { isNonEmptyString } from '../../helper/index.js';
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from '../../node-singletons/fs.js';
|
|
9
11
|
import * as path from '../../node-singletons/path.js';
|
|
12
|
+
import { ProjectRuntime } from '../../runtime/ProjectRuntime.js';
|
|
13
|
+
const isWranglerVarName = (value) => /^[A-Za-z_]\w*$/.test(value);
|
|
14
|
+
const isAbsolutePath = (value) => value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
|
|
10
15
|
const resolveNpmPath = () => {
|
|
11
16
|
try {
|
|
12
17
|
return typeof Common.resolveNpmPath === 'function' ? Common.resolveNpmPath() : 'npm';
|
|
@@ -168,6 +173,26 @@ const resolveCacheEnabledPreference = (options) => {
|
|
|
168
173
|
return options.cache;
|
|
169
174
|
return undefined;
|
|
170
175
|
};
|
|
176
|
+
const resolveRootEnvPreference = (options) => {
|
|
177
|
+
const hasRootEnv = hasFlag('--root-env');
|
|
178
|
+
const hasNoRootEnv = hasFlag('--no-root-env');
|
|
179
|
+
if (hasRootEnv && hasNoRootEnv) {
|
|
180
|
+
throw ErrorFactory.createCliError('Error: Cannot use both --root-env and --no-root-env.');
|
|
181
|
+
}
|
|
182
|
+
if (hasRootEnv)
|
|
183
|
+
return true;
|
|
184
|
+
if (hasNoRootEnv)
|
|
185
|
+
return false;
|
|
186
|
+
if (typeof options.rootEnv === 'boolean')
|
|
187
|
+
return options.rootEnv;
|
|
188
|
+
return true;
|
|
189
|
+
};
|
|
190
|
+
const resolveEnvPath = (options, projectRoot) => {
|
|
191
|
+
const raw = typeof options.envPath === 'string' ? options.envPath.trim() : '';
|
|
192
|
+
if (raw === '')
|
|
193
|
+
return undefined;
|
|
194
|
+
return isAbsolutePath(raw) ? raw : path.join(projectRoot, raw);
|
|
195
|
+
};
|
|
171
196
|
const findNearestPackageJsonDir = (cwd) => {
|
|
172
197
|
let current = path.resolve(cwd);
|
|
173
198
|
while (true) {
|
|
@@ -210,9 +235,87 @@ const buildStartEnv = (projectRoot) => ({
|
|
|
210
235
|
...process.env,
|
|
211
236
|
ZINTRUST_PROJECT_ROOT: projectRoot,
|
|
212
237
|
});
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
238
|
+
const buildWorkerDevVarsContent = () => {
|
|
239
|
+
return (Object.entries(process.env)
|
|
240
|
+
.filter((entry) => {
|
|
241
|
+
const [key, value] = entry;
|
|
242
|
+
return isWranglerVarName(key) && typeof value === 'string';
|
|
243
|
+
})
|
|
244
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
245
|
+
.join('\n') + '\n');
|
|
246
|
+
};
|
|
247
|
+
async function withWranglerEnvSnapshot(cwd, envName, fn) {
|
|
248
|
+
const normalizedEnv = typeof envName === 'string' ? envName.trim() : '';
|
|
249
|
+
const targetName = normalizedEnv === '' ? '.dev.vars' : `.dev.vars.${normalizedEnv}`;
|
|
250
|
+
const targetPath = path.join(cwd, targetName);
|
|
251
|
+
const backupPath = existsSync(targetPath)
|
|
252
|
+
? `${targetPath}.disabled-by-zin-${generateUuid()}`
|
|
253
|
+
: undefined;
|
|
254
|
+
if (backupPath !== undefined) {
|
|
255
|
+
renameSync(targetPath, backupPath);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
writeFileSync(targetPath, buildWorkerDevVarsContent(), 'utf-8');
|
|
259
|
+
return await fn();
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
try {
|
|
263
|
+
if (existsSync(targetPath))
|
|
264
|
+
unlinkSync(targetPath);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// noop
|
|
268
|
+
}
|
|
269
|
+
if (backupPath !== undefined) {
|
|
270
|
+
try {
|
|
271
|
+
if (existsSync(backupPath))
|
|
272
|
+
renameSync(backupPath, targetPath);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// noop
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const resolveManifestServiceEnvDir = (projectRoot, entry) => {
|
|
281
|
+
const configRoot = entry.configRoot;
|
|
282
|
+
if (isNonEmptyString(configRoot)) {
|
|
283
|
+
return path.dirname(path.join(projectRoot, configRoot));
|
|
284
|
+
}
|
|
285
|
+
return path.join(projectRoot, 'src', 'services', entry.domain, entry.name);
|
|
286
|
+
};
|
|
287
|
+
const ensureStartEnvLoaded = (context, options) => {
|
|
288
|
+
const envPath = resolveEnvPath(options, context.projectRoot);
|
|
289
|
+
const rootEnv = resolveRootEnvPreference(options);
|
|
290
|
+
const extraCwds = envPath === undefined && context.cwd !== context.projectRoot ? [context.cwd] : [];
|
|
291
|
+
EnvFileLoader.ensureLoaded({
|
|
292
|
+
cwd: context.projectRoot,
|
|
293
|
+
includeCwd: rootEnv,
|
|
294
|
+
extraCwds,
|
|
295
|
+
...(envPath === undefined ? {} : { envPaths: [envPath] }),
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
const preloadManifestServiceEnv = async (context, options) => {
|
|
299
|
+
if (context.cwd !== context.projectRoot)
|
|
300
|
+
return;
|
|
301
|
+
if (resolveEnvPath(options, context.projectRoot) !== undefined)
|
|
302
|
+
return;
|
|
303
|
+
process.env['ZINTRUST_PROJECT_ROOT'] = context.projectRoot;
|
|
304
|
+
ProjectRuntime.clear();
|
|
305
|
+
await ProjectRuntime.tryLoadNodeRuntime();
|
|
306
|
+
const manifest = ProjectRuntime.getServiceManifest().filter((entry) => entry.monolithEnabled !== false);
|
|
307
|
+
if (manifest.length === 0)
|
|
308
|
+
return;
|
|
309
|
+
const envPaths = manifest
|
|
310
|
+
.map((entry) => resolveManifestServiceEnvDir(context.projectRoot, entry))
|
|
311
|
+
.filter((value, index, items) => items.indexOf(value) === index);
|
|
312
|
+
if (envPaths.length === 0)
|
|
313
|
+
return;
|
|
314
|
+
EnvFileLoader.ensureLoaded({
|
|
315
|
+
cwd: context.projectRoot,
|
|
316
|
+
includeCwd: resolveRootEnvPreference(options),
|
|
317
|
+
envPaths,
|
|
318
|
+
});
|
|
216
319
|
};
|
|
217
320
|
const isFrameworkRepo = (packageJson) => packageJson.name === '@zintrust/core';
|
|
218
321
|
const hasDevScript = (packageJson) => {
|
|
@@ -330,10 +433,12 @@ const executeWranglerStart = async (cmd, context, port, runtime, envName, wrangl
|
|
|
330
433
|
}
|
|
331
434
|
logMySqlProxyHint(cmd);
|
|
332
435
|
cmd.info('Starting in Wrangler dev mode...');
|
|
333
|
-
const exitCode = await
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
436
|
+
const exitCode = await withWranglerEnvSnapshot(context.cwd, envName, async () => {
|
|
437
|
+
return SpawnUtil.spawnAndWait({
|
|
438
|
+
command: 'wrangler',
|
|
439
|
+
args: wranglerArgs,
|
|
440
|
+
env: buildStartEnv(context.projectRoot),
|
|
441
|
+
});
|
|
337
442
|
});
|
|
338
443
|
process.exit(exitCode);
|
|
339
444
|
};
|
|
@@ -483,7 +588,9 @@ const executeSplitStart = async (cmd, context, _options) => {
|
|
|
483
588
|
const executeStart = async (options, cmd) => {
|
|
484
589
|
const cwd = process.cwd();
|
|
485
590
|
const context = resolveStartContext(cwd);
|
|
486
|
-
|
|
591
|
+
process.env['ZINTRUST_PROJECT_ROOT'] = context.projectRoot;
|
|
592
|
+
ensureStartEnvLoaded(context, options);
|
|
593
|
+
await preloadManifestServiceEnv(context, options);
|
|
487
594
|
const mode = resolveMode(options);
|
|
488
595
|
const port = resolvePort(options);
|
|
489
596
|
const runtime = resolveRuntime(options);
|
|
@@ -541,8 +648,11 @@ export const StartCommand = Object.freeze({
|
|
|
541
648
|
.option('--no-cache', 'Disable cache functionality')
|
|
542
649
|
.option('--watch', 'Force watch mode (Node only)')
|
|
543
650
|
.option('--no-watch', 'Disable watch mode (Node only)')
|
|
651
|
+
.option('--root-env', 'Load root project .env files for standalone service start')
|
|
652
|
+
.option('--no-root-env', 'Skip root project .env files for standalone service start')
|
|
544
653
|
.option('--mode <development|production|testing>', 'Override app mode')
|
|
545
654
|
.option('--env <name>', 'Wrangler environment name (Wrangler mode only)')
|
|
655
|
+
.option('--env-path <path>', 'Explicit env directory or .env file path for standalone service start')
|
|
546
656
|
.option('--wrangler-config <path>', 'Wrangler config path (Wrangler mode only)')
|
|
547
657
|
.option('--runtime <nodejs|cloudflare|lambda|deno|auto>', 'Set RUNTIME for spawned Node')
|
|
548
658
|
.option('-p, --port <number>', 'Override server port');
|
|
@@ -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;AAaD;;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;AAkcD,eAAO,MAAM,iBAAiB;;;;EAI5B,CAAC"}
|
|
@@ -9,6 +9,7 @@ const coreModuleSpecifier = ['@zintrust', 'core'].join('/');
|
|
|
9
9
|
const coreStartModuleSpecifier = `${coreModuleSpecifier}/start`;
|
|
10
10
|
const serviceManifestImportExpression = "import('./bootstrap/service-manifest.ts').catch(() => import('./bootstrap/service-manifest.js'))";
|
|
11
11
|
const buildRouteImportExpression = (domain, serviceName) => `import('../services/${domain}/${serviceName}/routes/api.ts').catch(() => import('../services/${domain}/${serviceName}/routes/api.js'))`;
|
|
12
|
+
const getServiceConfigRoot = (domain, serviceName) => `src/services/${domain}/${serviceName}/config`;
|
|
12
13
|
/**
|
|
13
14
|
* ServiceScaffolder generates microservices with all necessary files
|
|
14
15
|
*/
|
|
@@ -107,6 +108,7 @@ export const serviceManifest: ReadonlyArray<ServiceManifestEntry> = [
|
|
|
107
108
|
id: '${serviceId}',
|
|
108
109
|
domain: '${domain}',
|
|
109
110
|
name: '${options.name}',
|
|
111
|
+
configRoot: '${getServiceConfigRoot(domain, options.name)}',
|
|
110
112
|
prefix: '${serviceId}',
|
|
111
113
|
port: ${options.port ?? 3001},
|
|
112
114
|
monolithEnabled: true,
|
|
@@ -148,6 +150,7 @@ function updateServiceManifest(projectRoot, options) {
|
|
|
148
150
|
id: '${serviceId}',
|
|
149
151
|
domain: '${domain}',
|
|
150
152
|
name: '${options.name}',
|
|
153
|
+
configRoot: '${getServiceConfigRoot(domain, options.name)}',
|
|
151
154
|
prefix: '${serviceId}',
|
|
152
155
|
port: ${options.port ?? 3001},
|
|
153
156
|
monolithEnabled: true,
|
|
@@ -236,7 +239,7 @@ function generateServiceConfig(options) {
|
|
|
236
239
|
function generateServiceIndex(options) {
|
|
237
240
|
const domain = options.domain ?? 'default';
|
|
238
241
|
const serviceId = `${domain}/${options.name}`;
|
|
239
|
-
const configRoot =
|
|
242
|
+
const configRoot = getServiceConfigRoot(domain, options.name);
|
|
240
243
|
return `/**
|
|
241
244
|
* ${options.name} Service - Entry Point
|
|
242
245
|
* Port: ${options.port ?? 3001}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EnvFileLoader.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/EnvFileLoader.ts"],"names":[],"mappings":"AASA,KAAK,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAmIzD,KAAK,WAAW,GAAG;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,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;AAaF,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;AAgMF,eAAO,MAAM,aAAa;qBAjDH,WAAW,KAAQ,SAAS;6BAapB,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,KAAQ,SAAS;mCAG/C,YAAY,KAAG,IAAI;oBA+BpC,SAAS;EAO5B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Env } from '../../config/env.js';
|
|
2
|
+
import { isArray, isNonEmptyString } from '../../helper/index.js';
|
|
2
3
|
import { existsSync, readFileSync } from '../../node-singletons/fs.js';
|
|
3
|
-
import
|
|
4
|
+
import * as path from '../../node-singletons/path.js';
|
|
4
5
|
const safeEnvGet = (key, defaultValue = '') => {
|
|
5
6
|
const envAny = Env;
|
|
6
7
|
if (typeof envAny.get === 'function')
|
|
@@ -102,7 +103,7 @@ const applyToProcessEnv = (values, overrideExisting) => {
|
|
|
102
103
|
}
|
|
103
104
|
};
|
|
104
105
|
const readEnvFileIfExists = (cwd, filename) => {
|
|
105
|
-
const fullPath = join(cwd, filename);
|
|
106
|
+
const fullPath = path.join(cwd, filename);
|
|
106
107
|
if (!existsSync(fullPath))
|
|
107
108
|
return undefined;
|
|
108
109
|
const raw = readFileSync(fullPath, 'utf-8');
|
|
@@ -120,20 +121,20 @@ const resolveAppMode = (cwd) => {
|
|
|
120
121
|
};
|
|
121
122
|
const filesLoader = (cwd, mode) => {
|
|
122
123
|
const files = [];
|
|
123
|
-
if (existsSync(join(cwd, '.env')))
|
|
124
|
+
if (existsSync(path.join(cwd, '.env')))
|
|
124
125
|
files.push('.env');
|
|
125
126
|
// Per your rule: production uses .env; dev uses .env.dev
|
|
126
127
|
if (mode !== undefined && mode !== '' && mode !== 'production') {
|
|
127
128
|
const modeFile = `.env.${mode}`;
|
|
128
|
-
if (existsSync(join(cwd, modeFile)))
|
|
129
|
+
if (existsSync(path.join(cwd, modeFile)))
|
|
129
130
|
files.push(modeFile);
|
|
130
131
|
}
|
|
131
132
|
const local = '.env.local';
|
|
132
|
-
if (existsSync(join(cwd, local)))
|
|
133
|
+
if (existsSync(path.join(cwd, local)))
|
|
133
134
|
files.push(local);
|
|
134
135
|
if (mode !== undefined && mode !== '') {
|
|
135
136
|
const modeLocal = `.env.${mode}.local`;
|
|
136
|
-
if (existsSync(join(cwd, modeLocal)))
|
|
137
|
+
if (existsSync(path.join(cwd, modeLocal)))
|
|
137
138
|
files.push(modeLocal);
|
|
138
139
|
}
|
|
139
140
|
return files;
|
|
@@ -161,25 +162,85 @@ const loadFromCwd = (cwd, overrideExisting) => {
|
|
|
161
162
|
}
|
|
162
163
|
return { loadedFiles: files, mode };
|
|
163
164
|
};
|
|
164
|
-
const
|
|
165
|
-
if (
|
|
166
|
-
return
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
const loadFromFile = (filePath, overrideExisting) => {
|
|
166
|
+
if (!existsSync(filePath))
|
|
167
|
+
return { loadedFiles: [] };
|
|
168
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
169
|
+
const parsed = parseEnvFile(raw);
|
|
170
|
+
applyToProcessEnv(parsed, overrideExisting);
|
|
171
|
+
const rawMode = parsed['NODE_ENV'];
|
|
172
|
+
const mode = isNonEmptyString(rawMode) ? normalizeAppMode(rawMode) : undefined;
|
|
173
|
+
if (mode !== undefined) {
|
|
174
|
+
safeEnvSet('NODE_ENV', mode);
|
|
175
|
+
}
|
|
176
|
+
return { loadedFiles: [filePath], mode };
|
|
177
|
+
};
|
|
178
|
+
const normalizeCwdList = (value) => {
|
|
179
|
+
if (!isArray(value))
|
|
180
|
+
return [];
|
|
181
|
+
return value
|
|
182
|
+
.filter(isNonEmptyString)
|
|
183
|
+
.map((item) => item.trim())
|
|
184
|
+
.filter((item) => item !== '');
|
|
185
|
+
};
|
|
186
|
+
const normalizeEnvPathList = (value) => normalizeCwdList(value);
|
|
187
|
+
const createLoadPlan = (options) => {
|
|
188
|
+
const cwd = isNonEmptyString(options.cwd) ? options.cwd : process.cwd();
|
|
189
|
+
const includeCwd = options.includeCwd !== false;
|
|
190
|
+
const extraCwds = normalizeCwdList(options.extraCwds);
|
|
191
|
+
const envPaths = normalizeEnvPathList(options.envPaths);
|
|
171
192
|
const overrideExisting = options.overrideExisting ?? true;
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
193
|
+
const sources = [];
|
|
194
|
+
if (includeCwd) {
|
|
195
|
+
sources.push({
|
|
196
|
+
key: `cwd:${cwd}`,
|
|
197
|
+
path: cwd,
|
|
198
|
+
kind: 'cwd',
|
|
199
|
+
overrideExisting,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
for (const extraCwd of extraCwds) {
|
|
203
|
+
sources.push({
|
|
204
|
+
key: `cwd:${extraCwd}`,
|
|
205
|
+
path: extraCwd,
|
|
206
|
+
kind: 'cwd',
|
|
207
|
+
overrideExisting: true,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
for (const envPath of envPaths) {
|
|
211
|
+
const looksLikeFile = path.basename(envPath).startsWith('.env');
|
|
212
|
+
sources.push({
|
|
213
|
+
key: `${looksLikeFile ? 'file' : 'cwd'}:${envPath}`,
|
|
214
|
+
path: envPath,
|
|
215
|
+
kind: looksLikeFile ? 'file' : 'cwd',
|
|
216
|
+
overrideExisting: true,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return sources.filter((source, index, items) => items.findIndex((item) => item.key === source.key) === index);
|
|
220
|
+
};
|
|
221
|
+
const loadSource = (source) => {
|
|
222
|
+
if (source.kind === 'file')
|
|
223
|
+
return loadFromFile(source.path, source.overrideExisting);
|
|
224
|
+
return loadFromCwd(source.path, source.overrideExisting);
|
|
225
|
+
};
|
|
226
|
+
const mergeCachedState = (state, source, next) => {
|
|
227
|
+
state.loadedSourceKeys.push(source.key);
|
|
228
|
+
if (next.mode !== undefined && state.mode === undefined) {
|
|
229
|
+
state.mode = next.mode;
|
|
230
|
+
}
|
|
231
|
+
if (next.loadedFiles.length > 0) {
|
|
232
|
+
state.loadedFiles.push(...next.loadedFiles);
|
|
233
|
+
}
|
|
234
|
+
return state;
|
|
235
|
+
};
|
|
236
|
+
const load = (options = {}) => {
|
|
237
|
+
const plan = createLoadPlan(options);
|
|
238
|
+
cached ??= { loadedFiles: [], loadedSourceKeys: [] };
|
|
239
|
+
for (const source of plan) {
|
|
240
|
+
if (cached.loadedSourceKeys.includes(source.key))
|
|
241
|
+
continue;
|
|
242
|
+
mergeCachedState(cached, source, loadSource(source));
|
|
243
|
+
}
|
|
183
244
|
return cached;
|
|
184
245
|
};
|
|
185
246
|
const ensureLoaded = (options = {}) => load({ ...options, overrideExisting: false });
|
package/src/config/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAsClF,eAAO,MAAM,cAAc,QAAO,WAAW,GAAG,SAAwB,CAAC;AAEzE,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,EAAE,WAAW,MAAM,KAAG,MAKzE,CAAC;AAGF,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,EAAE,eAAe,MAAM,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,EAAE,cAAc,MAAM,KAAG,MAI1D,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,EAAE,eAAe,MAAM,KAAG,MAI7D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,EAAE,eAAe,OAAO,KAAG,OAI7D,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,IAGhD,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,KAAG,IAInC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,GAAG,IAAI,KAAG,IAEpD,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,MAAM,CAAC,MAAM,EAAE,MAAM,CAOhD,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAO,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAKjE,CAAC;AACF,eAAO,MAAM,mBAAmB,QAAuC,CAAC;AAKxE,eAAO,MAAM,GAAG;eA3DS,MAAM,iBAAiB,MAAM,KAAG,MAAM;kBAMnC,MAAM,gBAAgB,MAAM,KAAG,MAAM;mBAYpC,MAAM,iBAAiB,OAAO,KAAG,OAAO;oBANvC,MAAM,iBAAiB,MAAM,KAAG,MAAM;eAY3C,MAAM,SAAS,MAAM,KAAG,IAAI;iBAK1B,MAAM,KAAG,IAAI;wBAMN,SAAS,GAAG,IAAI,KAAG,IAAI;oBAI7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;cAgCJ,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAgOpB,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoFxF,CAAC;AAEH,eAAO,MAAM,aAAa,QAAO,MAchC,CAAC"}
|
package/src/config/env.js
CHANGED
|
@@ -8,11 +8,24 @@
|
|
|
8
8
|
// Cache process check once at module load time
|
|
9
9
|
const processLike = typeof process === 'undefined' ? undefined : process;
|
|
10
10
|
let externalEnvSource = null;
|
|
11
|
+
const getGlobalEnv = () => {
|
|
12
|
+
const env = globalThis.env;
|
|
13
|
+
if (env === undefined || env === null || typeof env !== 'object')
|
|
14
|
+
return undefined;
|
|
15
|
+
return env;
|
|
16
|
+
};
|
|
11
17
|
const getEnvSource = () => {
|
|
12
18
|
if (typeof externalEnvSource === 'function')
|
|
13
19
|
return externalEnvSource();
|
|
14
20
|
if (externalEnvSource !== null)
|
|
15
21
|
return externalEnvSource;
|
|
22
|
+
const globalEnv = getGlobalEnv();
|
|
23
|
+
if (globalEnv !== undefined) {
|
|
24
|
+
return {
|
|
25
|
+
...processLike?.env,
|
|
26
|
+
...globalEnv,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
16
29
|
return processLike?.env ?? {};
|
|
17
30
|
};
|
|
18
31
|
const normalizeEnvValue = (value) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/functions/cloudflare.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/functions/cloudflare.ts"],"names":[],"mappings":";mBA0JuB,OAAO,QAAQ,OAAO,QAAQ,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;;AADhF,wBAoCE"}
|
|
@@ -101,6 +101,25 @@ const injectIoredisModule = async () => {
|
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
let startupConfigOverridesPromise;
|
|
104
|
+
const WORKER_ENV_SNAPSHOT_KEY = 'ZINTRUST_WORKER_ENV_SNAPSHOT';
|
|
105
|
+
const resolveWorkersEnv = (env) => {
|
|
106
|
+
const bindings = typeof env === 'object' && env !== null ? { ...env } : {};
|
|
107
|
+
const rawSnapshot = bindings[WORKER_ENV_SNAPSHOT_KEY];
|
|
108
|
+
if (typeof rawSnapshot !== 'string' || rawSnapshot.trim() === '') {
|
|
109
|
+
return bindings;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const parsed = JSON.parse(rawSnapshot);
|
|
113
|
+
Reflect.deleteProperty(bindings, WORKER_ENV_SNAPSHOT_KEY);
|
|
114
|
+
return {
|
|
115
|
+
...parsed,
|
|
116
|
+
...bindings,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return bindings;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
104
123
|
const ensureStartupConfigOverridesLoaded = async () => {
|
|
105
124
|
startupConfigOverridesPromise ??= applyStartupConfigOverrides();
|
|
106
125
|
await startupConfigOverridesPromise;
|
|
@@ -108,8 +127,9 @@ const ensureStartupConfigOverridesLoaded = async () => {
|
|
|
108
127
|
export default {
|
|
109
128
|
async fetch(request, _env, _ctx) {
|
|
110
129
|
try {
|
|
130
|
+
const workersEnv = resolveWorkersEnv(_env);
|
|
111
131
|
// Make bindings available to framework code in Workers
|
|
112
|
-
globalThis.env =
|
|
132
|
+
globalThis.env = workersEnv;
|
|
113
133
|
const AppRoutes = (await import('@routes/' + 'api.ts'));
|
|
114
134
|
if (AppRoutes !== undefined) {
|
|
115
135
|
globalThis.__zintrustRoutes = AppRoutes;
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.14
|
|
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-23T16:59:39.933Z
|
|
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-23T16:59:39.858Z'; // 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';
|
|
@@ -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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,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,uBAAuB,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MACrC,CAAC;AAenC,eAAO,MAAM,gBAAgB,GAAI,MAAM;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,KAAG,MAMH,CAAC;AAEF,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":"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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,uBAAuB,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MACrC,CAAC;AAenC,eAAO,MAAM,gBAAgB,GAAI,MAAM;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,KAAG,MAMH,CAAC;AAEF,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,oBAsBhE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,aAAa,CAAC,oBAAoB,CAU3F,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAI,OAAO,OAAO,KAAG,oBAAoB,GAAG,SAarF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAI,OAAO,OAAO,KAAG,oBAa9D,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,WAAW,aAAa,CAAC,MAAM,CAAC,KAC/B,OAGF,CAAC;;2BAxHmC,MAAM,QAAQ,MAAM,KAAG,MAAM;sCAElB,MAAM,QAAQ,MAAM,KAAG,MAAM;6BAgBtC;QACrC,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,KAAG,MAAM;kCAQkC,OAAO,KAAG,KAAK,IAAI,MAAM;iCAM1B;QACzC,EAAE,CAAC,EAAE,OAAO,CAAC;QACb,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,KAAG,MAAM;oCAOoC,OAAO,KAAG,KAAK,IAAI,oBAAoB;sCAwBrC,OAAO,KAAG,aAAa,CAAC,oBAAoB,CAAC;2CAYxC,OAAO,KAAG,oBAAoB,GAAG,SAAS;2CAe1C,OAAO,KAAG,oBAAoB;yCAgBtE,MAAM,eACJ,MAAM,aACR,aAAa,CAAC,MAAM,CAAC,KAC/B,OAAO;;AAKV,wBAWG"}
|
|
@@ -46,6 +46,10 @@ export const isServiceManifestEntry = (value) => {
|
|
|
46
46
|
if (prefix !== undefined && typeof prefix !== 'string') {
|
|
47
47
|
return false;
|
|
48
48
|
}
|
|
49
|
+
const configRoot = value['configRoot'];
|
|
50
|
+
if (configRoot !== undefined && typeof configRoot !== 'string') {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
49
53
|
const loadRoutes = value['loadRoutes'];
|
|
50
54
|
if (loadRoutes !== undefined && !isFunction(loadRoutes)) {
|
|
51
55
|
return false;
|
|
@@ -59,6 +63,7 @@ export const normalizeServiceManifest = (value) => {
|
|
|
59
63
|
...entry,
|
|
60
64
|
id: toCanonicalServiceId(entry),
|
|
61
65
|
prefix: getServicePrefix(entry),
|
|
66
|
+
...(isNonEmptyString(entry.configRoot) ? { configRoot: entry.configRoot } : {}),
|
|
62
67
|
monolithEnabled: entry.monolithEnabled !== false,
|
|
63
68
|
}));
|
|
64
69
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Database.d.ts","sourceRoot":"","sources":["../../../src/orm/Database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"Database.d.ts","sourceRoot":"","sources":["../../../src/orm/Database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAYxD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,WAAW,SAAS;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACjF,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrF,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACzE,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1F,cAAc,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1E,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3F,kBAAkB,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACvD,OAAO,IAAI,eAAe,CAAC;IAC3B,SAAS,IAAI,cAAc,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AAqhBD,eAAO,MAAM,QAAQ;IACnB;;OAEG;oBACa,cAAc,GAAG,SAAS;EAI1C,CAAC;AAIH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,cAAc,GAAG,SAAqB,EAC9C,uBAA0B,KACzB,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAMxC,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,UAAU,SAAY,GAAG,SAAS,CAsBtF;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAYnD"}
|
package/src/orm/Database.js
CHANGED
|
@@ -12,6 +12,7 @@ import { D1Adapter } from './adapters/D1Adapter.js';
|
|
|
12
12
|
import { D1RemoteAdapter } from './adapters/D1RemoteAdapter.js';
|
|
13
13
|
import { MySQLAdapter } from './adapters/MySQLAdapter.js';
|
|
14
14
|
import { MySQLProxyAdapter } from './adapters/MySQLProxyAdapter.js';
|
|
15
|
+
import { DatabaseConnectionRegistry } from './DatabaseConnectionRegistry.js';
|
|
15
16
|
import { PostgreSQLAdapter } from './adapters/PostgreSQLAdapter.js';
|
|
16
17
|
import { PostgreSQLProxyAdapter } from './adapters/PostgreSQLProxyAdapter.js';
|
|
17
18
|
import { SQLiteAdapter } from './adapters/SQLiteAdapter.js';
|
|
@@ -432,14 +433,15 @@ export const useEnsureDbConnected = async (config = undefined, connectionName =
|
|
|
432
433
|
};
|
|
433
434
|
export function useDatabase(config, connection = 'default') {
|
|
434
435
|
if (databaseInstances.has(connection) === false) {
|
|
435
|
-
|
|
436
|
+
const resolvedConfig = config ?? DatabaseConnectionRegistry.get(connection);
|
|
437
|
+
if (resolvedConfig === undefined) {
|
|
436
438
|
// Diagnostic logging
|
|
437
439
|
Logger.error('[DEBUG] Database instances keys:', Array.from(databaseInstances.keys()));
|
|
438
440
|
Logger.error('[DEBUG] Requesting connection:', connection);
|
|
439
441
|
throw ErrorFactory.createConfigError(`Database connection '${connection}' is not registered. ` +
|
|
440
442
|
`Call useDatabase(config, '${connection}') during startup to register it.`);
|
|
441
443
|
}
|
|
442
|
-
databaseInstances.set(connection, Database.create(
|
|
444
|
+
databaseInstances.set(connection, Database.create(resolvedConfig));
|
|
443
445
|
}
|
|
444
446
|
const instance = databaseInstances.get(connection);
|
|
445
447
|
if (instance === undefined) {
|
|
@@ -459,4 +461,5 @@ export async function resetDatabase() {
|
|
|
459
461
|
});
|
|
460
462
|
await Promise.all(promises);
|
|
461
463
|
databaseInstances.clear();
|
|
464
|
+
DatabaseConnectionRegistry.clear();
|
|
462
465
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DatabaseConfig } from './DatabaseAdapter';
|
|
2
|
+
export declare const DatabaseConnectionRegistry: Readonly<{
|
|
3
|
+
clear(): void;
|
|
4
|
+
set(name: string, config: DatabaseConfig): void;
|
|
5
|
+
get(name: string): DatabaseConfig | undefined;
|
|
6
|
+
}>;
|
|
7
|
+
export default DatabaseConnectionRegistry;
|
|
8
|
+
//# sourceMappingURL=DatabaseConnectionRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseConnectionRegistry.d.ts","sourceRoot":"","sources":["../../../src/orm/DatabaseConnectionRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,eAAO,MAAM,0BAA0B;aAC5B,IAAI;cAIH,MAAM,UAAU,cAAc,GAAG,IAAI;cAIrC,MAAM,GAAG,cAAc,GAAG,SAAS;EAG7C,CAAC;AAEH,eAAe,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const state = new Map();
|
|
2
|
+
export const DatabaseConnectionRegistry = Object.freeze({
|
|
3
|
+
clear() {
|
|
4
|
+
state.clear();
|
|
5
|
+
},
|
|
6
|
+
set(name, config) {
|
|
7
|
+
state.set(name, config);
|
|
8
|
+
},
|
|
9
|
+
get(name) {
|
|
10
|
+
return state.get(name);
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
export default DatabaseConnectionRegistry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseRuntimeRegistration.d.ts","sourceRoot":"","sources":["../../../src/orm/DatabaseRuntimeRegistration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"DatabaseRuntimeRegistration.d.ts","sourceRoot":"","sources":["../../../src/orm/DatabaseRuntimeRegistration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,cAAc,CAAC;AA4DtB;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAapF"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* instances that can be selected via `useDatabase(undefined, name)`.
|
|
6
6
|
*/
|
|
7
7
|
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
8
|
+
import { DatabaseConnectionRegistry } from './DatabaseConnectionRegistry.js';
|
|
8
9
|
import { useDatabase } from './Database.js';
|
|
9
10
|
const toOrmConfig = (cfg) => {
|
|
10
11
|
switch (cfg.driver) {
|
|
@@ -50,9 +51,9 @@ const toOrmConfig = (cfg) => {
|
|
|
50
51
|
}
|
|
51
52
|
};
|
|
52
53
|
const registerConnections = (connections) => {
|
|
54
|
+
DatabaseConnectionRegistry.clear();
|
|
53
55
|
for (const [name, runtimeCfg] of Object.entries(connections)) {
|
|
54
|
-
|
|
55
|
-
useDatabase(toOrmConfig(runtimeCfg), name);
|
|
56
|
+
DatabaseConnectionRegistry.set(name, toOrmConfig(runtimeCfg));
|
|
56
57
|
}
|
|
57
58
|
};
|
|
58
59
|
import { Logger } from '../config/logger.js';
|
|
@@ -71,5 +72,6 @@ export function registerDatabasesFromRuntimeConfig(config) {
|
|
|
71
72
|
throw ErrorFactory.createConfigError(`Database default connection not configured: ${String(config.default ?? '')}`);
|
|
72
73
|
}
|
|
73
74
|
Logger.info(`✓ Registering default database connection: ${config.default}`);
|
|
75
|
+
useDatabase(toOrmConfig(defaultCfg), config.default);
|
|
74
76
|
useDatabase(toOrmConfig(defaultCfg), 'default');
|
|
75
77
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectBootstrap.d.ts","sourceRoot":"","sources":["../../../src/runtime/ProjectBootstrap.ts"],"names":[],"mappings":"AAgCA,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAU1D;;;;AAED,wBAEG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Logger } from '../config/logger.js';
|
|
2
|
+
import { existsSync } from '../node-singletons/fs.js';
|
|
3
|
+
import * as path from '../node-singletons/path.js';
|
|
4
|
+
import { pathToFileURL } from '../node-singletons/url.js';
|
|
5
|
+
const getProjectRoot = () => {
|
|
6
|
+
const fromEnv = process.env?.['ZINTRUST_PROJECT_ROOT'] ?? '';
|
|
7
|
+
if (fromEnv.trim() !== '')
|
|
8
|
+
return fromEnv.trim();
|
|
9
|
+
return process.cwd();
|
|
10
|
+
};
|
|
11
|
+
const getBootstrapCandidates = (projectRoot) => [
|
|
12
|
+
path.join(projectRoot, 'src', 'boot', 'bootstrap.ts'),
|
|
13
|
+
path.join(projectRoot, 'dist', 'src', 'boot', 'bootstrap.js'),
|
|
14
|
+
path.join(projectRoot, 'src', 'boot', 'bootstrap.js'),
|
|
15
|
+
];
|
|
16
|
+
const tryImportBootstrapCandidate = async (candidate) => {
|
|
17
|
+
if (!existsSync(candidate))
|
|
18
|
+
return false;
|
|
19
|
+
try {
|
|
20
|
+
await import(pathToFileURL(candidate).href);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
Logger.warn('Failed to import project bootstrap candidate', {
|
|
25
|
+
candidate,
|
|
26
|
+
error: error instanceof Error ? error.message : String(error),
|
|
27
|
+
});
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
export async function loadProjectBootstrap() {
|
|
32
|
+
const projectRoot = getProjectRoot();
|
|
33
|
+
for (const candidate of getBootstrapCandidates(projectRoot)) {
|
|
34
|
+
// eslint-disable-next-line no-await-in-loop
|
|
35
|
+
const loaded = await tryImportBootstrapCandidate(candidate);
|
|
36
|
+
if (loaded)
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await import('../boot/bootstrap.js');
|
|
40
|
+
}
|
|
41
|
+
export default Object.freeze({
|
|
42
|
+
loadProjectBootstrap,
|
|
43
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtime/ProjectRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ProjectRuntime.d.ts","sourceRoot":"","sources":["../../../src/runtime/ProjectRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;AA+ExC,eAAO,MAAM,cAAc;aAChB,IAAI;iBAIA,oBAAoB,GAAG,SAAS;gBAIjC,OAAO,GAAG,oBAAoB;oCAIV,OAAO,GAAG,oBAAoB,GAAG,SAAS;0BAM9C,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;4BAgBvC,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;0BAejD,aAAa,CAAC,oBAAoB,CAAC;wBAIrC,oBAAoB,GAAG,SAAS;EAGpD,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -33,6 +33,9 @@ const cacheProjectRuntime = (module) => {
|
|
|
33
33
|
const getCachedProjectRuntime = () => {
|
|
34
34
|
return getRuntimeGlobal().__zintrustProjectRuntime;
|
|
35
35
|
};
|
|
36
|
+
const hasLoadedServiceManifest = (runtime) => {
|
|
37
|
+
return Array.isArray(runtime?.serviceManifest);
|
|
38
|
+
};
|
|
36
39
|
const tryImportNodeRuntimeCandidate = async (candidate) => {
|
|
37
40
|
if (!existsSync(candidate))
|
|
38
41
|
return undefined;
|
|
@@ -76,7 +79,7 @@ export const ProjectRuntime = Object.freeze({
|
|
|
76
79
|
},
|
|
77
80
|
async tryLoadNodeRuntime() {
|
|
78
81
|
const cached = getCachedProjectRuntime();
|
|
79
|
-
if (cached
|
|
82
|
+
if (hasLoadedServiceManifest(cached))
|
|
80
83
|
return cached;
|
|
81
84
|
const projectRoot = getProjectRoot();
|
|
82
85
|
const candidates = getNodeRuntimeCandidates(projectRoot);
|
|
@@ -90,7 +93,7 @@ export const ProjectRuntime = Object.freeze({
|
|
|
90
93
|
},
|
|
91
94
|
async tryLoadWorkerRuntime() {
|
|
92
95
|
const cached = getCachedProjectRuntime();
|
|
93
|
-
if (cached
|
|
96
|
+
if (hasLoadedServiceManifest(cached))
|
|
94
97
|
return cached;
|
|
95
98
|
const workerModuleIds = ['../' + 'zintrust.runtime.wg.js', '../' + 'zintrust.runtime.js'];
|
|
96
99
|
for (const moduleId of workerModuleIds) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudflareAdapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/adapters/CloudflareAdapter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,aAAa,EAGb,cAAc,EACf,MAAM,yBAAyB,CAAC;AAGjC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;IAC5B;;OAEG;mBACY,aAAa,GAAG,cAAc;
|
|
1
|
+
{"version":3,"file":"CloudflareAdapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/adapters/CloudflareAdapter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,aAAa,EAGb,cAAc,EACf,MAAM,yBAAyB,CAAC;AAGjC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;IAC5B;;OAEG;mBACY,aAAa,GAAG,cAAc;IA8D7C;;;OAGG;qBACc,OAAO;IAKxB;;;OAGG;qBACc,MAAM,GAAG,OAAO;EAIjC,CAAC;AAiKH;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,OAAO;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACjC,EAAE,CAAC,EAAE;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { appConfig } from '../../config/index.js';
|
|
5
5
|
import { isUndefinedOrNull } from '../../helper/index.js';
|
|
6
6
|
import { Cloudflare } from '../../config/cloudflare.js';
|
|
7
|
-
import { Env } from '../../config/env.js';
|
|
7
|
+
import { Env, getProcessLike } from '../../config/env.js';
|
|
8
8
|
import { Logger } from '../../config/logger.js';
|
|
9
9
|
import { createMockHttpObjects, ErrorResponse, HttpResponse } from '../RuntimeAdapter.js';
|
|
10
10
|
/**
|
|
@@ -19,7 +19,13 @@ export const CloudflareAdapter = Object.freeze({
|
|
|
19
19
|
create(config) {
|
|
20
20
|
const workersEnv = Cloudflare.getWorkersEnv();
|
|
21
21
|
if (workersEnv !== null) {
|
|
22
|
-
|
|
22
|
+
const processEnv = getProcessLike()?.env;
|
|
23
|
+
const resolveEnvSource = () => {
|
|
24
|
+
if (processEnv === undefined)
|
|
25
|
+
return workersEnv;
|
|
26
|
+
return { ...processEnv, ...workersEnv };
|
|
27
|
+
};
|
|
28
|
+
Env.setSource(resolveEnvSource);
|
|
23
29
|
}
|
|
24
30
|
const logger = config.logger ?? createDefaultLogger();
|
|
25
31
|
return {
|
package/src/start.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/start.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;AAuBxC,eAAO,MAAM,UAAU,GAAI,eAAe,MAAM,KAAG,OAYlD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,eAAe,OAAO,KAAG,oBASnE,CAAC;AAqFF,eAAO,MAAM,qBAAqB,GAChC,eAAe,MAAM,EACrB,eAAe,OAAO,KACrB,OAAO,CAAC,oBAAoB,CAS9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,IAAI,CAO1C,CAAC;AAEF;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEpE;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElD;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
|
package/src/start.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ErrorFactory } from './exceptions/ZintrustError.js';
|
|
2
|
+
import { isArray, isNonEmptyString, isObject } from './helper/index.js';
|
|
2
3
|
import { ZintrustLang } from './lang/lang.js';
|
|
3
4
|
import { normalizeActiveServiceRuntime, } from './microservices/ServiceManifest.js';
|
|
4
5
|
import { ProjectRuntime } from './runtime/ProjectRuntime.js';
|
|
5
6
|
import { isNodeRuntime } from './runtime/detectRuntime.js';
|
|
7
|
+
const isAbsolutePath = (value) => value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
|
|
6
8
|
const fileUrlToPathLike = (value) => {
|
|
7
9
|
if (!value.startsWith(ZintrustLang.FILE_PROTOCOL))
|
|
8
10
|
return value;
|
|
@@ -34,7 +36,68 @@ export const configureStandaloneService = (activeService) => {
|
|
|
34
36
|
}
|
|
35
37
|
return ProjectRuntime.set({ activeService: normalized }).activeService ?? normalized;
|
|
36
38
|
};
|
|
39
|
+
const normalizeStandaloneEnvPaths = (value) => {
|
|
40
|
+
if (isNonEmptyString(value)) {
|
|
41
|
+
const trimmed = value.trim();
|
|
42
|
+
return trimmed === '' ? [] : [trimmed];
|
|
43
|
+
}
|
|
44
|
+
if (!isArray(value))
|
|
45
|
+
return [];
|
|
46
|
+
return value
|
|
47
|
+
.filter(isNonEmptyString)
|
|
48
|
+
.map((item) => item.trim())
|
|
49
|
+
.filter((item) => item !== '');
|
|
50
|
+
};
|
|
51
|
+
const resolveStandaloneProjectRoot = async () => {
|
|
52
|
+
const configuredRoot = process.env?.['ZINTRUST_PROJECT_ROOT'] ?? '';
|
|
53
|
+
if (isNonEmptyString(configuredRoot))
|
|
54
|
+
return configuredRoot;
|
|
55
|
+
const { existsSync } = await import('./node-singletons/fs.js');
|
|
56
|
+
const path = await import('./node-singletons/path.js');
|
|
57
|
+
let current = process.cwd();
|
|
58
|
+
while (true) {
|
|
59
|
+
if (existsSync(path.join(current, 'package.json')))
|
|
60
|
+
return current;
|
|
61
|
+
const parent = path.dirname(current);
|
|
62
|
+
if (parent === current)
|
|
63
|
+
return process.cwd();
|
|
64
|
+
current = parent;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const resolveServiceEnvPath = async (importMetaUrl, activeService, projectRoot) => {
|
|
68
|
+
const path = await import('./node-singletons/path.js');
|
|
69
|
+
if (isObject(activeService) && isNonEmptyString(activeService['configRoot'])) {
|
|
70
|
+
return path.dirname(path.join(projectRoot, activeService['configRoot']));
|
|
71
|
+
}
|
|
72
|
+
const entryFile = fileUrlToPathLike(importMetaUrl);
|
|
73
|
+
const entryDir = path.dirname(entryFile);
|
|
74
|
+
return path.basename(entryDir) === 'src' ? path.dirname(entryDir) : entryDir;
|
|
75
|
+
};
|
|
76
|
+
const resolveConfiguredEnvPaths = async (projectRoot, activeService, importMetaUrl) => {
|
|
77
|
+
const path = await import('./node-singletons/path.js');
|
|
78
|
+
const configured = isObject(activeService)
|
|
79
|
+
? normalizeStandaloneEnvPaths(activeService['envPath'])
|
|
80
|
+
: [];
|
|
81
|
+
if (configured.length > 0) {
|
|
82
|
+
return configured.map((value) => isAbsolutePath(value) ? value : path.join(projectRoot, value));
|
|
83
|
+
}
|
|
84
|
+
return [await resolveServiceEnvPath(importMetaUrl, activeService, projectRoot)];
|
|
85
|
+
};
|
|
86
|
+
const ensureStandaloneServiceEnv = async (importMetaUrl, activeService) => {
|
|
87
|
+
if (!isNodeRuntime())
|
|
88
|
+
return;
|
|
89
|
+
const { EnvFileLoader } = await import('./cli/utils/EnvFileLoader.js');
|
|
90
|
+
const projectRoot = await resolveStandaloneProjectRoot();
|
|
91
|
+
const envPaths = await resolveConfiguredEnvPaths(projectRoot, activeService, importMetaUrl);
|
|
92
|
+
const rootEnv = !isObject(activeService) || activeService['rootEnv'] !== false;
|
|
93
|
+
EnvFileLoader.ensureLoaded({
|
|
94
|
+
cwd: projectRoot,
|
|
95
|
+
includeCwd: rootEnv,
|
|
96
|
+
envPaths,
|
|
97
|
+
});
|
|
98
|
+
};
|
|
37
99
|
export const bootStandaloneService = async (importMetaUrl, activeService) => {
|
|
100
|
+
await ensureStandaloneServiceEnv(importMetaUrl, activeService);
|
|
38
101
|
const configuredService = configureStandaloneService(activeService);
|
|
39
102
|
if (isNodeMain(importMetaUrl)) {
|
|
40
103
|
await start();
|
|
@@ -49,10 +112,8 @@ export const bootStandaloneService = async (importMetaUrl, activeService) => {
|
|
|
49
112
|
export const start = async () => {
|
|
50
113
|
if (!isNodeRuntime())
|
|
51
114
|
return;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// In unit tests, importing bootstrap has heavy side effects (starts server + exits).
|
|
55
|
-
await import('./boot/bootstrap.js');
|
|
115
|
+
const projectBootstrapModule = (await import('./runtime/ProjectBootstrap.js'));
|
|
116
|
+
await projectBootstrapModule.loadProjectBootstrap();
|
|
56
117
|
};
|
|
57
118
|
/**
|
|
58
119
|
* Cloudflare Workers entry (module worker style).
|