@zintrust/core 0.1.23 → 0.1.25
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 +4 -3
- package/src/auth/Auth.d.ts.map +1 -0
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +8 -0
- package/src/boot/bootstrap.js +34 -15
- package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
- package/src/cache/drivers/RedisDriver.js +10 -5
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +6 -0
- package/src/cli/commands/DbSeedCommand.d.ts.map +1 -1
- package/src/cli/commands/DbSeedCommand.js +6 -38
- package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.js +12 -55
- package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateWorkerCommand.js +8 -54
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +1 -13
- package/src/cli/commands/QueueCommand.d.ts.map +1 -1
- package/src/cli/commands/QueueCommand.js +89 -39
- package/src/cli/commands/QueueLockCommand.d.ts +7 -0
- package/src/cli/commands/QueueLockCommand.d.ts.map +1 -0
- package/src/cli/commands/QueueLockCommand.js +138 -0
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +16 -16
- package/src/cli/commands/TemplatesCommand.js +1 -1
- package/src/cli/commands/WorkerCommands.d.ts.map +1 -1
- package/src/cli/commands/WorkerCommands.js +46 -22
- package/src/cli/scaffolding/ProjectScaffolder.js +2 -2
- package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/RouteGenerator.js +27 -28
- package/src/cli/services/VersionChecker.d.ts +53 -0
- package/src/cli/services/VersionChecker.d.ts.map +1 -0
- package/src/cli/services/VersionChecker.js +176 -0
- package/src/cli/utils/DatabaseCliUtils.d.ts +20 -0
- package/src/cli/utils/DatabaseCliUtils.d.ts.map +1 -0
- package/src/cli/utils/DatabaseCliUtils.js +54 -0
- package/src/cli/workers/QueueWorkRunner.d.ts.map +1 -1
- package/src/cli/workers/QueueWorkRunner.js +128 -7
- package/src/common/ExternalServiceUtils.d.ts +2 -2
- package/src/config/app.d.ts +4 -0
- package/src/config/app.d.ts.map +1 -1
- package/src/config/app.js +9 -0
- package/src/config/constants.d.ts +140 -10
- package/src/config/constants.d.ts.map +1 -1
- package/src/config/constants.js +86 -5
- package/src/config/index.d.ts +1 -0
- package/src/config/index.d.ts.map +1 -1
- package/src/config/middleware.d.ts +6 -6
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +6 -7
- package/src/config/queue.d.ts +4 -0
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +1 -1
- package/src/config/redis.d.ts +17 -0
- package/src/config/redis.d.ts.map +1 -0
- package/src/config/redis.js +54 -0
- package/src/config/type.d.ts +3 -0
- package/src/config/type.d.ts.map +1 -1
- package/src/http/Request.d.ts +10 -1
- package/src/http/Request.d.ts.map +1 -1
- package/src/http/Request.js +79 -7
- package/src/http/error-pages/ErrorPageRenderer.d.ts.map +1 -1
- package/src/http/error-pages/ErrorPageRenderer.js +4 -3
- package/src/index.d.ts +14 -11
- package/src/index.d.ts.map +1 -1
- package/src/index.js +18 -11
- package/src/lang/lang.d.ts +23 -0
- package/src/lang/lang.d.ts.map +1 -0
- package/src/lang/lang.js +22 -0
- package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
- package/src/middleware/ErrorHandlerMiddleware.js +9 -1
- package/src/migrations/schema/SchemaCompiler.js +1 -1
- package/src/migrations/schema/types.d.ts +1 -1
- package/src/migrations/schema/types.d.ts.map +1 -1
- package/src/node.d.ts +1 -1
- package/src/node.d.ts.map +1 -1
- package/src/node.js +1 -1
- package/src/orm/Database.d.ts +1 -1
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +22 -3
- package/src/performance/Optimizer.js +1 -1
- package/src/routing/Router.d.ts +6 -2
- package/src/routing/Router.d.ts.map +1 -1
- package/src/routing/Router.js +19 -4
- package/src/runtime/PluginAutoImports.d.ts.map +1 -1
- package/src/runtime/PluginAutoImports.js +1 -13
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +2 -14
- package/src/runtime/PluginRegistry.js +2 -2
- package/src/start.d.ts.map +1 -1
- package/src/start.js +8 -7
- package/src/templates/TemplateRegistry.js +2 -2
- package/src/templates/TemplateRegistry.ts +2 -2
- package/src/templates/feature/Queue.ts.tpl +114 -0
- package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +22 -0
- package/src/templates/project/basic/config/queue.ts.tpl +19 -0
- package/src/templates/project/basic/package.json.tpl +2 -1
- package/src/templates/project/basic/src/index.ts.tpl +0 -3
- package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -1
- package/src/toolkit/Secrets/providers/AwsSecretsManager.js +1 -13
- package/src/toolkit/Secrets/providers/CloudflareKv.d.ts.map +1 -1
- package/src/toolkit/Secrets/providers/CloudflareKv.js +4 -16
- package/src/tools/broadcast/drivers/Redis.d.ts.map +1 -1
- package/src/tools/broadcast/drivers/Redis.js +8 -56
- package/src/tools/mail/Mail.d.ts +1 -29
- package/src/tools/mail/Mail.d.ts.map +1 -1
- package/src/tools/mail/Mail.js +1 -111
- package/src/tools/mail/drivers/SendGrid.d.ts.map +1 -1
- package/src/tools/mail/drivers/SendGrid.js +4 -3
- package/src/tools/mail/drivers/Smtp.d.ts.map +1 -1
- package/src/tools/mail/drivers/Smtp.js +32 -10
- package/src/tools/mail/index.d.ts +40 -0
- package/src/tools/mail/index.d.ts.map +1 -0
- package/src/tools/mail/index.js +129 -0
- package/src/tools/mail/template-loader.d.ts +10 -0
- package/src/tools/mail/template-loader.d.ts.map +1 -0
- package/src/tools/mail/template-loader.js +101 -0
- package/src/tools/mail/template-utils.d.ts +10 -0
- package/src/tools/mail/template-utils.d.ts.map +1 -0
- package/src/tools/mail/template-utils.js +16 -0
- package/src/tools/mail/templates/index.d.ts +30 -0
- package/src/tools/mail/templates/index.d.ts.map +1 -1
- package/src/tools/mail/templates/index.js +69 -0
- package/src/tools/queue/AdvancedQueue.d.ts +19 -0
- package/src/tools/queue/AdvancedQueue.d.ts.map +1 -0
- package/src/tools/queue/AdvancedQueue.js +352 -0
- package/src/tools/queue/DeduplicationBuilder.d.ts +20 -0
- package/src/tools/queue/DeduplicationBuilder.d.ts.map +1 -0
- package/src/tools/queue/DeduplicationBuilder.js +77 -0
- package/src/tools/queue/LockProvider.d.ts +25 -0
- package/src/tools/queue/LockProvider.d.ts.map +1 -0
- package/src/tools/queue/LockProvider.js +276 -0
- package/src/tools/queue/Queue.d.ts.map +1 -1
- package/src/tools/queue/Queue.js +2 -1
- package/src/tools/queue/QueueExtensions.d.ts +46 -0
- package/src/tools/queue/QueueExtensions.d.ts.map +1 -0
- package/src/tools/queue/QueueExtensions.js +129 -0
- package/src/tools/queue/QueueRuntimeRegistration.d.ts.map +1 -1
- package/src/tools/queue/QueueRuntimeRegistration.js +2 -2
- package/src/tools/queue/drivers/Database.d.ts +23 -0
- package/src/tools/queue/drivers/Database.d.ts.map +1 -0
- package/src/tools/queue/drivers/Database.js +123 -0
- package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
- package/src/tools/queue/drivers/Redis.js +11 -82
- package/src/tools/queue/index.d.ts +9 -0
- package/src/tools/queue/index.d.ts.map +1 -0
- package/src/tools/queue/index.js +7 -0
- package/src/tools/redis/RedisKeyManager.d.ts +64 -0
- package/src/tools/redis/RedisKeyManager.d.ts.map +1 -0
- package/src/tools/redis/RedisKeyManager.js +124 -0
- package/src/tools/storage/drivers/S3.d.ts.map +1 -1
- package/src/tools/storage/drivers/S3.js +4 -16
- package/src/types/Queue.d.ts +62 -0
- package/src/types/Queue.d.ts.map +1 -0
- package/src/types/Queue.js +5 -0
- package/src/features/Auth.d.ts.map +0 -1
- package/src/features/Queue.d.ts +0 -21
- package/src/features/Queue.d.ts.map +0 -1
- package/src/features/Queue.js +0 -33
- package/src/templates/features/Queue.ts.tpl +0 -47
- package/src/tools/mail/templates/markdown/index.d.ts +0 -17
- package/src/tools/mail/templates/markdown/index.d.ts.map +0 -1
- package/src/tools/mail/templates/markdown/index.js +0 -49
- package/src/tools/mail/templates/markdown/registry.d.ts +0 -15
- package/src/tools/mail/templates/markdown/registry.d.ts.map +0 -1
- package/src/tools/mail/templates/markdown/registry.js +0 -34
- package/src/tools/mail/templates/markdown/validator.d.ts +0 -16
- package/src/tools/mail/templates/markdown/validator.d.ts.map +0 -1
- package/src/tools/mail/templates/markdown/validator.js +0 -24
- /package/src/{features → auth}/Auth.d.ts +0 -0
- /package/src/{features → auth}/Auth.js +0 -0
- /package/src/templates/{features → auth}/Auth.ts.tpl +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VersionChecker - CLI Version Update Notification Service
|
|
3
|
+
*
|
|
4
|
+
* Checks if the current CLI version is outdated and warns users
|
|
5
|
+
* when a newer version is available from npm registry.
|
|
6
|
+
*/
|
|
7
|
+
interface VersionCheckResult {
|
|
8
|
+
currentVersion: string;
|
|
9
|
+
latestVersion: string;
|
|
10
|
+
isOutdated: boolean;
|
|
11
|
+
updateAvailable: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface VersionCheckConfig {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
checkInterval: number;
|
|
16
|
+
skipVersionCheck: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare const VersionChecker: Readonly<{
|
|
19
|
+
/**
|
|
20
|
+
* Get current version from package.json
|
|
21
|
+
*/
|
|
22
|
+
getCurrentVersion(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get version check configuration
|
|
25
|
+
*/
|
|
26
|
+
getConfig(): VersionCheckConfig;
|
|
27
|
+
/**
|
|
28
|
+
* Check if version check should be performed
|
|
29
|
+
*/
|
|
30
|
+
shouldCheckVersion(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Fetch latest version from npm registry
|
|
33
|
+
*/
|
|
34
|
+
fetchLatestVersion(): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Compare versions using semver-like comparison
|
|
37
|
+
*/
|
|
38
|
+
compareVersions(current: string, latest: string): number;
|
|
39
|
+
/**
|
|
40
|
+
* Perform version check and return result
|
|
41
|
+
*/
|
|
42
|
+
checkVersion(): Promise<VersionCheckResult | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Display update notification to user
|
|
45
|
+
*/
|
|
46
|
+
displayUpdateNotification(result: VersionCheckResult): void;
|
|
47
|
+
/**
|
|
48
|
+
* Run version check and display notification if needed
|
|
49
|
+
*/
|
|
50
|
+
runVersionCheck(): Promise<void>;
|
|
51
|
+
}>;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=VersionChecker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersionChecker.d.ts","sourceRoot":"","sources":["../../../../src/cli/services/VersionChecker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAUD,UAAU,kBAAkB;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc;IACzB;;OAEG;yBACkB,MAAM;IAY3B;;OAEG;iBACU,kBAAkB;IAQ/B;;OAEG;0BACmB,OAAO;IA+B7B;;OAEG;0BACyB,OAAO,CAAC,MAAM,CAAC;IAwB3C;;OAEG;6BACsB,MAAM,UAAU,MAAM,GAAG,MAAM;IAmBxD;;OAEG;oBACmB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IA8BxD;;OAEG;sCAC+B,kBAAkB,GAAG,IAAI;IA4B3D;;OAEG;uBACsB,OAAO,CAAC,IAAI,CAAC;EAWtC,CAAC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VersionChecker - CLI Version Update Notification Service
|
|
3
|
+
*
|
|
4
|
+
* Checks if the current CLI version is outdated and warns users
|
|
5
|
+
* when a newer version is available from npm registry.
|
|
6
|
+
*/
|
|
7
|
+
import { Logger } from '../../config/logger.js';
|
|
8
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
9
|
+
import { readFileSync } from '../../node-singletons/fs.js';
|
|
10
|
+
import { join } from '../../node-singletons/path.js';
|
|
11
|
+
export const VersionChecker = Object.freeze({
|
|
12
|
+
/**
|
|
13
|
+
* Get current version from package.json
|
|
14
|
+
*/
|
|
15
|
+
getCurrentVersion() {
|
|
16
|
+
try {
|
|
17
|
+
const packagePath = join(process.cwd(), 'package.json');
|
|
18
|
+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
|
|
19
|
+
return typeof packageJson.version === 'string' ? packageJson.version : '0.0.0';
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return '0.0.0';
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* Get version check configuration
|
|
27
|
+
*/
|
|
28
|
+
getConfig() {
|
|
29
|
+
return {
|
|
30
|
+
enabled: process.env['ZINTRUST_VERSION_CHECK'] !== 'false',
|
|
31
|
+
checkInterval: parseInt(process.env['ZINTRUST_VERSION_CHECK_INTERVAL'] ?? '24', 10),
|
|
32
|
+
skipVersionCheck: process.env['ZINTRUST_SKIP_VERSION_CHECK'] === 'true',
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
/**
|
|
36
|
+
* Check if version check should be performed
|
|
37
|
+
*/
|
|
38
|
+
shouldCheckVersion() {
|
|
39
|
+
const config = this.getConfig();
|
|
40
|
+
// Skip if disabled
|
|
41
|
+
if (!config.enabled || config.skipVersionCheck) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// Skip for version commands
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
if (args.includes('-v') || args.includes('--version') || args.includes('help')) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Check last check time
|
|
50
|
+
const lastCheckKey = 'zintrust_last_version_check';
|
|
51
|
+
const lastCheck = globalThis.localStorage?.getItem?.(lastCheckKey);
|
|
52
|
+
if (lastCheck !== null && lastCheck !== undefined) {
|
|
53
|
+
const lastCheckTime = parseInt(lastCheck, 10);
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const hoursSinceLastCheck = (now - lastCheckTime) / (1000 * 60 * 60);
|
|
56
|
+
if (hoursSinceLastCheck < config.checkInterval) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Fetch latest version from npm registry
|
|
64
|
+
*/
|
|
65
|
+
async fetchLatestVersion() {
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetch('https://registry.npmjs.org/@zintrust/core/latest', {
|
|
68
|
+
method: 'GET',
|
|
69
|
+
headers: {
|
|
70
|
+
Accept: 'application/json',
|
|
71
|
+
'User-Agent': 'ZinTrust-CLI-Version-Check',
|
|
72
|
+
},
|
|
73
|
+
signal: AbortSignal.timeout(5000), // 5 second timeout
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw ErrorFactory.createConfigError(`HTTP ${response.status}: ${response.statusText}`);
|
|
77
|
+
}
|
|
78
|
+
const data = (await response.json());
|
|
79
|
+
return data['dist-tags'].latest || data.version;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// Silently fail for network issues - don't block CLI usage
|
|
83
|
+
Logger.debug('Failed to fetch latest version from npm registry', error);
|
|
84
|
+
throw ErrorFactory.createConfigError('Failed to check for updates', error);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Compare versions using semver-like comparison
|
|
89
|
+
*/
|
|
90
|
+
compareVersions(current, latest) {
|
|
91
|
+
const cleanVersion = (version) => version.replace(/^v/, '').replace(/-.*$/, '');
|
|
92
|
+
const currentParts = cleanVersion(current).split('.').map(Number);
|
|
93
|
+
const latestParts = cleanVersion(latest).split('.').map(Number);
|
|
94
|
+
const maxLength = Math.max(currentParts.length, latestParts.length);
|
|
95
|
+
for (let i = 0; i < maxLength; i++) {
|
|
96
|
+
const currentPart = currentParts[i] || 0;
|
|
97
|
+
const latestPart = latestParts[i] || 0;
|
|
98
|
+
if (currentPart < latestPart)
|
|
99
|
+
return -1;
|
|
100
|
+
if (currentPart > latestPart)
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
return 0;
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* Perform version check and return result
|
|
107
|
+
*/
|
|
108
|
+
async checkVersion() {
|
|
109
|
+
if (!this.shouldCheckVersion()) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const currentVersion = this.getCurrentVersion();
|
|
114
|
+
const latestVersion = await this.fetchLatestVersion();
|
|
115
|
+
const comparison = this.compareVersions(currentVersion, latestVersion);
|
|
116
|
+
const isOutdated = comparison < 0;
|
|
117
|
+
const updateAvailable = isOutdated;
|
|
118
|
+
// Update last check time
|
|
119
|
+
const lastCheckKey = 'zintrust_last_version_check';
|
|
120
|
+
globalThis.localStorage?.setItem?.(lastCheckKey, Date.now().toString());
|
|
121
|
+
return {
|
|
122
|
+
currentVersion,
|
|
123
|
+
latestVersion,
|
|
124
|
+
isOutdated,
|
|
125
|
+
updateAvailable,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// Silently fail - version check should never block CLI usage
|
|
130
|
+
Logger.debug('Version check failed, continuing with CLI execution', error);
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Display update notification to user
|
|
136
|
+
*/
|
|
137
|
+
displayUpdateNotification(result) {
|
|
138
|
+
if (!result.updateAvailable) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const { currentVersion, latestVersion } = result;
|
|
142
|
+
// Use process.stdout.write for better control and to avoid eslint console errors
|
|
143
|
+
const output = [
|
|
144
|
+
'',
|
|
145
|
+
'⚠️ Update Available',
|
|
146
|
+
'┌' + '─'.repeat(50) + '┐',
|
|
147
|
+
`│ Current: ${currentVersion.padEnd(40)}│`,
|
|
148
|
+
`│ Latest: ${latestVersion.padEnd(40)}│`,
|
|
149
|
+
'└' + '─'.repeat(50) + '┘',
|
|
150
|
+
'',
|
|
151
|
+
'💡 Update to get the latest features and bug fixes:',
|
|
152
|
+
` npm install -g @zintrust/core@${latestVersion}`,
|
|
153
|
+
' or: npx @zintrust/core@latest [command]',
|
|
154
|
+
'',
|
|
155
|
+
'🔧 To disable version checks:',
|
|
156
|
+
' export ZINTRUST_VERSION_CHECK=false',
|
|
157
|
+
'',
|
|
158
|
+
].join('\n');
|
|
159
|
+
process.stdout.write(output);
|
|
160
|
+
},
|
|
161
|
+
/**
|
|
162
|
+
* Run version check and display notification if needed
|
|
163
|
+
*/
|
|
164
|
+
async runVersionCheck() {
|
|
165
|
+
try {
|
|
166
|
+
const result = await this.checkVersion();
|
|
167
|
+
if (result) {
|
|
168
|
+
this.displayUpdateNotification(result);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// Version check should never crash the CLI
|
|
173
|
+
Logger.debug('Version check encountered an error', error);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CommandOptions, IBaseCommand } from '../BaseCommand';
|
|
2
|
+
import type { DatabaseConfig as OrmDatabaseConfig } from '../../orm/DatabaseAdapter';
|
|
3
|
+
export type ConnectionConfig = {
|
|
4
|
+
driver: string;
|
|
5
|
+
host?: string;
|
|
6
|
+
port?: number;
|
|
7
|
+
database?: string;
|
|
8
|
+
username?: string;
|
|
9
|
+
password?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const mapConnectionToOrmConfig: (conn: ConnectionConfig) => OrmDatabaseConfig;
|
|
12
|
+
export declare const parseRollbackSteps: (options: CommandOptions) => number;
|
|
13
|
+
export declare const confirmProductionRun: (params: {
|
|
14
|
+
cmd: IBaseCommand;
|
|
15
|
+
interactive: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
destructive?: boolean;
|
|
18
|
+
force?: boolean;
|
|
19
|
+
}) => Promise<boolean>;
|
|
20
|
+
//# sourceMappingURL=DatabaseCliUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseCliUtils.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/DatabaseCliUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrE,OAAO,KAAK,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,MAAM,gBAAgB,KAAG,iBAkCjE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS,cAAc,KAAG,MAG5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,QAAQ;IACjD,GAAG,EAAE,YAAY,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,KAAG,OAAO,CAAC,OAAO,CAalB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PromptHelper } from '../PromptHelper.js';
|
|
2
|
+
import { Env } from '../../config/env.js';
|
|
3
|
+
export const mapConnectionToOrmConfig = (conn) => {
|
|
4
|
+
switch (conn.driver) {
|
|
5
|
+
case 'sqlite':
|
|
6
|
+
return { driver: 'sqlite', database: conn.database ?? ':memory:' };
|
|
7
|
+
case 'postgresql':
|
|
8
|
+
return {
|
|
9
|
+
driver: 'postgresql',
|
|
10
|
+
host: conn.host,
|
|
11
|
+
port: conn.port,
|
|
12
|
+
database: conn.database,
|
|
13
|
+
username: conn.username,
|
|
14
|
+
password: conn.password,
|
|
15
|
+
};
|
|
16
|
+
case 'mysql':
|
|
17
|
+
return {
|
|
18
|
+
driver: 'mysql',
|
|
19
|
+
host: conn.host,
|
|
20
|
+
port: conn.port,
|
|
21
|
+
database: conn.database,
|
|
22
|
+
username: conn.username,
|
|
23
|
+
password: conn.password,
|
|
24
|
+
};
|
|
25
|
+
case 'sqlserver':
|
|
26
|
+
return {
|
|
27
|
+
driver: 'sqlserver',
|
|
28
|
+
host: conn.host,
|
|
29
|
+
port: conn.port,
|
|
30
|
+
database: conn.database,
|
|
31
|
+
username: conn.username,
|
|
32
|
+
password: conn.password,
|
|
33
|
+
};
|
|
34
|
+
default:
|
|
35
|
+
return { driver: 'sqlite', database: ':memory:' };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export const parseRollbackSteps = (options) => {
|
|
39
|
+
const stepRaw = typeof options['step'] === 'string' ? options['step'] : '1';
|
|
40
|
+
return Math.max(1, Number.parseInt(stepRaw, 10) || 1);
|
|
41
|
+
};
|
|
42
|
+
export const confirmProductionRun = async (params) => {
|
|
43
|
+
if (Env.NODE_ENV !== 'production')
|
|
44
|
+
return true;
|
|
45
|
+
if (params.force === true)
|
|
46
|
+
return true;
|
|
47
|
+
const prompt = params.destructive === true ? `${params.message} (destructive)` : params.message;
|
|
48
|
+
const confirmed = await PromptHelper.confirm(prompt, false, params.interactive);
|
|
49
|
+
if (!confirmed) {
|
|
50
|
+
params.cmd.warn('Cancelled.');
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueueWorkRunner.d.ts","sourceRoot":"","sources":["../../../../src/cli/workers/QueueWorkRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"QueueWorkRunner.d.ts","sourceRoot":"","sources":["../../../../src/cli/workers/QueueWorkRunner.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,cAAc,CAAC;AAoBzD,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAiQF,eAAO,MAAM,eAAe;iBACP,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;qBAuCzD,OAAO,GAAG,aAAa;EAUxC,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Broadcast } from '../../tools/broadcast/Broadcast.js';
|
|
2
|
+
import { Env } from '../../config/env.js';
|
|
2
3
|
import { Logger } from '../../config/logger.js';
|
|
3
4
|
import { queueConfig } from '../../config/queue.js';
|
|
4
5
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
6
|
+
import { ZintrustLang } from '../../lang/lang.js';
|
|
5
7
|
import { Notification } from '../../tools/notification/Notification.js';
|
|
8
|
+
import { createLockProvider, getLockProvider, registerLockProvider } from '../../tools/queue/LockProvider.js';
|
|
6
9
|
import { Queue } from '../../tools/queue/Queue.js';
|
|
7
10
|
import { registerQueuesFromRuntimeConfig } from '../../tools/queue/QueueRuntimeRegistration.js';
|
|
8
11
|
const isKind = (value) => value === 'broadcast' || value === 'notification';
|
|
@@ -44,9 +47,119 @@ const shouldStop = (startedAtMs, timeoutSeconds) => {
|
|
|
44
47
|
const elapsedMs = Date.now() - startedAtMs;
|
|
45
48
|
return elapsedMs >= timeoutSeconds * 1000;
|
|
46
49
|
};
|
|
50
|
+
const QUEUE_META_KEY = '__zintrustQueueMeta';
|
|
51
|
+
let lockProviderCache = null;
|
|
52
|
+
const getLockProviderForQueue = () => {
|
|
53
|
+
if (lockProviderCache)
|
|
54
|
+
return lockProviderCache;
|
|
55
|
+
const providerName = Env.get('QUEUE_LOCK_PROVIDER', ZintrustLang.REDIS).trim();
|
|
56
|
+
const prefix = Env.get('QUEUE_LOCK_PREFIX', ZintrustLang.ZINTRUST_LOCKS_PREFIX).trim();
|
|
57
|
+
const defaultTtl = Env.getInt('QUEUE_DEFAULT_DEDUP_TTL', ZintrustLang.ZINTRUST_LOCKS_TTL);
|
|
58
|
+
const existing = getLockProvider(providerName);
|
|
59
|
+
if (existing) {
|
|
60
|
+
lockProviderCache = existing;
|
|
61
|
+
return existing;
|
|
62
|
+
}
|
|
63
|
+
const provider = createLockProvider({
|
|
64
|
+
type: providerName === ZintrustLang.REDIS ? ZintrustLang.REDIS : ZintrustLang.MEMORY,
|
|
65
|
+
prefix: prefix.length > 0 ? prefix : ZintrustLang.ZINTRUST_LOCKS_PREFIX,
|
|
66
|
+
defaultTtl,
|
|
67
|
+
});
|
|
68
|
+
registerLockProvider(providerName, provider);
|
|
69
|
+
lockProviderCache = provider;
|
|
70
|
+
return provider;
|
|
71
|
+
};
|
|
72
|
+
const extractQueueMeta = (payload) => {
|
|
73
|
+
const metaValue = payload[QUEUE_META_KEY];
|
|
74
|
+
if (metaValue !== undefined && metaValue !== null && typeof metaValue === 'object') {
|
|
75
|
+
const { [QUEUE_META_KEY]: metaRaw, ...rest } = payload;
|
|
76
|
+
return { payload: rest, meta: metaRaw };
|
|
77
|
+
}
|
|
78
|
+
return { payload, meta: undefined };
|
|
79
|
+
};
|
|
80
|
+
const resolveConditionStatus = (condition) => {
|
|
81
|
+
const normalized = condition.trim().toLowerCase();
|
|
82
|
+
if (normalized.includes('failed') || normalized.includes('error'))
|
|
83
|
+
return 'failed';
|
|
84
|
+
if (normalized.includes('success') || normalized.includes('completed'))
|
|
85
|
+
return 'success';
|
|
86
|
+
// Try to extract explicit comparison like: job.result.status === "completed"
|
|
87
|
+
const match = new RegExp(/status\s*={1,3}\s*['"]([a-z]+)['"]/).exec(normalized);
|
|
88
|
+
const capturedValue = match?.[1];
|
|
89
|
+
if (capturedValue !== null && capturedValue !== undefined && capturedValue.length > 0) {
|
|
90
|
+
const value = capturedValue;
|
|
91
|
+
if (value === 'failed' || value === 'error')
|
|
92
|
+
return 'failed';
|
|
93
|
+
if (value === 'success' || value === 'completed')
|
|
94
|
+
return 'success';
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
};
|
|
98
|
+
const shouldReleaseForOutcome = (releaseAfter, outcome) => {
|
|
99
|
+
if (releaseAfter === 'success')
|
|
100
|
+
return outcome === 'success';
|
|
101
|
+
if (releaseAfter === 'failed')
|
|
102
|
+
return outcome === 'failed';
|
|
103
|
+
if (typeof releaseAfter === 'string') {
|
|
104
|
+
const normalized = releaseAfter.toLowerCase();
|
|
105
|
+
if (normalized.includes('failed') || normalized.includes('error'))
|
|
106
|
+
return outcome === 'failed';
|
|
107
|
+
if (normalized.includes('success') || normalized.includes('completed'))
|
|
108
|
+
return outcome === 'success';
|
|
109
|
+
const fromCondition = resolveConditionStatus(normalized);
|
|
110
|
+
return fromCondition !== null && fromCondition === outcome;
|
|
111
|
+
}
|
|
112
|
+
if (releaseAfter !== null && releaseAfter !== undefined && typeof releaseAfter === 'object') {
|
|
113
|
+
const condition = String(releaseAfter.condition ?? '').toLowerCase();
|
|
114
|
+
const fromCondition = resolveConditionStatus(condition);
|
|
115
|
+
return fromCondition !== null && fromCondition === outcome;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
};
|
|
119
|
+
const releaseLockAfterResult = async (meta, outcome) => {
|
|
120
|
+
if (meta === undefined)
|
|
121
|
+
return;
|
|
122
|
+
const deduplicationId = meta.deduplicationId;
|
|
123
|
+
if (deduplicationId === undefined || deduplicationId === null) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const deduplicationKey = String(deduplicationId).trim();
|
|
127
|
+
if (deduplicationKey === '')
|
|
128
|
+
return;
|
|
129
|
+
const releaseAfter = meta.releaseAfter;
|
|
130
|
+
if (releaseAfter === undefined || releaseAfter === null || releaseAfter === '')
|
|
131
|
+
return;
|
|
132
|
+
if (!shouldReleaseForOutcome(releaseAfter, outcome))
|
|
133
|
+
return;
|
|
134
|
+
const provider = getLockProviderForQueue();
|
|
135
|
+
const doRelease = async () => {
|
|
136
|
+
const status = await provider.status(deduplicationKey);
|
|
137
|
+
if (!status.exists)
|
|
138
|
+
return;
|
|
139
|
+
await provider.release({
|
|
140
|
+
key: deduplicationKey,
|
|
141
|
+
ttl: status.ttl ?? 0,
|
|
142
|
+
acquired: true,
|
|
143
|
+
expires: status.expires ?? new Date(),
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
const delay = typeof releaseAfter === 'object' && typeof releaseAfter.delay === 'number'
|
|
147
|
+
? releaseAfter.delay
|
|
148
|
+
: 0;
|
|
149
|
+
if (delay > 0) {
|
|
150
|
+
const timeoutId = globalThis.setTimeout(() => {
|
|
151
|
+
void doRelease();
|
|
152
|
+
}, delay);
|
|
153
|
+
timeoutId.unref();
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
await doRelease();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
47
159
|
const processMessage = async (options, msg, maxAttempts, result) => {
|
|
48
160
|
const payload = msg.payload ?? {};
|
|
49
|
-
const
|
|
161
|
+
const { payload: payloadWithoutMeta, meta } = extractQueueMeta(payload);
|
|
162
|
+
const kind = options.kind ?? detectKindFromPayload(payloadWithoutMeta);
|
|
50
163
|
if (kind === undefined) {
|
|
51
164
|
Logger.warn('Queue worker: unknown job payload; dropping', {
|
|
52
165
|
queue: options.queueName,
|
|
@@ -57,24 +170,28 @@ const processMessage = async (options, msg, maxAttempts, result) => {
|
|
|
57
170
|
await Queue.ack(options.queueName, msg.id, options.driverName);
|
|
58
171
|
return 'continue';
|
|
59
172
|
}
|
|
60
|
-
const timestamp = getTimestamp(
|
|
173
|
+
const timestamp = getTimestamp(payloadWithoutMeta);
|
|
61
174
|
if (typeof timestamp === 'number' && timestamp > Date.now()) {
|
|
62
175
|
// Not due yet: re-enqueue and stop after rotating the head once.
|
|
63
|
-
|
|
176
|
+
const payloadForRequeue = meta
|
|
177
|
+
? { ...payloadWithoutMeta, [QUEUE_META_KEY]: meta }
|
|
178
|
+
: payloadWithoutMeta;
|
|
179
|
+
await Queue.enqueue(options.queueName, payloadForRequeue, options.driverName);
|
|
64
180
|
await Queue.ack(options.queueName, msg.id, options.driverName);
|
|
65
181
|
result.notDueRequeued++;
|
|
66
182
|
return 'break';
|
|
67
183
|
}
|
|
68
|
-
const attempts = getAttempts(
|
|
184
|
+
const attempts = getAttempts(payloadWithoutMeta);
|
|
69
185
|
try {
|
|
70
186
|
if (kind === 'broadcast') {
|
|
71
|
-
const job =
|
|
187
|
+
const job = payloadWithoutMeta;
|
|
72
188
|
await Broadcast.send(job.channel, job.event, job.data);
|
|
73
189
|
}
|
|
74
190
|
else {
|
|
75
|
-
const job =
|
|
191
|
+
const job = payloadWithoutMeta;
|
|
76
192
|
await Notification.send(job.recipient, job.message, job.options ?? {});
|
|
77
193
|
}
|
|
194
|
+
await releaseLockAfterResult(meta, 'success');
|
|
78
195
|
await Queue.ack(options.queueName, msg.id, options.driverName);
|
|
79
196
|
result.processed++;
|
|
80
197
|
return 'continue';
|
|
@@ -91,10 +208,14 @@ const processMessage = async (options, msg, maxAttempts, result) => {
|
|
|
91
208
|
error,
|
|
92
209
|
});
|
|
93
210
|
if (canRetry) {
|
|
94
|
-
|
|
211
|
+
const payloadForRetry = meta
|
|
212
|
+
? { ...payloadWithoutMeta, [QUEUE_META_KEY]: meta }
|
|
213
|
+
: payloadWithoutMeta;
|
|
214
|
+
await Queue.enqueue(options.queueName, withAttempts(payloadForRetry, nextAttempts), options.driverName);
|
|
95
215
|
result.retried++;
|
|
96
216
|
}
|
|
97
217
|
else {
|
|
218
|
+
await releaseLockAfterResult(meta, 'failed');
|
|
98
219
|
result.dropped++;
|
|
99
220
|
}
|
|
100
221
|
await Queue.ack(options.queueName, msg.id, options.driverName);
|
|
@@ -47,7 +47,7 @@ export declare const HealthUtils: {
|
|
|
47
47
|
* Build health response
|
|
48
48
|
*/
|
|
49
49
|
buildHealthResponse(status: "healthy" | "unhealthy" | "alive" | "ready" | "not_ready", environment: string, extra?: Record<string, unknown>): {
|
|
50
|
-
status: "
|
|
50
|
+
status: "ready" | "unhealthy" | "healthy" | "alive" | "not_ready";
|
|
51
51
|
timestamp: string;
|
|
52
52
|
environment: string;
|
|
53
53
|
};
|
|
@@ -55,7 +55,7 @@ export declare const HealthUtils: {
|
|
|
55
55
|
* Build error health response
|
|
56
56
|
*/
|
|
57
57
|
buildErrorResponse(status: "unhealthy" | "not_ready", environment: string, error: Error, extra?: Record<string, unknown>): {
|
|
58
|
-
status: "
|
|
58
|
+
status: "ready" | "unhealthy" | "healthy" | "alive" | "not_ready";
|
|
59
59
|
timestamp: string;
|
|
60
60
|
environment: string;
|
|
61
61
|
};
|
package/src/config/app.d.ts
CHANGED
package/src/config/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/config/app.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,cAAc,CAAC;AAoI3D,QAAA,MAAM,UAAU,QAAO,MAAM,CAAC,UAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/config/app.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,cAAc,CAAC;AAoI3D,QAAA,MAAM,UAAU,QAAO,MAAM,CAAC,UAA2B,CAAC;AAsF1D,eAAO,MAAM,SAAS;IAtEpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;kCACc,OAAO;IAIxB;;OAEG;iCACa,OAAO;IAIvB;;OAEG;8BACU,OAAO;IAIpB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;+BA/EkB,MAAM,CAAC,UAAU;kCAhDd,MAAM;EAsIoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC"}
|
package/src/config/app.js
CHANGED
|
@@ -117,11 +117,20 @@ const normalizeMode = () => {
|
|
|
117
117
|
return 'testing';
|
|
118
118
|
return 'development';
|
|
119
119
|
};
|
|
120
|
+
const Prefix = () => {
|
|
121
|
+
const app_name = (Env.APP_NAME || 'zintrust').toLowerCase().replaceAll(/\s/g, '_');
|
|
122
|
+
const env = Env.NODE_ENV;
|
|
123
|
+
return `${app_name}_zintrust_${env}`;
|
|
124
|
+
};
|
|
120
125
|
const appConfigObj = {
|
|
121
126
|
/**
|
|
122
127
|
* Application name
|
|
123
128
|
*/
|
|
124
129
|
name: readEnvString('APP_NAME', Env.APP_NAME),
|
|
130
|
+
/**
|
|
131
|
+
* Application prefix
|
|
132
|
+
*/
|
|
133
|
+
prefix: Prefix(),
|
|
125
134
|
/**
|
|
126
135
|
* Application environment
|
|
127
136
|
*/
|