@zintrust/core 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -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;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
+ {"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;AA4FF,eAAO,MAAM,oBAAoB,GAC/B,kBAAkB,MAAM,EACxB,QAAQ,OAAO,KACd,OAAO,CAAC,IAAI,CAoBd,CAAC"}
@@ -64,6 +64,7 @@ const registerAppRoutes = async (resolvedBasePath, router) => {
64
64
  }
65
65
  };
66
66
  const registerManifestRoutes = async (router) => {
67
+ await ProjectRuntime.tryLoadNodeRuntime();
67
68
  const serviceManifest = ProjectRuntime.getServiceManifest();
68
69
  if (serviceManifest.length === 0)
69
70
  return;
@@ -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;AAgtBvF,eAAO,MAAM,YAAY;cACb,YAAY;EA6BtB,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;AAmvBvF,eAAO,MAAM,YAAY;cACb,YAAY;EAmCtB,CAAC"}
@@ -7,6 +7,7 @@ import * as Common from '../../common/index.js';
7
7
  import { ErrorFactory } from '../../exceptions/ZintrustError.js';
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from '../../node-singletons/fs.js';
9
9
  import * as path from '../../node-singletons/path.js';
10
+ const isAbsolutePath = (value) => value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
10
11
  const resolveNpmPath = () => {
11
12
  try {
12
13
  return typeof Common.resolveNpmPath === 'function' ? Common.resolveNpmPath() : 'npm';
@@ -168,6 +169,26 @@ const resolveCacheEnabledPreference = (options) => {
168
169
  return options.cache;
169
170
  return undefined;
170
171
  };
172
+ const resolveRootEnvPreference = (options) => {
173
+ const hasRootEnv = hasFlag('--root-env');
174
+ const hasNoRootEnv = hasFlag('--no-root-env');
175
+ if (hasRootEnv && hasNoRootEnv) {
176
+ throw ErrorFactory.createCliError('Error: Cannot use both --root-env and --no-root-env.');
177
+ }
178
+ if (hasRootEnv)
179
+ return true;
180
+ if (hasNoRootEnv)
181
+ return false;
182
+ if (typeof options.rootEnv === 'boolean')
183
+ return options.rootEnv;
184
+ return true;
185
+ };
186
+ const resolveEnvPath = (options, projectRoot) => {
187
+ const raw = typeof options.envPath === 'string' ? options.envPath.trim() : '';
188
+ if (raw === '')
189
+ return undefined;
190
+ return isAbsolutePath(raw) ? raw : path.join(projectRoot, raw);
191
+ };
171
192
  const findNearestPackageJsonDir = (cwd) => {
172
193
  let current = path.resolve(cwd);
173
194
  while (true) {
@@ -210,9 +231,16 @@ const buildStartEnv = (projectRoot) => ({
210
231
  ...process.env,
211
232
  ZINTRUST_PROJECT_ROOT: projectRoot,
212
233
  });
213
- const ensureStartEnvLoaded = (context) => {
214
- const extraCwds = context.cwd === context.projectRoot ? [] : [context.cwd];
215
- EnvFileLoader.ensureLoaded({ cwd: context.projectRoot, extraCwds });
234
+ const ensureStartEnvLoaded = (context, options) => {
235
+ const envPath = resolveEnvPath(options, context.projectRoot);
236
+ const rootEnv = resolveRootEnvPreference(options);
237
+ const extraCwds = envPath === undefined && context.cwd !== context.projectRoot ? [context.cwd] : [];
238
+ EnvFileLoader.ensureLoaded({
239
+ cwd: context.projectRoot,
240
+ includeCwd: rootEnv,
241
+ extraCwds,
242
+ ...(envPath === undefined ? {} : { envPaths: [envPath] }),
243
+ });
216
244
  };
217
245
  const isFrameworkRepo = (packageJson) => packageJson.name === '@zintrust/core';
218
246
  const hasDevScript = (packageJson) => {
@@ -483,7 +511,7 @@ const executeSplitStart = async (cmd, context, _options) => {
483
511
  const executeStart = async (options, cmd) => {
484
512
  const cwd = process.cwd();
485
513
  const context = resolveStartContext(cwd);
486
- ensureStartEnvLoaded(context);
514
+ ensureStartEnvLoaded(context, options);
487
515
  const mode = resolveMode(options);
488
516
  const port = resolvePort(options);
489
517
  const runtime = resolveRuntime(options);
@@ -541,8 +569,11 @@ export const StartCommand = Object.freeze({
541
569
  .option('--no-cache', 'Disable cache functionality')
542
570
  .option('--watch', 'Force watch mode (Node only)')
543
571
  .option('--no-watch', 'Disable watch mode (Node only)')
572
+ .option('--root-env', 'Load root project .env files for standalone service start')
573
+ .option('--no-root-env', 'Skip root project .env files for standalone service start')
544
574
  .option('--mode <development|production|testing>', 'Override app mode')
545
575
  .option('--env <name>', 'Wrangler environment name (Wrangler mode only)')
576
+ .option('--env-path <path>', 'Explicit env directory or .env file path for standalone service start')
546
577
  .option('--wrangler-config <path>', 'Wrangler config path (Wrangler mode only)')
547
578
  .option('--runtime <nodejs|cloudflare|lambda|deno|auto>', 'Set RUNTIME for spawned Node')
548
579
  .option('-p, --port <number>', 'Override server port');
@@ -1,7 +1,9 @@
1
1
  type node_env = 'development' | 'production' | 'testing';
2
2
  type LoadOptions = {
3
3
  cwd?: string;
4
+ includeCwd?: boolean;
4
5
  extraCwds?: string[];
6
+ envPaths?: string[];
5
7
  overrideExisting?: boolean;
6
8
  };
7
9
  type LoadState = {
@@ -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,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"}
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 { join } from '../../node-singletons/path.js';
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 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
- : [];
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 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 };
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/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @zintrust/core v0.4.11
2
+ * @zintrust/core v0.4.13
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-23T13:29:47.237Z
8
+ * Built: 2026-03-23T14:57:40.299Z
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-23T13:29:47.153Z'; // Replaced during build
24
+ export const ZINTRUST_BUILD_DATE = '2026-03-23T14:57:40.266Z'; // 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":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEzF,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAuJN,eAAO,MAAM,iBAAiB;uCACY,uBAAuB,GAAY,OAAO,CAAC,YAAY,CAAC;IAkBhG;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;qCAkEnB,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;EAavE,CAAC"}
1
+ {"version":3,"file":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEzF,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AA6MN,eAAO,MAAM,iBAAiB;uCACY,uBAAuB,GAAY,OAAO,CAAC,YAAY,CAAC;IAkBhG;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;qCAkEnB,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;EAavE,CAAC"}
@@ -94,6 +94,47 @@ const resolveLocalPackageSpecifier = (specifier) => {
94
94
  return null;
95
95
  return pathToFileURL(resolved).href;
96
96
  };
97
+ const isMissingPackageImport = (error, specifier) => {
98
+ if (specifier.startsWith('.'))
99
+ return false;
100
+ if (error === null || typeof error !== 'object')
101
+ return false;
102
+ const maybe = error;
103
+ const message = typeof maybe.message === 'string' ? maybe.message : '';
104
+ if (maybe.code === 'ERR_MODULE_NOT_FOUND' && message.length === 0)
105
+ return true;
106
+ if (maybe.code === 'ERR_MODULE_NOT_FOUND' && message.includes(specifier))
107
+ return true;
108
+ return (message.includes(`Cannot find package '${specifier}'`) ||
109
+ message.includes(`Cannot find module '${specifier}'`));
110
+ };
111
+ const getMissingPackageStatus = (error, specifier) => {
112
+ if (isMissingPackageImport(error, specifier)) {
113
+ Logger.debug('[plugins] Optional auto-import package not installed', {
114
+ specifier,
115
+ });
116
+ return 'missing';
117
+ }
118
+ return 'failed';
119
+ };
120
+ const importFromLocalFallback = async (specifier, fallback) => {
121
+ try {
122
+ await import(fallback);
123
+ Logger.debug('[plugins] Loaded auto-import specifier from local fallback', {
124
+ specifier,
125
+ fallback,
126
+ });
127
+ return 'loaded';
128
+ }
129
+ catch (fallbackError) {
130
+ Logger.debug('[plugins] Failed auto-import local fallback', {
131
+ specifier,
132
+ fallback,
133
+ error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError),
134
+ });
135
+ return getMissingPackageStatus(fallbackError, specifier);
136
+ }
137
+ };
97
138
  const importSingleSpecifier = async (entry) => {
98
139
  const target = entry.specifier.startsWith('.')
99
140
  ? resolveRelativeSpecifier(entry)
@@ -101,52 +142,48 @@ const importSingleSpecifier = async (entry) => {
101
142
  try {
102
143
  await import(target);
103
144
  Logger.debug('[plugins] Loaded auto-import specifier', { specifier: entry.specifier });
104
- return true;
145
+ return 'loaded';
105
146
  }
106
- catch {
147
+ catch (error) {
107
148
  const fallback = resolveLocalPackageSpecifier(entry.specifier);
108
- if (fallback !== null) {
109
- try {
110
- await import(fallback);
111
- Logger.debug('[plugins] Loaded auto-import specifier from local fallback', {
112
- specifier: entry.specifier,
113
- fallback,
114
- });
115
- return true;
116
- }
117
- catch (fallbackError) {
118
- Logger.debug('[plugins] Failed auto-import local fallback', {
119
- specifier: entry.specifier,
120
- fallback,
121
- error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError),
122
- });
123
- }
124
- }
125
- return false;
149
+ if (fallback !== null)
150
+ return importFromLocalFallback(entry.specifier, fallback);
151
+ return getMissingPackageStatus(error, entry.specifier);
126
152
  }
127
153
  };
128
154
  const importSpecifiers = async (specifiers) => {
129
155
  // Import all specifiers in parallel
130
156
  const importPromises = Array.from(specifiers).map(async (entry) => {
131
- const success = await importSingleSpecifier(entry);
132
- return { specifier: entry.specifier, success };
157
+ const status = await importSingleSpecifier(entry);
158
+ return { specifier: entry.specifier, status };
133
159
  });
134
160
  const results = await Promise.allSettled(importPromises);
135
- // Count successful imports
136
- return results.filter((result) => result.status === 'fulfilled' && result.value.success).length;
161
+ return results.reduce((summary, result) => {
162
+ if (result.status !== 'fulfilled') {
163
+ summary.failed += 1;
164
+ return summary;
165
+ }
166
+ if (result.value.status === 'loaded')
167
+ summary.loaded += 1;
168
+ else if (result.value.status === 'missing')
169
+ summary.missing += 1;
170
+ else
171
+ summary.failed += 1;
172
+ return summary;
173
+ }, { loaded: 0, missing: 0, failed: 0 });
137
174
  };
138
175
  export const PluginAutoImports = Object.freeze({
139
176
  async tryImportRuntimeAutoImports(mode = 'base') {
140
177
  const specifiers = OfficialPlugins.getAutoImports(mode);
141
- const loaded = await importSpecifiers(specifiers.map((specifier) => ({ specifier, filePath: `official:${mode}` })));
142
- if (loaded === specifiers.length) {
178
+ const summary = await importSpecifiers(specifiers.map((specifier) => ({ specifier, filePath: `official:${mode}` })));
179
+ if (summary.failed === 0) {
143
180
  return { ok: true, loadedPath: `official:${mode}` };
144
181
  }
145
182
  return {
146
183
  ok: false,
147
184
  loadedPath: `official:${mode}`,
148
185
  reason: 'import-failed',
149
- errorMessage: `Loaded ${loaded}/${specifiers.length} official plugin imports`,
186
+ errorMessage: `Loaded ${summary.loaded}/${specifiers.length} official plugin imports`,
150
187
  };
151
188
  },
152
189
  /**
@@ -209,8 +246,8 @@ export const PluginAutoImports = Object.freeze({
209
246
  if (specifiers.length === 0) {
210
247
  return { ok: false, reason: 'import-failed', errorMessage: 'No import specifiers found' };
211
248
  }
212
- const loaded = await importSpecifiers(specifiers);
213
- if (loaded > 0) {
249
+ const summary = await importSpecifiers(specifiers);
250
+ if (summary.loaded > 0) {
214
251
  return { ok: true, loadedPath: 'manual-imports' };
215
252
  }
216
253
  return { ok: false, reason: 'import-failed', errorMessage: 'All specifier imports failed' };
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/start.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;AAexC,eAAO,MAAM,UAAU,GAAI,eAAe,MAAM,KAAG,OAYlD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,eAAe,OAAO,KAAG,oBASnE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,eAAe,MAAM,EACrB,eAAe,OAAO,KACrB,OAAO,CAAC,oBAAoB,CAQ9B,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"}
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();