@zintrust/core 0.7.2 → 0.7.7

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.7.2",
3
+ "version": "0.7.7",
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":"KVRemoteDriver.d.ts","sourceRoot":"","sources":["../../../../src/cache/drivers/KVRemoteDriver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA2YtD,eAAO,MAAM,cAAc;kBA5FM,WAAW;EA8F1C,CAAC;AAEH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"KVRemoteDriver.d.ts","sourceRoot":"","sources":["../../../../src/cache/drivers/KVRemoteDriver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6YtD,eAAO,MAAM,cAAc;kBAvEM,WAAW;EAyE1C,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -206,6 +206,25 @@ const createCloudflareKvApiClient = (resolveNamespaceId) => {
206
206
  };
207
207
  return { getJson, putJson, deleteKey };
208
208
  };
209
+ const logKvRemoteProxyFallback = (operation, error) => {
210
+ Logger.warn(`KV remote proxy ${operation} failed; falling back to Cloudflare KV API`, Logger.withTraceSkipContext({
211
+ error: error instanceof Error ? error.message : String(error),
212
+ }));
213
+ };
214
+ const clearKvRemoteDriver = async () => {
215
+ Logger.warn('KV remote clear() is not implemented.');
216
+ await Promise.resolve();
217
+ };
218
+ const createKvRemoteHas = (getJson) => {
219
+ return async function has(key) {
220
+ if (!hasCloudflareApiCreds())
221
+ return (await this.get(key)) !== null;
222
+ const settings = getSettings();
223
+ if (!hasProxySigningCreds(settings))
224
+ return (await getJson(key)) !== null;
225
+ return (await this.get(key)) !== null;
226
+ };
227
+ };
209
228
  const createKvRemoteDriver = () => {
210
229
  const resolveNamespaceId = createCloudflareNamespaceIdResolver();
211
230
  const cf = createCloudflareKvApiClient(resolveNamespaceId);
@@ -226,11 +245,7 @@ const createKvRemoteDriver = () => {
226
245
  catch (error) {
227
246
  if (!hasCloudflareApiCreds())
228
247
  throw error;
229
- Logger.warn('KV remote proxy GET failed; falling back to Cloudflare KV API', {
230
- ...Logger.withTraceSkipContext({
231
- error: error instanceof Error ? error.message : String(error),
232
- }),
233
- });
248
+ logKvRemoteProxyFallback('GET', error);
234
249
  return cf.getJson(key);
235
250
  }
236
251
  },
@@ -252,11 +267,7 @@ const createKvRemoteDriver = () => {
252
267
  catch (error) {
253
268
  if (!hasCloudflareApiCreds())
254
269
  throw error;
255
- Logger.warn('KV remote proxy PUT failed; falling back to Cloudflare KV API', {
256
- ...Logger.withTraceSkipContext({
257
- error: error instanceof Error ? error.message : String(error),
258
- }),
259
- });
270
+ logKvRemoteProxyFallback('PUT', error);
260
271
  await cf.putJson(key, value, ttl);
261
272
  }
262
273
  },
@@ -276,26 +287,12 @@ const createKvRemoteDriver = () => {
276
287
  catch (error) {
277
288
  if (!hasCloudflareApiCreds())
278
289
  throw error;
279
- Logger.warn('KV remote proxy DELETE failed; falling back to Cloudflare KV API', {
280
- ...Logger.withTraceSkipContext({
281
- error: error instanceof Error ? error.message : String(error),
282
- }),
283
- });
290
+ logKvRemoteProxyFallback('DELETE', error);
284
291
  await cf.deleteKey(key);
285
292
  }
286
293
  },
287
- async clear() {
288
- Logger.warn('KV remote clear() is not implemented.');
289
- await Promise.resolve();
290
- },
291
- async has(key) {
292
- if (!hasCloudflareApiCreds())
293
- return (await this.get(key)) !== null;
294
- const settings = getSettings();
295
- if (!hasProxySigningCreds(settings))
296
- return (await cf.getJson(key)) !== null;
297
- return (await this.get(key)) !== null;
298
- },
294
+ clear: clearKvRemoteDriver,
295
+ has: createKvRemoteHas(cf.getJson),
299
296
  };
300
297
  };
