@zintrust/core 1.5.2 → 1.5.4
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/bin/z.js +35 -2
- package/bin/zin.js +35 -2
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +32 -6
- package/bin/zintrust.d.ts.map +1 -1
- package/bin/zintrust.js +35 -2
- package/bin/zt.js +22 -2
- package/package.json +1 -1
- package/src/boot/bootstrap.d.ts +1 -1
- package/src/boot/bootstrap.d.ts.map +1 -1
- package/src/boot/bootstrap.js +14 -9
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +1 -0
- package/src/cli/utils/spawn.d.ts +1 -0
- package/src/cli/utils/spawn.d.ts.map +1 -1
- package/src/cli/utils/spawn.js +74 -10
- package/src/config/index.d.ts +2 -1
- package/src/config/index.d.ts.map +1 -1
- package/src/config/index.js +3 -3
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +32 -3
- package/src/http/RequestContext.d.ts.map +1 -1
- package/src/http/RequestContext.js +6 -3
- package/src/index.js +3 -3
- package/src/migrations/schema/Schema.d.ts.map +1 -1
- package/src/migrations/schema/Schema.js +122 -5
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +9 -3
- package/src/runtime/WorkerAdapterImports.d.ts +2 -2
- package/src/runtime/WorkerAdapterImports.js +1 -1
- package/src/runtime/plugins/trace-runtime.d.ts.map +1 -1
- package/src/runtime/plugins/trace-runtime.js +2 -1
- package/src/runtime/plugins/trace.d.ts +1 -0
- package/src/runtime/plugins/trace.d.ts.map +1 -1
- package/src/runtime/plugins/trace.js +7 -5
- package/src/templates/project/basic/config/middleware.ts.tpl +3 -3
- package/src/zintrust.plugins.d.ts +6 -3
- package/src/zintrust.plugins.d.ts.map +1 -1
- package/src/zintrust.plugins.js +6 -3
package/bin/z.js
CHANGED
|
@@ -3,5 +3,38 @@
|
|
|
3
3
|
* ZinTrust CLI Shortcut - 'z'
|
|
4
4
|
* Mirrors bin/zintrust.ts for convenience
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const tsTarget = path.join(here, 'zintrust-main.ts');
|
|
14
|
+
const jsTarget = path.join(here, 'zintrust-main.js');
|
|
15
|
+
const target = existsSync(tsTarget) ? tsTarget : jsTarget;
|
|
16
|
+
const tsxImportPath = require.resolve('tsx');
|
|
17
|
+
const nodeArgs = target.endsWith('.ts')
|
|
18
|
+
? ['--import', tsxImportPath, target, ...process.argv.slice(2)]
|
|
19
|
+
: [target, ...process.argv.slice(2)];
|
|
20
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
env: process.env,
|
|
23
|
+
});
|
|
24
|
+
const result = await new Promise((resolve, reject) => {
|
|
25
|
+
let settled = false;
|
|
26
|
+
const finalize = (exitCode, signal) => {
|
|
27
|
+
if (settled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
settled = true;
|
|
31
|
+
child.off?.('error', reject);
|
|
32
|
+
child.off?.('exit', finalize);
|
|
33
|
+
child.off?.('close', finalize);
|
|
34
|
+
resolve({ exitCode, signal });
|
|
35
|
+
};
|
|
36
|
+
child.once('error', reject);
|
|
37
|
+
child.once('exit', finalize);
|
|
38
|
+
child.once('close', finalize);
|
|
39
|
+
});
|
|
40
|
+
process.exit(result.exitCode ?? (result.signal === 'SIGINT' || result.signal === 'SIGTERM' ? 0 : 1));
|
package/bin/zin.js
CHANGED
|
@@ -3,5 +3,38 @@
|
|
|
3
3
|
* ZinTrust CLI Shortcut - 'zin'
|
|
4
4
|
* Mirrors bin/zintrust.ts for convenience
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const tsTarget = path.join(here, 'zintrust-main.ts');
|
|
14
|
+
const jsTarget = path.join(here, 'zintrust-main.js');
|
|
15
|
+
const target = existsSync(tsTarget) ? tsTarget : jsTarget;
|
|
16
|
+
const tsxImportPath = require.resolve('tsx');
|
|
17
|
+
const nodeArgs = target.endsWith('.ts')
|
|
18
|
+
? ['--import', tsxImportPath, target, ...process.argv.slice(2)]
|
|
19
|
+
: [target, ...process.argv.slice(2)];
|
|
20
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
env: process.env,
|
|
23
|
+
});
|
|
24
|
+
const result = await new Promise((resolve, reject) => {
|
|
25
|
+
let settled = false;
|
|
26
|
+
const finalize = (exitCode, signal) => {
|
|
27
|
+
if (settled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
settled = true;
|
|
31
|
+
child.off?.('error', reject);
|
|
32
|
+
child.off?.('exit', finalize);
|
|
33
|
+
child.off?.('close', finalize);
|
|
34
|
+
resolve({ exitCode, signal });
|
|
35
|
+
};
|
|
36
|
+
child.once('error', reject);
|
|
37
|
+
child.once('exit', finalize);
|
|
38
|
+
child.once('close', finalize);
|
|
39
|
+
});
|
|
40
|
+
process.exit(result.exitCode ?? (result.signal === 'SIGINT' || result.signal === 'SIGTERM' ? 0 : 1));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zintrust-main.d.ts","sourceRoot":"","sources":["../../bin/zintrust-main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;
|
|
1
|
+
{"version":3,"file":"zintrust-main.d.ts","sourceRoot":"","sources":["../../bin/zintrust-main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAiYF,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAMzC;AAED,eAAO,MAAM,mBAAmB;;qCAhWQ,MAAM,KAAG,qBAAqB,GAAG,SAAS;mCA6C5C,MAAM,GAAG,IAAI,UAAU,MAAM,CAAC,OAAO,GAAG,IAAI,KAAG,MAAM;iCAnEzD,MAAM;8BAIP,MAAM,KAAG,MAAM;uCAoGtC,qBAAqB,WACpB,MAAM,EAAE,KAChB,OAAO,CAAC,KAAK,CAAC;oCA9FsB,MAAM,sBAAsB,MAAM,KAAG,OAAO;6CAkI7B,MAAM,EAAE,KAAG,OAAO,CAAC,OAAO,CAAC;yCA7F1E,MAAM,sBACS,MAAM,QACrB,MAAM,CAAC,UAAU,KACrB,qBAAqB,GAAG,SAAS;EA4UlC,CAAC;AAaH,OAAO,EAAE,CAAC"}
|
package/bin/zintrust-main.js
CHANGED
|
@@ -80,6 +80,28 @@ const getHandoffExitCode = (exitCode, signal) => {
|
|
|
80
80
|
return 0;
|
|
81
81
|
return 1;
|
|
82
82
|
};
|
|
83
|
+
const waitForChildTermination = async (child) => {
|
|
84
|
+
return await new Promise((resolve, reject) => {
|
|
85
|
+
let settled = false;
|
|
86
|
+
const finish = (exitCode, signal) => {
|
|
87
|
+
if (settled)
|
|
88
|
+
return;
|
|
89
|
+
settled = true;
|
|
90
|
+
child.off?.('exit', onExit);
|
|
91
|
+
child.off?.('close', onClose);
|
|
92
|
+
resolve({ exitCode, signal });
|
|
93
|
+
};
|
|
94
|
+
const onExit = (exitCode, signal) => {
|
|
95
|
+
finish(exitCode, signal);
|
|
96
|
+
};
|
|
97
|
+
const onClose = (exitCode, signal) => {
|
|
98
|
+
finish(exitCode, signal);
|
|
99
|
+
};
|
|
100
|
+
child.once('error', reject);
|
|
101
|
+
child.once('exit', onExit);
|
|
102
|
+
child.once('close', onClose);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
83
105
|
const handoffToProjectLocalCli = async (target, rawArgs) => {
|
|
84
106
|
const child = spawn(process.execPath, [target.binPath, ...rawArgs], {
|
|
85
107
|
stdio: 'inherit',
|
|
@@ -104,12 +126,7 @@ const handoffToProjectLocalCli = async (target, rawArgs) => {
|
|
|
104
126
|
process.on('SIGINT', onSigint);
|
|
105
127
|
process.on('SIGTERM', onSigterm);
|
|
106
128
|
try {
|
|
107
|
-
const result = await
|
|
108
|
-
child.once('error', reject);
|
|
109
|
-
child.once('close', (exitCode, signal) => {
|
|
110
|
-
resolve({ exitCode, signal });
|
|
111
|
-
});
|
|
112
|
-
});
|
|
129
|
+
const result = await waitForChildTermination(child);
|
|
113
130
|
process.exit(getHandoffExitCode(result.exitCode, result.signal));
|
|
114
131
|
}
|
|
115
132
|
finally {
|
|
@@ -317,3 +334,12 @@ export const CliLauncherInternal = Object.freeze({
|
|
|
317
334
|
maybeHandoffToProjectLocalCli,
|
|
318
335
|
resolveProjectLocalCliHandoff,
|
|
319
336
|
});
|
|
337
|
+
const shouldRunAsMain = () => {
|
|
338
|
+
const entryArg = process.argv[1];
|
|
339
|
+
if (typeof entryArg !== 'string' || entryArg.trim() === '')
|
|
340
|
+
return false;
|
|
341
|
+
return getRealPath(entryArg) === getRealPath(fileURLToPath(import.meta.url));
|
|
342
|
+
};
|
|
343
|
+
if (shouldRunAsMain()) {
|
|
344
|
+
await run();
|
|
345
|
+
}
|
package/bin/zintrust.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zintrust.d.ts","sourceRoot":"","sources":["../../bin/zintrust.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"zintrust.d.ts","sourceRoot":"","sources":["../../bin/zintrust.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AA8CH,OAAO,EAAE,CAAC"}
|
package/bin/zintrust.js
CHANGED
|
@@ -6,5 +6,38 @@
|
|
|
6
6
|
* bin/zintrust-main.ts. Keeping the implementation hashbang-free allows other
|
|
7
7
|
* shortcuts (zin/z/zt) to import it without parse issues.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const tsTarget = path.join(here, 'zintrust-main.ts');
|
|
17
|
+
const jsTarget = path.join(here, 'zintrust-main.js');
|
|
18
|
+
const target = existsSync(tsTarget) ? tsTarget : jsTarget;
|
|
19
|
+
const tsxImportPath = require.resolve('tsx');
|
|
20
|
+
const nodeArgs = target.endsWith('.ts')
|
|
21
|
+
? ['--import', tsxImportPath, target, ...process.argv.slice(2)]
|
|
22
|
+
: [target, ...process.argv.slice(2)];
|
|
23
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
24
|
+
stdio: 'inherit',
|
|
25
|
+
env: process.env,
|
|
26
|
+
});
|
|
27
|
+
const result = await new Promise((resolve, reject) => {
|
|
28
|
+
let settled = false;
|
|
29
|
+
const finalize = (exitCode, signal) => {
|
|
30
|
+
if (settled) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
settled = true;
|
|
34
|
+
child.off?.('error', reject);
|
|
35
|
+
child.off?.('exit', finalize);
|
|
36
|
+
child.off?.('close', finalize);
|
|
37
|
+
resolve({ exitCode, signal });
|
|
38
|
+
};
|
|
39
|
+
child.once('error', reject);
|
|
40
|
+
child.once('exit', finalize);
|
|
41
|
+
child.once('close', finalize);
|
|
42
|
+
});
|
|
43
|
+
process.exit(result.exitCode ?? (result.signal === 'SIGINT' || result.signal === 'SIGTERM' ? 0 : 1));
|
package/bin/zt.js
CHANGED
|
@@ -3,5 +3,25 @@
|
|
|
3
3
|
* ZinTrust CLI Shortcut - 'z'
|
|
4
4
|
* Mirrors bin/zintrust.ts for convenience
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const tsTarget = path.join(here, 'zintrust-main.ts');
|
|
12
|
+
const jsTarget = path.join(here, 'zintrust-main.js');
|
|
13
|
+
const target = existsSync(tsTarget) ? tsTarget : jsTarget;
|
|
14
|
+
const nodeArgs = target.endsWith('.ts')
|
|
15
|
+
? ['--import', 'tsx', target, ...process.argv.slice(2)]
|
|
16
|
+
: [target, ...process.argv.slice(2)];
|
|
17
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
env: process.env,
|
|
20
|
+
});
|
|
21
|
+
const result = await new Promise((resolve, reject) => {
|
|
22
|
+
child.once('error', reject);
|
|
23
|
+
child.once('close', (exitCode, signal) => {
|
|
24
|
+
resolve({ exitCode, signal });
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
process.exit(result.exitCode ?? (result.signal === 'SIGINT' || result.signal === 'SIGTERM' ? 0 : 1));
|
package/package.json
CHANGED
package/src/boot/bootstrap.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/boot/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/boot/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyWH,eAAO,MAAM,cAAc,eAAmB,CAAC"}
|
package/src/boot/bootstrap.js
CHANGED
|
@@ -283,15 +283,20 @@ const BootstrapFunctions = Object.freeze({
|
|
|
283
283
|
});
|
|
284
284
|
},
|
|
285
285
|
});
|
|
286
|
-
|
|
287
|
-
await BootstrapFunctions.start().catch((error) => {
|
|
286
|
+
const startBootstrap = async () => {
|
|
288
287
|
try {
|
|
289
|
-
|
|
288
|
+
await BootstrapFunctions.start();
|
|
289
|
+
BootstrapFunctions.setupShutdownHandler();
|
|
290
290
|
}
|
|
291
|
-
catch {
|
|
292
|
-
|
|
291
|
+
catch (error) {
|
|
292
|
+
try {
|
|
293
|
+
Logger.error('Failed to bootstrap application:', error);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// best-effort logging
|
|
297
|
+
}
|
|
298
|
+
process.exit(1);
|
|
293
299
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
BootstrapFunctions.setupShutdownHandler();
|
|
300
|
+
};
|
|
301
|
+
// Run bootstrap without parse-time top-level await so Worker bundles can load this module.
|
|
302
|
+
export const bootstrapReady = startBootstrap();
|
|
@@ -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;AAugCvF,eAAO,MAAM,YAAY;cACb,YAAY;;mCA38BU,MAAM,KAAG,OAAO;4CAaP,MAAM,KAAG,MAAM;4CA4Bf,MAAM,KAAG,OAAO;sCAetB,MAAM,WAAW,MAAM,KAAG,OAAO;oCAmBnC,MAAM,KAAG,OAAO;;EA26BjD,CAAC"}
|
|
@@ -635,6 +635,7 @@ const executeNodeStart = async (cmd, context, mode, watchEnabled, _port) => {
|
|
|
635
635
|
command: dev.command,
|
|
636
636
|
args: dev.args,
|
|
637
637
|
forwardSignals: false,
|
|
638
|
+
ttySignalForwardDelayMs: 1500,
|
|
638
639
|
env: {
|
|
639
640
|
...buildStartEnv(context.projectRoot),
|
|
640
641
|
ZINTRUST_BOOTSTRAP_PREFERENCE: 'source',
|
package/src/cli/utils/spawn.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA8HD,eAAO,MAAM,SAAS;wBACM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;EA2F7D,CAAC"}
|
package/src/cli/utils/spawn.js
CHANGED
|
@@ -45,6 +45,60 @@ const buildCommandNotFoundMessage = (command) => {
|
|
|
45
45
|
}
|
|
46
46
|
return `Error: '${command}' not found on PATH.`;
|
|
47
47
|
};
|
|
48
|
+
const waitForChildExit = async (child, onExit) => {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
let settled = false;
|
|
51
|
+
const finish = (result) => {
|
|
52
|
+
if (settled)
|
|
53
|
+
return;
|
|
54
|
+
settled = true;
|
|
55
|
+
child.off?.('exit', onExitEvent);
|
|
56
|
+
child.off?.('close', onCloseEvent);
|
|
57
|
+
onExit();
|
|
58
|
+
resolve(result);
|
|
59
|
+
};
|
|
60
|
+
const onExitEvent = (code, signal) => {
|
|
61
|
+
finish({ exitCode: code, signal });
|
|
62
|
+
};
|
|
63
|
+
const onCloseEvent = (code, signal) => {
|
|
64
|
+
finish({ exitCode: code, signal });
|
|
65
|
+
};
|
|
66
|
+
child.once('error', (error) => {
|
|
67
|
+
reject(error);
|
|
68
|
+
});
|
|
69
|
+
child.once('exit', onExitEvent);
|
|
70
|
+
child.once('close', onCloseEvent);
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
const createDelayedSignalForwarder = (input) => {
|
|
74
|
+
let delayedSignalTimer;
|
|
75
|
+
const clear = () => {
|
|
76
|
+
if (delayedSignalTimer === undefined)
|
|
77
|
+
return;
|
|
78
|
+
clearTimeout(delayedSignalTimer);
|
|
79
|
+
delayedSignalTimer = undefined;
|
|
80
|
+
};
|
|
81
|
+
const schedule = (signal) => {
|
|
82
|
+
if (input.ttySignalForwardDelayMs <= 0 ||
|
|
83
|
+
delayedSignalTimer !== undefined ||
|
|
84
|
+
input.isChildClosed()) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
delayedSignalTimer = globalThis.setTimeout(() => {
|
|
88
|
+
delayedSignalTimer = undefined;
|
|
89
|
+
if (input.isChildClosed())
|
|
90
|
+
return;
|
|
91
|
+
try {
|
|
92
|
+
input.forwardSignal(signal);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// best-effort fallback for interactive watch processes
|
|
96
|
+
}
|
|
97
|
+
}, input.ttySignalForwardDelayMs);
|
|
98
|
+
delayedSignalTimer.unref?.();
|
|
99
|
+
};
|
|
100
|
+
return { clear, schedule };
|
|
101
|
+
};
|
|
48
102
|
export const SpawnUtil = Object.freeze({
|
|
49
103
|
async spawnAndWait(input) {
|
|
50
104
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -59,6 +113,10 @@ export const SpawnUtil = Object.freeze({
|
|
|
59
113
|
// (and often SIGTERM) so forwarding can cause duplicates. `tsx watch` is
|
|
60
114
|
// especially sensitive here and can print "Previous process hasn't exited yet. Force killing...".
|
|
61
115
|
const forwardSignals = typeof input.forwardSignals === 'boolean' ? input.forwardSignals : !process.stdin.isTTY;
|
|
116
|
+
const ttySignalForwardDelayMs = process.stdin.isTTY === true && forwardSignals === false
|
|
117
|
+
? Math.max(0, input.ttySignalForwardDelayMs ?? 0)
|
|
118
|
+
: 0;
|
|
119
|
+
let childClosed = false;
|
|
62
120
|
const forwardSignal = (signal) => {
|
|
63
121
|
try {
|
|
64
122
|
child.kill(signal);
|
|
@@ -75,29 +133,34 @@ export const SpawnUtil = Object.freeze({
|
|
|
75
133
|
throw wrapped;
|
|
76
134
|
}
|
|
77
135
|
};
|
|
136
|
+
const delayedSignalForwarder = createDelayedSignalForwarder({
|
|
137
|
+
ttySignalForwardDelayMs,
|
|
138
|
+
isChildClosed: () => childClosed,
|
|
139
|
+
forwardSignal,
|
|
140
|
+
});
|
|
78
141
|
const onSigint = () => {
|
|
79
142
|
if (forwardSignals) {
|
|
80
143
|
forwardSignal('SIGINT');
|
|
144
|
+
return;
|
|
81
145
|
}
|
|
82
|
-
//
|
|
83
|
-
//
|
|
146
|
+
// In interactive TTY mode, let the child receive the terminal SIGINT directly first.
|
|
147
|
+
// If it is still alive after a short grace period, send one fallback signal so the
|
|
148
|
+
// watcher exits without requiring a second Ctrl+C from the user.
|
|
149
|
+
delayedSignalForwarder.schedule('SIGINT');
|
|
84
150
|
};
|
|
85
151
|
const onSigterm = () => {
|
|
86
152
|
if (forwardSignals) {
|
|
87
153
|
forwardSignal('SIGTERM');
|
|
154
|
+
return;
|
|
88
155
|
}
|
|
89
|
-
|
|
156
|
+
delayedSignalForwarder.schedule('SIGTERM');
|
|
90
157
|
};
|
|
91
158
|
process.on('SIGINT', onSigint);
|
|
92
159
|
process.on('SIGTERM', onSigterm);
|
|
93
160
|
try {
|
|
94
|
-
const result = await
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
child.once('close', (code, signal) => {
|
|
99
|
-
resolve({ exitCode: code, signal });
|
|
100
|
-
});
|
|
161
|
+
const result = await waitForChildExit(child, () => {
|
|
162
|
+
childClosed = true;
|
|
163
|
+
delayedSignalForwarder.clear();
|
|
101
164
|
});
|
|
102
165
|
return getExitCode(result.exitCode, result.signal);
|
|
103
166
|
}
|
|
@@ -109,6 +172,7 @@ export const SpawnUtil = Object.freeze({
|
|
|
109
172
|
throw ErrorFactory.createTryCatchError('Failed to spawn child process', error);
|
|
110
173
|
}
|
|
111
174
|
finally {
|
|
175
|
+
delayedSignalForwarder.clear();
|
|
112
176
|
process.off('SIGINT', onSigint);
|
|
113
177
|
process.off('SIGTERM', onSigterm);
|
|
114
178
|
}
|
package/src/config/index.d.ts
CHANGED
|
@@ -12,13 +12,13 @@ export { notificationConfig, type NotificationConfig } from './notification';
|
|
|
12
12
|
export { queueConfig, type QueueConfig } from './queue';
|
|
13
13
|
export { securityConfig } from './security';
|
|
14
14
|
export { storageConfig, type StorageConfig } from './storage';
|
|
15
|
+
export type { MiddlewareConfigType } from './type';
|
|
15
16
|
export { createRedisConnection } from './workers';
|
|
16
17
|
/**
|
|
17
18
|
* Combined configuration object
|
|
18
19
|
* Sealed namespace for immutability
|
|
19
20
|
*/
|
|
20
21
|
export declare const config: Readonly<{
|
|
21
|
-
readonly middleware: import("./type").MiddlewareConfigType;
|
|
22
22
|
readonly app: Readonly<{
|
|
23
23
|
readonly name: string;
|
|
24
24
|
readonly prefix: string;
|
|
@@ -211,6 +211,7 @@ export declare const config: Readonly<{
|
|
|
211
211
|
readonly namespace: string;
|
|
212
212
|
};
|
|
213
213
|
}>;
|
|
214
|
+
readonly middleware: import("./type").MiddlewareConfigType;
|
|
214
215
|
readonly cache: {
|
|
215
216
|
default: string;
|
|
216
217
|
drivers: import("./type").CacheConfigInput["drivers"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;8BAkCgc,CAAC;;;;;;;;;;;;;;;;;;;;iFA/Cjb,CAAA;;;;;;;;;;;;;;;;;;;;8BAD2B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAgDoU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;EAHzX,CAAC;AAEZ,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC"}
|
package/src/config/index.js
CHANGED
|
@@ -28,9 +28,6 @@ export { createRedisConnection } from './workers.js';
|
|
|
28
28
|
* Sealed namespace for immutability
|
|
29
29
|
*/
|
|
30
30
|
export const config = Object.freeze({
|
|
31
|
-
get middleware() {
|
|
32
|
-
return middlewareConfig;
|
|
33
|
-
},
|
|
34
31
|
get app() {
|
|
35
32
|
return appConfig;
|
|
36
33
|
},
|
|
@@ -52,6 +49,9 @@ export const config = Object.freeze({
|
|
|
52
49
|
get microservices() {
|
|
53
50
|
return microservicesConfig;
|
|
54
51
|
},
|
|
52
|
+
get middleware() {
|
|
53
|
+
return middlewareConfig;
|
|
54
|
+
},
|
|
55
55
|
get cache() {
|
|
56
56
|
return cacheConfig;
|
|
57
57
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../src/config/queue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../src/config/queue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAyChG,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC;IACzC,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACnF,OAAO,EAAE;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAClC,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,CAAC,CAAC;AA+EH;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAO,kBA4DnC,CAAC;AAgDH,QAAA,MAAM,iBAAiB,QAAO;IAC5B,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,CAAC,YAAY,EAAE,sBAAsB,KAAK,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACzF,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACnF,OAAO,EAAE;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAClC,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CAuEH,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAqB/D,eAAO,MAAM,WAAW,EAAE,WAYxB,CAAC"}
|
package/src/config/queue.js
CHANGED
|
@@ -6,10 +6,39 @@
|
|
|
6
6
|
import { Cloudflare } from './cloudflare.js';
|
|
7
7
|
import { Env } from './env.js';
|
|
8
8
|
import { Logger } from './logger.js';
|
|
9
|
-
import { isKnownMiddlewareName, middlewareConfig } from './middleware.js';
|
|
10
9
|
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
11
10
|
import { ZintrustLang } from '../lang/lang.js';
|
|
12
11
|
import { StartupConfigFile, StartupConfigFileRegistry } from '../runtime/StartupConfigFileRegistry.js';
|
|
12
|
+
const StaticMiddlewareKeys = Object.freeze({
|
|
13
|
+
log: true,
|
|
14
|
+
error: true,
|
|
15
|
+
security: true,
|
|
16
|
+
rateLimit: true,
|
|
17
|
+
sanitizeBody: true,
|
|
18
|
+
fillRateLimit: true,
|
|
19
|
+
authRateLimit: true,
|
|
20
|
+
userMutationRateLimit: true,
|
|
21
|
+
csrf: true,
|
|
22
|
+
auth: true,
|
|
23
|
+
jwt: true,
|
|
24
|
+
bulletproof: true,
|
|
25
|
+
validateLogin: true,
|
|
26
|
+
validateRegister: true,
|
|
27
|
+
validateUserStore: true,
|
|
28
|
+
validateUserUpdate: true,
|
|
29
|
+
validateUserFill: true,
|
|
30
|
+
});
|
|
31
|
+
const isKnownQueueMonitorMiddlewareName = (value) => {
|
|
32
|
+
return (Object.hasOwn(StaticMiddlewareKeys, value) || /^rateLimit:\d+:\d+(?:\.\d+)?$/.test(value.trim()));
|
|
33
|
+
};
|
|
34
|
+
const getConfiguredQueueMonitorRouteKeys = () => {
|
|
35
|
+
const middlewareOverrides = StartupConfigFileRegistry.get(StartupConfigFile.Middleware) ?? {};
|
|
36
|
+
const routeConfig = middlewareOverrides.route;
|
|
37
|
+
if (typeof routeConfig !== 'object' || routeConfig === null || Array.isArray(routeConfig)) {
|
|
38
|
+
return new Set();
|
|
39
|
+
}
|
|
40
|
+
return new Set(Object.keys(routeConfig));
|
|
41
|
+
};
|
|
13
42
|
const getQueueDriver = (driverConfig) => {
|
|
14
43
|
const driverName = driverConfig.default;
|
|
15
44
|
return driverConfig.drivers[driverName];
|
|
@@ -124,9 +153,9 @@ const createBaseMonitor = () => {
|
|
|
124
153
|
.map((m) => m.trim())
|
|
125
154
|
.filter((m) => m.length > 0);
|
|
126
155
|
if (enabled && middleware.length > 0) {
|
|
127
|
-
const knownKeys =
|
|
156
|
+
const knownKeys = getConfiguredQueueMonitorRouteKeys();
|
|
128
157
|
const unknownKeys = middleware.filter((name) => {
|
|
129
|
-
return !knownKeys.has(name) && !
|
|
158
|
+
return !knownKeys.has(name) && !isKnownQueueMonitorMiddlewareName(name);
|
|
130
159
|
});
|
|
131
160
|
if (unknownKeys.length > 0) {
|
|
132
161
|
Logger.error('Unknown QUEUE_MONITOR_MIDDLEWARE keys configured', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestContext.d.ts","sourceRoot":"","sources":["../../../src/http/RequestContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"RequestContext.d.ts","sourceRoot":"","sources":["../../../src/http/RequestContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwGD,eAAO,MAAM,cAAc;QACf,CAAC,WAAW,eAAe,YAAY,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;eAKpD,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;YAK7C,eAAe,GAAG,SAAS;gBAIvB,QAAQ,GAAG,eAAe;gBAoC1B,QAAQ,WAAW,eAAe,GAAG,IAAI;aAS5C,QAAQ,GAAG,eAAe,GAAG,SAAS;oBAM/B,eAAe,UAAU,MAAM,GAAG,eAAe;mBASlD,QAAQ,UAAU,MAAM,GAAG,SAAS,GAAG,IAAI;qBAIzC,QAAQ,YAAY,MAAM,GAAG,SAAS,GAAG,IAAI;oBAI9C,QAAQ,WAAW,MAAM,GAAG,SAAS,GAAG,IAAI;EAG5D,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -77,9 +77,12 @@ const setContextField = (req, field, value) => {
|
|
|
77
77
|
ctx[field] = value;
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const initializeStorage = async () => {
|
|
81
|
+
const storage = await resolveStorage();
|
|
82
|
+
syncStorage = storage;
|
|
83
|
+
return storage;
|
|
84
|
+
};
|
|
85
|
+
const STORAGE_PROMISE = initializeStorage();
|
|
83
86
|
export const RequestContext = Object.freeze({
|
|
84
87
|
async run(context, callback) {
|
|
85
88
|
const storage = await STORAGE_PROMISE;
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v1.5.
|
|
2
|
+
* @zintrust/core v1.5.4
|
|
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-
|
|
8
|
+
* Built: 2026-04-29T07:41:51.160Z
|
|
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-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-04-29T07:41:51.121Z'; // 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":"Schema.d.ts","sourceRoot":"","sources":["../../../../src/migrations/schema/Schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../../src/migrations/schema/Schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAM/C,OAAO,KAAK,EAKV,aAAa,EACd,MAAM,0BAA0B,CAAC;AAoYlC,iBAAS,mBAAmB,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAWzD;AAED,eAAO,MAAM,MAAM;;EAEjB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
|
+
import { isNonEmptyString, isObject } from '../../helper/index.js';
|
|
2
3
|
import { BaseAdapter } from '../../orm/DatabaseAdapter.js';
|
|
3
4
|
import { isSqliteFamily } from '../enum/index.js';
|
|
4
5
|
import { MigrationBlueprint } from '../schema/Blueprint.js';
|
|
@@ -9,18 +10,128 @@ function assertIdentifier(label, value) {
|
|
|
9
10
|
throw ErrorFactory.createValidationError(`Invalid ${label} identifier: ${value}`);
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
|
-
function isRecord(value) {
|
|
13
|
-
return typeof value === 'object' && value !== null;
|
|
14
|
-
}
|
|
15
13
|
function getStringProp(value, key) {
|
|
16
|
-
if (!
|
|
14
|
+
if (!isObject(value))
|
|
17
15
|
return null;
|
|
18
16
|
const v = value[key];
|
|
19
|
-
return
|
|
17
|
+
return isNonEmptyString(v) ? v : null;
|
|
20
18
|
}
|
|
21
19
|
function mapNames(rows) {
|
|
22
20
|
return rows.map((r) => getStringProp(r, 'name') ?? '').filter((name) => name.length > 0);
|
|
23
21
|
}
|
|
22
|
+
function normalizeSqliteAffinity(type) {
|
|
23
|
+
if (!isNonEmptyString(type))
|
|
24
|
+
return null;
|
|
25
|
+
const normalized = type.trim().toUpperCase();
|
|
26
|
+
if (normalized.includes('INT'))
|
|
27
|
+
return 'INTEGER';
|
|
28
|
+
if (normalized.includes('CHAR') ||
|
|
29
|
+
normalized.includes('CLOB') ||
|
|
30
|
+
normalized.includes('TEXT') ||
|
|
31
|
+
normalized.includes('UUID') ||
|
|
32
|
+
normalized.includes('DATE') ||
|
|
33
|
+
normalized.includes('TIME') ||
|
|
34
|
+
normalized.includes('JSON')) {
|
|
35
|
+
return 'TEXT';
|
|
36
|
+
}
|
|
37
|
+
if (normalized.includes('BLOB'))
|
|
38
|
+
return 'BLOB';
|
|
39
|
+
if (normalized.includes('REAL') || normalized.includes('FLOA') || normalized.includes('DOUB')) {
|
|
40
|
+
return 'REAL';
|
|
41
|
+
}
|
|
42
|
+
return 'NUMERIC';
|
|
43
|
+
}
|
|
44
|
+
function getPlannedSqliteAffinity(def) {
|
|
45
|
+
switch (def.type) {
|
|
46
|
+
case 'STRING':
|
|
47
|
+
case 'DATE':
|
|
48
|
+
case 'UUID':
|
|
49
|
+
case 'TEXT':
|
|
50
|
+
case 'JSON':
|
|
51
|
+
case 'TIMESTAMP':
|
|
52
|
+
return 'TEXT';
|
|
53
|
+
case 'INTEGER':
|
|
54
|
+
case 'BIGINT':
|
|
55
|
+
return 'INTEGER';
|
|
56
|
+
case 'REAL':
|
|
57
|
+
return 'REAL';
|
|
58
|
+
case 'BLOB':
|
|
59
|
+
return 'BLOB';
|
|
60
|
+
case 'BOOLEAN':
|
|
61
|
+
return 'NUMERIC';
|
|
62
|
+
default:
|
|
63
|
+
return 'NUMERIC';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function getSqliteTableColumns(db, tableName) {
|
|
67
|
+
assertIdentifier('table', tableName);
|
|
68
|
+
const rows = await db.query(`PRAGMA table_info("${tableName}")`, [], true);
|
|
69
|
+
return rows
|
|
70
|
+
.map((row) => {
|
|
71
|
+
const name = getStringProp(row, 'name');
|
|
72
|
+
if (!isNonEmptyString(name))
|
|
73
|
+
return null;
|
|
74
|
+
return {
|
|
75
|
+
name,
|
|
76
|
+
affinity: normalizeSqliteAffinity(getStringProp(row, 'type')),
|
|
77
|
+
};
|
|
78
|
+
})
|
|
79
|
+
.filter((row) => row !== null);
|
|
80
|
+
}
|
|
81
|
+
function getColumnAffinityLabel(affinity) {
|
|
82
|
+
return affinity ?? 'unknown';
|
|
83
|
+
}
|
|
84
|
+
function buildPlannedColumnMap(columns) {
|
|
85
|
+
return new Map(columns.map((column) => [column.name, getPlannedSqliteAffinity(column)]));
|
|
86
|
+
}
|
|
87
|
+
function getColumnAffinity(columnName, existingColumns, plannedColumns) {
|
|
88
|
+
return plannedColumns.get(columnName) ?? existingColumns.get(columnName) ?? null;
|
|
89
|
+
}
|
|
90
|
+
function describeSqliteForeignKey(tableName, fk, localColumns, plannedColumns, referencedColumns) {
|
|
91
|
+
const local = fk.columns.map((column) => {
|
|
92
|
+
const affinity = getColumnAffinity(column, localColumns, plannedColumns);
|
|
93
|
+
return `${tableName}.${column} [${getColumnAffinityLabel(affinity)}]`;
|
|
94
|
+
});
|
|
95
|
+
const referenced = fk.referencedColumns.map((column) => {
|
|
96
|
+
const affinity = referencedColumns.get(column) ?? null;
|
|
97
|
+
return `${fk.referencedTable}.${column} [${getColumnAffinityLabel(affinity)}]`;
|
|
98
|
+
});
|
|
99
|
+
const hasMismatch = fk.columns.some((column, index) => {
|
|
100
|
+
const localAffinity = getColumnAffinity(column, localColumns, plannedColumns);
|
|
101
|
+
const referencedAffinity = referencedColumns.get(fk.referencedColumns[index]) ?? null;
|
|
102
|
+
return (isNonEmptyString(localAffinity) &&
|
|
103
|
+
isNonEmptyString(referencedAffinity) &&
|
|
104
|
+
localAffinity !== referencedAffinity);
|
|
105
|
+
});
|
|
106
|
+
const mismatchSuffix = hasMismatch
|
|
107
|
+
? ' (detected SQLite affinity mismatch between local and referenced columns)'
|
|
108
|
+
: '';
|
|
109
|
+
return `Add foreign key "${fk.name}": ${local.join(', ')} -> ${referenced.join(', ')}${mismatchSuffix}`;
|
|
110
|
+
}
|
|
111
|
+
async function buildSqliteAlterTableDiagnostic(db, tableName, plan) {
|
|
112
|
+
const details = [];
|
|
113
|
+
if (plan.dropColumns.length > 0) {
|
|
114
|
+
details.push(`Drop columns: ${plan.dropColumns.join(', ')}`);
|
|
115
|
+
}
|
|
116
|
+
if (plan.addForeignKeys.length > 0) {
|
|
117
|
+
const localColumns = await getSqliteTableColumns(db, tableName);
|
|
118
|
+
const localColumnMap = new Map(localColumns.map((column) => [column.name, column.affinity]));
|
|
119
|
+
const plannedColumnMap = buildPlannedColumnMap(plan.addColumns);
|
|
120
|
+
const foreignKeyDetails = await Promise.all(plan.addForeignKeys.map(async (fk) => {
|
|
121
|
+
const referenced = await getSqliteTableColumns(db, fk.referencedTable);
|
|
122
|
+
const referencedColumnMap = new Map(referenced.map((column) => [column.name, column.affinity]));
|
|
123
|
+
return describeSqliteForeignKey(tableName, fk, localColumnMap, plannedColumnMap, referencedColumnMap);
|
|
124
|
+
}));
|
|
125
|
+
details.push(...foreignKeyDetails);
|
|
126
|
+
}
|
|
127
|
+
if (plan.dropForeignKeys.length > 0) {
|
|
128
|
+
details.push(`Drop foreign keys: ${plan.dropForeignKeys.join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
return [
|
|
131
|
+
`SQLite/D1 schema.table('${tableName}') cannot drop columns or alter foreign keys without a table rebuild.`,
|
|
132
|
+
...details,
|
|
133
|
+
].join(' ');
|
|
134
|
+
}
|
|
24
135
|
function buildParameterized(db, sql, parameters) {
|
|
25
136
|
const adapter = db.getAdapterInstance(false);
|
|
26
137
|
return BaseAdapter.buildParameterizedQuery(sql, parameters, (i) => adapter.getPlaceholder(i));
|
|
@@ -58,6 +169,12 @@ async function schemaTable(db, tableName, callback) {
|
|
|
58
169
|
addForeignKeys: def.foreignKeys,
|
|
59
170
|
dropForeignKeys: blueprint.getDropForeignKeys(),
|
|
60
171
|
};
|
|
172
|
+
if (isSqliteFamily(db.getType()) &&
|
|
173
|
+
(plan.dropColumns.length > 0 ||
|
|
174
|
+
plan.addForeignKeys.length > 0 ||
|
|
175
|
+
plan.dropForeignKeys.length > 0)) {
|
|
176
|
+
throw ErrorFactory.createValidationError(await buildSqliteAlterTableDiagnostic(db, tableName, plan));
|
|
177
|
+
}
|
|
61
178
|
const statements = MigrationSchemaCompiler.compileAlterTable(db.getType(), tableName, plan);
|
|
62
179
|
await runStatements(db, statements);
|
|
63
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginManager.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PluginManager.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginManager.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AA2ShE,eAAO,MAAM,aAAa;IACxB;;OAEG;YACK,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAIxC;;OAEG;yBACkB,MAAM,GAAG,MAAM,GAAG,IAAI;IAW3C;;OAEG;0BACyB,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0DrD;;OAEG;sBACqB,MAAM,YAAY;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BrF;;;;OAIG;wBACuB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EA2ChD,CAAC"}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Plugin Manager
|
|
4
4
|
* Handles installation and removal of framework plugins.
|
|
5
5
|
*/
|
|
6
|
-
import { SpawnUtil } from '../cli/utils/spawn.js';
|
|
7
6
|
import { readEnvString } from '../common/ExternalServiceUtils.js';
|
|
8
7
|
import { esmDirname, resolvePackageManager } from '../common/index.js';
|
|
9
8
|
import { Logger } from '../config/logger.js';
|
|
@@ -13,6 +12,11 @@ import * as path from '../node-singletons/path.js';
|
|
|
13
12
|
import { PluginRegistry } from './PluginRegistry.js';
|
|
14
13
|
const __dirname = esmDirname(import.meta.url);
|
|
15
14
|
const MAX_PACKAGE_ROOT_SEARCH_DEPTH = 20;
|
|
15
|
+
let spawnUtilPromise;
|
|
16
|
+
const loadSpawnUtil = async () => {
|
|
17
|
+
spawnUtilPromise ??= import('../cli/utils/spawn.js').then((module) => module.SpawnUtil);
|
|
18
|
+
return spawnUtilPromise;
|
|
19
|
+
};
|
|
16
20
|
function findPackageRoot(startDir) {
|
|
17
21
|
let current = startDir;
|
|
18
22
|
for (let i = 0; i < MAX_PACKAGE_ROOT_SEARCH_DEPTH; i++) {
|
|
@@ -109,8 +113,9 @@ async function npmInstall(packages, options) {
|
|
|
109
113
|
break;
|
|
110
114
|
}
|
|
111
115
|
try {
|
|
116
|
+
const spawnUtil = await loadSpawnUtil();
|
|
112
117
|
// Use async spawn for all package managers to avoid blocking event loop
|
|
113
|
-
const exit = await
|
|
118
|
+
const exit = await spawnUtil.spawnAndWait({ command: cmd, args, cwd: projectRoot });
|
|
114
119
|
if (exit !== 0) {
|
|
115
120
|
throw ErrorFactory.createCliError(`Package manager ${pm} failed to install ${options.label}`, {
|
|
116
121
|
exit,
|
|
@@ -213,7 +218,8 @@ async function runPostInstall(plugin) {
|
|
|
213
218
|
Logger.info(`Running post-install command: ${plugin.postInstall.command}...`);
|
|
214
219
|
let exit;
|
|
215
220
|
try {
|
|
216
|
-
|
|
221
|
+
const spawnUtil = await loadSpawnUtil();
|
|
222
|
+
exit = await spawnUtil.spawnAndWait({
|
|
217
223
|
command: plugin.postInstall.command,
|
|
218
224
|
args: [],
|
|
219
225
|
cwd: projectRoot,
|
|
@@ -22,7 +22,7 @@ const tryImportOptional = async () => {
|
|
|
22
22
|
await tryImportProjectRuntime();
|
|
23
23
|
await import('./WorkerProjectPlugins.js');
|
|
24
24
|
};
|
|
25
|
-
const ready =
|
|
25
|
+
const ready = tryImportOptional();
|
|
26
26
|
export const WorkerAdapterImports = Object.freeze({
|
|
27
27
|
loaded: true,
|
|
28
28
|
ready,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace-runtime.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC;CACtC,CAAC;AAwEF,eAAO,MAAM,WAAW,QAAO,OAA0C,CAAC;AAE1E,eAAO,MAAM,WAAW,EAAE,cAIxB,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,eAIzB,CAAC;AAEH,eAAO,MAAM,sBAAsB,GACjC,QAAQ,OAAO,EACf,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,OAAO,EACf,SAAS,OAAO,EAChB,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,OAAO,OAAO,EACd,UAAU;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAChF,IASF,CAAC;AAEF,eAAO,MAAM,2BAA2B,QAAa,OAAO,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"trace-runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace-runtime.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC;CACtC,CAAC;AAwEF,eAAO,MAAM,WAAW,QAAO,OAA0C,CAAC;AAE1E,eAAO,MAAM,WAAW,EAAE,cAIxB,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,eAIzB,CAAC;AAEH,eAAO,MAAM,sBAAsB,GACjC,QAAQ,OAAO,EACf,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,OAAO,EACf,SAAS,OAAO,EAChB,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,OAAO,OAAO,EACd,UAAU;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAChF,IASF,CAAC;AAEF,eAAO,MAAM,2BAA2B,QAAa,OAAO,CAAC,IAAI,CAKhE,CAAC"}
|
|
@@ -59,5 +59,6 @@ export const ensureSystemTraceRegistered = async () => {
|
|
|
59
59
|
const module = await loadSystemTraceModule();
|
|
60
60
|
if (module === undefined)
|
|
61
61
|
return;
|
|
62
|
-
await import('../../../packages/trace/src/register.js').catch(() => undefined);
|
|
62
|
+
const registerModule = await import('../../../packages/trace/src/register.js').catch(() => undefined);
|
|
63
|
+
await registerModule?.registerTraceReady?.catch(() => undefined);
|
|
63
64
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,CAAC;AAmBf,eAAO,MAAM,KAAK,eAAoB,CAAC"}
|
|
@@ -7,8 +7,10 @@ const tryImport = async (specifier) => {
|
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const loadTracePlugin = async () => {
|
|
11
|
+
const importedPackagePlugin = await tryImport('@zintrust/trace/plugin');
|
|
12
|
+
if (!importedPackagePlugin) {
|
|
13
|
+
await import('../../../packages/trace/src/plugin.js').catch(() => undefined);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const ready = loadTracePlugin();
|
|
@@ -32,17 +32,17 @@ export default {
|
|
|
32
32
|
.filter((m: string) => m.length > 0) as ReadonlyArray<string>,
|
|
33
33
|
fillRateLimit: {
|
|
34
34
|
windowMs: 60_000,
|
|
35
|
-
|
|
35
|
+
maxRequests: 5,
|
|
36
36
|
message: 'Too many fill requests, please try again later.',
|
|
37
37
|
},
|
|
38
38
|
authRateLimit: {
|
|
39
39
|
windowMs: 60_000,
|
|
40
|
-
|
|
40
|
+
maxRequests: 4,
|
|
41
41
|
message: 'Too many authentication attempts, please try again later.',
|
|
42
42
|
},
|
|
43
43
|
userMutationRateLimit: {
|
|
44
44
|
windowMs: 60_000,
|
|
45
|
-
|
|
45
|
+
maxRequests: 20,
|
|
46
46
|
message: 'Too many user mutation requests, please try again later.',
|
|
47
47
|
},
|
|
48
48
|
responders: {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* ZinTrust plugin auto-imports
|
|
3
|
+
*
|
|
4
|
+
* In real projects, this file is managed by `zin plugin install` and contains
|
|
5
|
+
* side-effect imports (e.g. `@zintrust/db-sqlite/register`) that register
|
|
6
|
+
* optional adapters/drivers into core registries.
|
|
7
|
+
*
|
|
5
8
|
*/
|
|
6
9
|
export type {};
|
|
7
10
|
export declare const __zintrustGeneratedPluginStub = "zintrust.plugins.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zintrust.plugins.d.ts","sourceRoot":"","sources":["../../src/zintrust.plugins.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"zintrust.plugins.d.ts","sourceRoot":"","sources":["../../src/zintrust.plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,YAAY,EAAE,CAAC;AAgBf,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;;AACnE,wBAAkB"}
|
package/src/zintrust.plugins.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* ZinTrust plugin auto-imports
|
|
3
|
+
*
|
|
4
|
+
* In real projects, this file is managed by `zin plugin install` and contains
|
|
5
|
+
* side-effect imports (e.g. `@zintrust/db-sqlite/register`) that register
|
|
6
|
+
* optional adapters/drivers into core registries.
|
|
7
|
+
*
|
|
5
8
|
*/
|
|
6
9
|
import * as TraceRuntime from './runtime/plugins/trace-runtime.js';
|
|
7
10
|
globalThis.__zintrust_system_trace_plugin_requested__ = true;
|