301
298
  export const KVRemoteDriver = Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"ScheduleCliSupport.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/schedule/ScheduleCliSupport.ts"],"names":[],"mappings":"AAsMA,eAAO,MAAM,kBAAkB;sCA1Ec,OAAO,CAAC,OAAO,CAAC;mBA4EtC,OAAO,CAAC,IAAI,CAAC;gCA3BG,OAAO,CAAC,IAAI,CAAC;EAqClD,CAAC;AAEH,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"ScheduleCliSupport.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/schedule/ScheduleCliSupport.ts"],"names":[],"mappings":"AAyNA,eAAO,MAAM,kBAAkB;sCAzEc,OAAO,CAAC,OAAO,CAAC;mBA2EtC,OAAO,CAAC,IAAI,CAAC;gCA3BG,OAAO,CAAC,IAAI,CAAC;EAqClD,CAAC;AAEH,eAAe,kBAAkB,CAAC"}
@@ -33,16 +33,33 @@ const getProjectSourceCliEntry = (projectRoot) => {
33
33
  }
34
34
  return undefined;
35
35
  };
36
- const isRunningProjectSourceCli = (projectRoot) => {
36
+ const getCurrentCliScript = () => {
37
37
  const script = String(process.argv[1] ?? '').trim();
38
38
  if (script.length === 0)
39
- return false;
39
+ return undefined;
40
40
  const resolvedScript = path.resolve(script);
41
+ return existsSync(resolvedScript) ? resolvedScript : undefined;
42
+ };
43
+ const isRunningProjectSourceCli = (projectRoot) => {
44
+ const resolvedScript = getCurrentCliScript();
45
+ if (resolvedScript === undefined)
46
+ return false;
41
47
  const sourceCliEntry = getProjectSourceCliEntry(projectRoot);
42
48
  if (sourceCliEntry === undefined)
43
49
  return false;
44
50
  return resolvedScript === path.resolve(sourceCliEntry);
45
51
  };
52
+ const getScheduleReentryScript = (projectRoot) => {
53
+ const sourceCliEntry = getProjectSourceCliEntry(projectRoot);
54
+ if (sourceCliEntry !== undefined) {
55
+ return path.relative(projectRoot, sourceCliEntry);
56
+ }
57
+ const currentCliScript = getCurrentCliScript();
58
+ if (currentCliScript === undefined)
59
+ return undefined;
60
+ const relativeCurrentScript = path.relative(projectRoot, currentCliScript);
61
+ return relativeCurrentScript.startsWith('..') ? currentCliScript : relativeCurrentScript;
62
+ };
46
63
  const getExistingProjectSchedulePath = () => {
47
64
  for (const loader of getProjectScheduleLoaders()) {
48
65
  if (loader.exists())
@@ -108,14 +125,13 @@ const ensureProjectSourceContext = async () => {
108
125
  if (isRunningProjectSourceCli(projectRoot)) {
109
126
  return false;
110
127
  }
111
- const sourceCliEntry = getProjectSourceCliEntry(projectRoot);
112
- if (sourceCliEntry === undefined) {
113
- throw ErrorFactory.createCliError('Source schedules require a project CLI entrypoint at bin/zin.ts or bin/zintrust.ts');
128
+ const reentryScript = getScheduleReentryScript(projectRoot);
129
+ if (reentryScript === undefined) {
130
+ throw ErrorFactory.createCliError('Source schedules require either a project CLI entrypoint at bin/zin.ts or bin/zintrust.ts, or a resolvable current CLI script.');
114
131
  }
115
- const relativeSourceCliEntry = path.relative(projectRoot, sourceCliEntry);
116
132
  const exitCode = await SpawnUtil.spawnAndWait({
117
133
  command: 'tsx',
118
- args: [relativeSourceCliEntry, ...process.argv.slice(2)],
134
+ args: [reentryScript, ...process.argv.slice(2)],
119
135
  cwd: projectRoot,
120
136
  env: {
121
137
  ...process.env,
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AA0kBD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsBrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAsBA;AA8ID;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAsB,GAAG,kBAAkB,CAsB/F;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
1
+ {"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AAumBD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsBrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAsBA;AAwJD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAsB,GAAG,kBAAkB,CAsB/F;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
@@ -7,6 +7,7 @@ import { EnvData } from '../scaffolding/env.js';
7
7
  import { extractMajorMinorVersion, toCompatibleGovernanceVersion, } from '../scaffolding/ScaffoldingVersionUtils.js';
8
8
  import { Logger } from '../../config/logger.js';
9
9
  import { ErrorFactory } from '../../exceptions/ZintrustError.js';
10
+ import { isNonEmptyString } from '../../helper/index.js';
10
11
  import { randomBytes } from '../../node-singletons/crypto.js';
11
12
  import fs from '../../node-singletons/fs.js';
12
13
  import * as path from '../../node-singletons/path.js';
@@ -24,11 +25,38 @@ const readBundledGovernancePackage = () => {
24
25
  const SAFE_PATH = '/usr/local/bin:/usr/bin:/bin';
25
26
  const NPM_VIEW_TIMEOUT_MS = 1500;
26
27
  const publishedVersionCache = new Map();
27
- const createSafeNpmEnv = () => ({
28
- ...process.env,
29
- NODE_ENV: process.env['NODE_ENV'] ?? 'development',
30
- PATH: SAFE_PATH,
31
- });
28
+ const SAFE_NPM_ENV_KEYS = Object.freeze([
29
+ 'HOME',
30
+ 'USERPROFILE',
31
+ 'APPDATA',
32
+ 'LOCALAPPDATA',
33
+ 'npm_config_userconfig',
34
+ 'npm_config_cache',
35
+ 'NPM_CONFIG_CACHE',
36
+ 'npm_config_registry',
37
+ 'NPM_CONFIG_REGISTRY',
38
+ 'HTTP_PROXY',
39
+ 'HTTPS_PROXY',
40
+ 'NO_PROXY',
41
+ 'http_proxy',
42
+ 'https_proxy',
43
+ 'no_proxy',
44
+ 'SSL_CERT_FILE',
45
+ 'NODE_EXTRA_CA_CERTS',
46
+ ]);
47
+ const createSafeNpmEnv = () => {
48
+ const env = {
49
+ NODE_ENV: process.env['NODE_ENV'] ?? 'development',
50
+ PATH: SAFE_PATH,
51
+ };
52
+ for (const key of SAFE_NPM_ENV_KEYS) {
53
+ const value = process.env[key];
54
+ if (isNonEmptyString(value)) {
55
+ env[key] = value;
56
+ }
57
+ }
58
+ return env;
59
+ };
32
60
  const loadPublishedNpmVersion = (packageName) => {
33
61
  if (publishedVersionCache.has(packageName)) {
34
62
  return publishedVersionCache.get(packageName);
@@ -563,6 +591,14 @@ const createDirectoriesForState = (state) => {
563
591
  const template = resolveTemplate(state.templateName);
564
592
  return createDirectories(state.projectPath, template?.directories ?? []);
565
593
  };
594
+ const canReuseExistingProjectPath = (projectPath) => {
595
+ try {
596
+ return fs.statSync(projectPath).isDirectory() && fs.readdirSync(projectPath).length === 0;
597
+ }
598
+ catch {
599
+ return false;
600
+ }
601
+ };
566
602
  const createFilesForState = (state) => {
567
603
  const template = resolveTemplate(state.templateName);
568
604
  const variables = state.variables;
@@ -622,9 +658,12 @@ const scaffoldWithState = async (state, options
622
658
  }
623
659
  prepareContext(state, options);
624
660
  if (fs.existsSync(state.projectPath)) {
625
- if (options.overwrite === true) {
661
+ if (options.overwrite === true || options.force === true) {
626
662
  fs.rmSync(state.projectPath, { recursive: true, force: true });
627
663
  }
664
+ else if (canReuseExistingProjectPath(state.projectPath)) {
665
+ Logger.info(`Reusing empty project directory: ${state.projectPath}`);
666
+ }
628
667
  else {
629
668
  return {
630
669
  success: false,
@@ -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;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA0CD,eAAO,MAAM,SAAS;wBACM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;EAiF7D,CAAC"}
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/spawn.ts"],"names":[],"mappings":"AAOA,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;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAiDD,eAAO,MAAM,SAAS;wBACM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;EAiF7D,CAAC"}
@@ -3,6 +3,7 @@ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
3
3
  import { spawn } from '../../node-singletons/child-process.js';
4
4
  import { existsSync } from '../../node-singletons/fs.js';
5
5
  import * as path from '../../node-singletons/path.js';
6
+ import { fileURLToPath } from '../../node-singletons/url.js';
6
7
  const getExitCode = (exitCode, signal) => {
7
8
  if (typeof exitCode === 'number')
8
9
  return exitCode;
@@ -10,22 +11,28 @@ const getExitCode = (exitCode, signal) => {
10
11
  return 0;
11
12
  return 1;
12
13
  };
14
+ const CURRENT_PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
15
+ const buildBinCandidates = (binDir, command) => process.platform === 'win32'
16
+ ? [
17
+ path.join(binDir, `${command}.cmd`),
18
+ path.join(binDir, `${command}.exe`),
19
+ path.join(binDir, `${command}.bat`),
20
+ path.join(binDir, command),
21
+ ]
22
+ : [path.join(binDir, command)];
13
23
  const resolveLocalBin = (command, cwd) => {
14
24
  // If command is already a path, leave it alone.
15
25
  if (command.includes('/') || command.includes('\\'))
16
26
  return command;
17
- const binDir = path.join(cwd, 'node_modules', '.bin');
18
- const candidates = process.platform === 'win32'
19
- ? [
20
- path.join(binDir, `${command}.cmd`),
21
- path.join(binDir, `${command}.exe`),
22
- path.join(binDir, `${command}.bat`),
23
- path.join(binDir, command),
24
- ]
25
- : [path.join(binDir, command)];
26
- for (const candidate of candidates) {
27
- if (existsSync(candidate))
28
- return candidate;
27
+ const binDirs = [
28
+ path.join(cwd, 'node_modules', '.bin'),
29
+ path.join(CURRENT_PACKAGE_ROOT, 'node_modules', '.bin'),
30
+ ].filter((value, index, items) => items.indexOf(value) === index);
31
+ for (const binDir of binDirs) {
32
+ for (const candidate of buildBinCandidates(binDir, command)) {
33
+ if (existsSync(candidate))
34
+ return candidate;
35
+ }
29
36
  }
30
37
  return command;
31
38
  };
@@ -34,7 +41,6 @@ const buildCommandNotFoundMessage = (command) => {
34
41
  return [
35
42
  "Error: 'tsx' not found on PATH.",
36
43
  '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
44
  ].join(' ');
39
45
  }
40
46
  return `Error: '${command}' not found on PATH.`;
@@ -6,23 +6,21 @@ interface ILogger {
6
6
  error(message: string, error?: unknown, category?: string): void;
7
7
  fatal(message: string, error?: unknown, category?: string): void;
8
8
  }
9
+ interface ILoggerNamespace extends ILogger {
10
+ cleanLogsOnce(): Promise<string[]>;
11
+ scope(scope: string): ILogger;
12
+ addSink(fn: LogSink): () => void;
13
+ withTraceSkipContext(context?: Record<string, unknown>): Record<string, unknown>;
14
+ shouldSkipTraceLogContext(context?: Record<string, unknown>): boolean;
15
+ }
9
16
  /**
10
17
  * External log sink. Receives every log line after the built-in sinks have fired.
11
18
  * Return value is ignored; errors are swallowed to protect the caller.
12
19
  */
13
20
  export type LogSink = (level: LogLevel, message: string, context?: Record<string, unknown>) => void;
21
+ export declare const withTraceSkipContext: (context?: Record<string, unknown>) => Record<string, unknown>;
22
+ export declare const shouldSkipTraceLogContext: (context?: Record<string, unknown>) => boolean;
14
23
  export declare const cleanLogsOnce: () => Promise<string[]>;
15
- export declare const Logger: Readonly<{
16
- debug: (message: string, data?: unknown, category?: string) => void;
17
- info: (message: string, data?: unknown, category?: string) => void;
18
- warn: (message: string, data?: unknown, category?: string) => void;
19
- error: (message: string, error?: unknown, category?: string) => void;
20
- fatal: (message: string, error?: unknown, category?: string) => void;
21
- cleanLogsOnce: () => Promise<string[]>;
22
- scope: (scope: string) => ILogger;
23
- addSink: (fn: LogSink) => (() => void);
24
- withTraceSkipContext: (context?: Record<string, unknown>) => Record<string, unknown>;
25
- shouldSkipTraceLogContext: (context?: Record<string, unknown>) => boolean;
26
- }>;
24
+ export declare const Logger: ILoggerNamespace;
27
25
  export default Logger;
28
26
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/config/logger.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,UAAU,OAAO;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClE;AAkzBD;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AA+CpG,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,MAAM,EAAE,CAYtD,CAAC;AAEF,eAAO,MAAM,MAAM;qBAxNQ,MAAM,SAAS,OAAO,aAAa,MAAM,KAAG,IAAI;oBAuBjD,MAAM,SAAS,OAAO,aAAa,MAAM,KAAG,IAAI;oBAuBhD,MAAM,SAAS,OAAO,aAAa,MAAM,KAAG,IAAI;qBAuB/C,MAAM,UAAU,OAAO,aAAa,MAAM,KAAG,IAAI;qBA6BjD,MAAM,UAAU,OAAO,aAAa,MAAM,KAAG,IAAI;yBAwGrC,OAAO,CAAC,MAAM,EAAE,CAAC;mBAvEtB,MAAM,KAAG,OAAO;kBA8D7B,OAAO,KAAG,CAAC,MAAM,IAAI,CAAC;qCAlCH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;0CAO5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAAO;EA6D5E,CAAC;AAEH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/config/logger.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,UAAU,OAAO;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClE;AAED,UAAU,gBAAiB,SAAQ,OAAO;IACxC,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,IAAI,CAAC;IACjC,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjF,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;CACvE;AAkzBD;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAIpG,eAAO,MAAM,oBAAoB,GAC/B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CASxB,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAE7E,CAAC;AAkCF,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,MAAM,EAAE,CAYtD,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,gBAWnB,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -741,13 +741,16 @@ const createLoggerScope = (scope) => {
741
741
  };
742
742
  };
743
743
  const TRACE_SKIP_LOG_CONTEXT_KEY = '__zintrustSkipTraceLog';
744
- const withTraceSkipContext = (context) => {
744
+ export const withTraceSkipContext = (context) => {
745
+ if (context === undefined) {
746
+ return { [TRACE_SKIP_LOG_CONTEXT_KEY]: true };
747
+ }
745
748
  return {
746
- ...(context ?? {}),
749
+ ...context,
747
750
  [TRACE_SKIP_LOG_CONTEXT_KEY]: true,
748
751
  };
749
752
  };
750
- const shouldSkipTraceLogContext = (context) => {
753
+ export const shouldSkipTraceLogContext = (context) => {
751
754
  return context?.[TRACE_SKIP_LOG_CONTEXT_KEY] === true;
752
755
  };
753
756
  const loggerSinks = [];
package/src/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @zintrust/core v0.7.2
2
+ * @zintrust/core v0.7.7
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-04-18T19:22:40.542Z
8
+ * Built: 2026-04-19T15:28:44.954Z
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-04-18T19:22:40.508Z'; // Replaced during build
24
+ export const ZINTRUST_BUILD_DATE = '2026-04-19T15:28:44.919Z'; // 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":"ProxyServerUtils.d.ts","sourceRoot":"","sources":["../../../src/proxy/ProxyServerUtils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAI7D,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,kBAAkB,EAC7B,QAAQ,MAAM,EACd,WAAW;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KACjE,eAUF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,WAAW,kBAAkB,EAC7B,QAAQ,MAAM,KACb;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CAOtB,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,KAAK,eAAe,EACpB,MAAM,MAAM,EACZ,QAAQ;IAAE,OAAO,EAAE,kBAAkB,CAAA;CAAE,EACvC,aAAa,MAAM,KAClB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAkCtE,CAAC"}
1
+ {"version":3,"file":"ProxyServerUtils.d.ts","sourceRoot":"","sources":["../../../src/proxy/ProxyServerUtils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAI7D,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC,CAAC;AAuCH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,kBAAkB,EAC7B,QAAQ,MAAM,EACd,WAAW;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KACjE,eAUF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,WAAW,kBAAkB,EAC7B,QAAQ,MAAM,KACb;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CAOtB,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,KAAK,eAAe,EACpB,MAAM,MAAM,EACZ,QAAQ;IAAE,OAAO,EAAE,kBAAkB,CAAA;CAAE,EACvC,aAAa,MAAM,KAClB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAoCtE,CAAC"}
@@ -1,7 +1,42 @@
1
1
  import { Env } from '../config/env.js';
2
2
  import { Logger } from '../config/logger.js';
3
+ import { isNonEmptyString } from '../helper/index.js';
3
4
  import { resolveProxySigningConfig } from './ProxySigningConfigResolver.js';
4
5
  import { extractSigningHeaders, verifyProxySignatureIfNeeded } from './ProxySigningRequest.js';
6
+ const PROXY_DEBUG_ENV_BY_SERVICE = Object.freeze({
7
+ MySQLProxyServer: 'MYSQL_PROXY_DEBUG',
8
+ PostgresProxyServer: 'POSTGRES_PROXY_DEBUG',
9
+ RedisProxyServer: 'REDIS_PROXY_DEBUG',
10
+ SqlServerProxyServer: 'SQLSERVER_PROXY_DEBUG',
11
+ });
12
+ const parseProxyDebugValue = (raw) => {
13
+ const normalized = raw.trim().toLowerCase();
14
+ if (normalized === 'true' || normalized === '1' || normalized === 'yes')
15
+ return true;
16
+ if (normalized === 'false' || normalized === '0' || normalized === 'no')
17
+ return false;
18
+ return undefined;
19
+ };
20
+ const resolveProxyDebugEnabled = (serviceName) => {
21
+ const serviceEnvKey = PROXY_DEBUG_ENV_BY_SERVICE[serviceName];
22
+ const serviceRaw = serviceEnvKey ? Env.get(serviceEnvKey, '') : '';
23
+ if (isNonEmptyString(serviceRaw)) {
24
+ const parsed = parseProxyDebugValue(serviceRaw);
25
+ if (parsed !== undefined)
26
+ return parsed;
27
+ }
28
+ const sharedRaw = Env.get('ZT_PROXY_DEBUG', '');
29
+ if (isNonEmptyString(sharedRaw)) {
30
+ const parsed = parseProxyDebugValue(sharedRaw);
31
+ if (parsed !== undefined)
32
+ return parsed;
33
+ }
34
+ return false;
35
+ };
36
+ const withTraceSkipProxyContext = (context) => ({
37
+ ...context,
38
+ __zintrustSkipTraceLog: true,
39
+ });
5
40
  export const resolveBaseConfig = (overrides, prefix, defaults) => {
6
41
  const host = overrides.host ?? Env.get(`${prefix}_PROXY_HOST`, Env.HOST ?? defaults?.host ?? '127.0.0.1');
7
42
  const port = overrides.port ?? Env.getInt(`${prefix}_PROXY_PORT`, Env.PORT ?? defaults?.port ?? 3000);
@@ -18,22 +53,24 @@ export const resolveBaseSigningConfig = (overrides, prefix) => resolveProxySigni
18
53
  export const verifyRequestSignature = async (req, body, config, serviceName) => {
19
54
  const headers = extractSigningHeaders(req);
20
55
  const hasAnySigningHeader = Object.values(headers).some((value) => typeof value === 'string' && value.trim() !== '');
21
- Logger.debug(`[${serviceName}] Verifying request signature`, {
22
- ...Logger.withTraceSkipContext({
23
- path: req.url ?? '',
24
- method: req.method ?? 'POST',
25
- requireSigning: config.signing.require,
26
- hasAnySigningHeader,
27
- configuredKeyId: config.signing.keyId,
28
- hasConfiguredSecret: config.signing.secret.trim() !== '',
29
- bodyBytes: body.length,
30
- }),
31
- });
56
+ if (resolveProxyDebugEnabled(serviceName)) {
57
+ Logger.debug(`[${serviceName}] Verifying request signature`, {
58
+ ...withTraceSkipProxyContext({
59
+ path: req.url ?? '',
60
+ method: req.method ?? 'POST',
61
+ requireSigning: config.signing.require,
62
+ hasAnySigningHeader,
63
+ configuredKeyId: config.signing.keyId,
64
+ hasConfiguredSecret: config.signing.secret.trim() !== '',
65
+ bodyBytes: body.length,
66
+ }),
67
+ });
68
+ }
32
69
  const verified = await verifyProxySignatureIfNeeded(req, body, config.signing);
33
70
  if (!verified.ok) {
34
71
  const error = verified.error ?? { status: 401, message: 'Unauthorized' };
35
72
  Logger.warn(`[${serviceName}] Signature verification failed`, {
36
- ...Logger.withTraceSkipContext({
73
+ ...withTraceSkipProxyContext({
37
74
  path: req.url ?? '',
38
75
  method: req.method ?? 'POST',
39
76
  status: error.status,