@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.
Files changed (172) hide show
  1. package/package.json +4 -3
  2. package/src/auth/Auth.d.ts.map +1 -0
  3. package/src/boot/Application.d.ts.map +1 -1
  4. package/src/boot/Application.js +8 -0
  5. package/src/boot/bootstrap.js +34 -15
  6. package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
  7. package/src/cache/drivers/RedisDriver.js +10 -5
  8. package/src/cli/CLI.d.ts.map +1 -1
  9. package/src/cli/CLI.js +6 -0
  10. package/src/cli/commands/DbSeedCommand.d.ts.map +1 -1
  11. package/src/cli/commands/DbSeedCommand.js +6 -38
  12. package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
  13. package/src/cli/commands/MigrateCommand.js +12 -55
  14. package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -1
  15. package/src/cli/commands/MigrateWorkerCommand.js +8 -54
  16. package/src/cli/commands/NewCommand.d.ts.map +1 -1
  17. package/src/cli/commands/NewCommand.js +1 -13
  18. package/src/cli/commands/QueueCommand.d.ts.map +1 -1
  19. package/src/cli/commands/QueueCommand.js +89 -39
  20. package/src/cli/commands/QueueLockCommand.d.ts +7 -0
  21. package/src/cli/commands/QueueLockCommand.d.ts.map +1 -0
  22. package/src/cli/commands/QueueLockCommand.js +138 -0
  23. package/src/cli/commands/StartCommand.d.ts.map +1 -1
  24. package/src/cli/commands/StartCommand.js +16 -16
  25. package/src/cli/commands/TemplatesCommand.js +1 -1
  26. package/src/cli/commands/WorkerCommands.d.ts.map +1 -1
  27. package/src/cli/commands/WorkerCommands.js +46 -22
  28. package/src/cli/scaffolding/ProjectScaffolder.js +2 -2
  29. package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
  30. package/src/cli/scaffolding/RouteGenerator.js +27 -28
  31. package/src/cli/services/VersionChecker.d.ts +53 -0
  32. package/src/cli/services/VersionChecker.d.ts.map +1 -0
  33. package/src/cli/services/VersionChecker.js +176 -0
  34. package/src/cli/utils/DatabaseCliUtils.d.ts +20 -0
  35. package/src/cli/utils/DatabaseCliUtils.d.ts.map +1 -0
  36. package/src/cli/utils/DatabaseCliUtils.js +54 -0
  37. package/src/cli/workers/QueueWorkRunner.d.ts.map +1 -1
  38. package/src/cli/workers/QueueWorkRunner.js +128 -7
  39. package/src/common/ExternalServiceUtils.d.ts +2 -2
  40. package/src/config/app.d.ts +4 -0
  41. package/src/config/app.d.ts.map +1 -1
  42. package/src/config/app.js +9 -0
  43. package/src/config/constants.d.ts +140 -10
  44. package/src/config/constants.d.ts.map +1 -1
  45. package/src/config/constants.js +86 -5
  46. package/src/config/index.d.ts +1 -0
  47. package/src/config/index.d.ts.map +1 -1
  48. package/src/config/middleware.d.ts +6 -6
  49. package/src/config/middleware.d.ts.map +1 -1
  50. package/src/config/middleware.js +6 -7
  51. package/src/config/queue.d.ts +4 -0
  52. package/src/config/queue.d.ts.map +1 -1
  53. package/src/config/queue.js +1 -1
  54. package/src/config/redis.d.ts +17 -0
  55. package/src/config/redis.d.ts.map +1 -0
  56. package/src/config/redis.js +54 -0
  57. package/src/config/type.d.ts +3 -0
  58. package/src/config/type.d.ts.map +1 -1
  59. package/src/http/Request.d.ts +10 -1
  60. package/src/http/Request.d.ts.map +1 -1
  61. package/src/http/Request.js +79 -7
  62. package/src/http/error-pages/ErrorPageRenderer.d.ts.map +1 -1
  63. package/src/http/error-pages/ErrorPageRenderer.js +4 -3
  64. package/src/index.d.ts +14 -11
  65. package/src/index.d.ts.map +1 -1
  66. package/src/index.js +18 -11
  67. package/src/lang/lang.d.ts +23 -0
  68. package/src/lang/lang.d.ts.map +1 -0
  69. package/src/lang/lang.js +22 -0
  70. package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
  71. package/src/middleware/ErrorHandlerMiddleware.js +9 -1
  72. package/src/migrations/schema/SchemaCompiler.js +1 -1
  73. package/src/migrations/schema/types.d.ts +1 -1
  74. package/src/migrations/schema/types.d.ts.map +1 -1
  75. package/src/node.d.ts +1 -1
  76. package/src/node.d.ts.map +1 -1
  77. package/src/node.js +1 -1
  78. package/src/orm/Database.d.ts +1 -1
  79. package/src/orm/Database.d.ts.map +1 -1
  80. package/src/orm/Database.js +22 -3
  81. package/src/performance/Optimizer.js +1 -1
  82. package/src/routing/Router.d.ts +6 -2
  83. package/src/routing/Router.d.ts.map +1 -1
  84. package/src/routing/Router.js +19 -4
  85. package/src/runtime/PluginAutoImports.d.ts.map +1 -1
  86. package/src/runtime/PluginAutoImports.js +1 -13
  87. package/src/runtime/PluginManager.d.ts.map +1 -1
  88. package/src/runtime/PluginManager.js +2 -14
  89. package/src/runtime/PluginRegistry.js +2 -2
  90. package/src/start.d.ts.map +1 -1
  91. package/src/start.js +8 -7
  92. package/src/templates/TemplateRegistry.js +2 -2
  93. package/src/templates/TemplateRegistry.ts +2 -2
  94. package/src/templates/feature/Queue.ts.tpl +114 -0
  95. package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +22 -0
  96. package/src/templates/project/basic/config/queue.ts.tpl +19 -0
  97. package/src/templates/project/basic/package.json.tpl +2 -1
  98. package/src/templates/project/basic/src/index.ts.tpl +0 -3
  99. package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -1
  100. package/src/toolkit/Secrets/providers/AwsSecretsManager.js +1 -13
  101. package/src/toolkit/Secrets/providers/CloudflareKv.d.ts.map +1 -1
  102. package/src/toolkit/Secrets/providers/CloudflareKv.js +4 -16
  103. package/src/tools/broadcast/drivers/Redis.d.ts.map +1 -1
  104. package/src/tools/broadcast/drivers/Redis.js +8 -56
  105. package/src/tools/mail/Mail.d.ts +1 -29
  106. package/src/tools/mail/Mail.d.ts.map +1 -1
  107. package/src/tools/mail/Mail.js +1 -111
  108. package/src/tools/mail/drivers/SendGrid.d.ts.map +1 -1
  109. package/src/tools/mail/drivers/SendGrid.js +4 -3
  110. package/src/tools/mail/drivers/Smtp.d.ts.map +1 -1
  111. package/src/tools/mail/drivers/Smtp.js +32 -10
  112. package/src/tools/mail/index.d.ts +40 -0
  113. package/src/tools/mail/index.d.ts.map +1 -0
  114. package/src/tools/mail/index.js +129 -0
  115. package/src/tools/mail/template-loader.d.ts +10 -0
  116. package/src/tools/mail/template-loader.d.ts.map +1 -0
  117. package/src/tools/mail/template-loader.js +101 -0
  118. package/src/tools/mail/template-utils.d.ts +10 -0
  119. package/src/tools/mail/template-utils.d.ts.map +1 -0
  120. package/src/tools/mail/template-utils.js +16 -0
  121. package/src/tools/mail/templates/index.d.ts +30 -0
  122. package/src/tools/mail/templates/index.d.ts.map +1 -1
  123. package/src/tools/mail/templates/index.js +69 -0
  124. package/src/tools/queue/AdvancedQueue.d.ts +19 -0
  125. package/src/tools/queue/AdvancedQueue.d.ts.map +1 -0
  126. package/src/tools/queue/AdvancedQueue.js +352 -0
  127. package/src/tools/queue/DeduplicationBuilder.d.ts +20 -0
  128. package/src/tools/queue/DeduplicationBuilder.d.ts.map +1 -0
  129. package/src/tools/queue/DeduplicationBuilder.js +77 -0
  130. package/src/tools/queue/LockProvider.d.ts +25 -0
  131. package/src/tools/queue/LockProvider.d.ts.map +1 -0
  132. package/src/tools/queue/LockProvider.js +276 -0
  133. package/src/tools/queue/Queue.d.ts.map +1 -1
  134. package/src/tools/queue/Queue.js +2 -1
  135. package/src/tools/queue/QueueExtensions.d.ts +46 -0
  136. package/src/tools/queue/QueueExtensions.d.ts.map +1 -0
  137. package/src/tools/queue/QueueExtensions.js +129 -0
  138. package/src/tools/queue/QueueRuntimeRegistration.d.ts.map +1 -1
  139. package/src/tools/queue/QueueRuntimeRegistration.js +2 -2
  140. package/src/tools/queue/drivers/Database.d.ts +23 -0
  141. package/src/tools/queue/drivers/Database.d.ts.map +1 -0
  142. package/src/tools/queue/drivers/Database.js +123 -0
  143. package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
  144. package/src/tools/queue/drivers/Redis.js +11 -82
  145. package/src/tools/queue/index.d.ts +9 -0
  146. package/src/tools/queue/index.d.ts.map +1 -0
  147. package/src/tools/queue/index.js +7 -0
  148. package/src/tools/redis/RedisKeyManager.d.ts +64 -0
  149. package/src/tools/redis/RedisKeyManager.d.ts.map +1 -0
  150. package/src/tools/redis/RedisKeyManager.js +124 -0
  151. package/src/tools/storage/drivers/S3.d.ts.map +1 -1
  152. package/src/tools/storage/drivers/S3.js +4 -16
  153. package/src/types/Queue.d.ts +62 -0
  154. package/src/types/Queue.d.ts.map +1 -0
  155. package/src/types/Queue.js +5 -0
  156. package/src/features/Auth.d.ts.map +0 -1
  157. package/src/features/Queue.d.ts +0 -21
  158. package/src/features/Queue.d.ts.map +0 -1
  159. package/src/features/Queue.js +0 -33
  160. package/src/templates/features/Queue.ts.tpl +0 -47
  161. package/src/tools/mail/templates/markdown/index.d.ts +0 -17
  162. package/src/tools/mail/templates/markdown/index.d.ts.map +0 -1
  163. package/src/tools/mail/templates/markdown/index.js +0 -49
  164. package/src/tools/mail/templates/markdown/registry.d.ts +0 -15
  165. package/src/tools/mail/templates/markdown/registry.d.ts.map +0 -1
  166. package/src/tools/mail/templates/markdown/registry.js +0 -34
  167. package/src/tools/mail/templates/markdown/validator.d.ts +0 -16
  168. package/src/tools/mail/templates/markdown/validator.d.ts.map +0 -1
  169. package/src/tools/mail/templates/markdown/validator.js +0 -24
  170. /package/src/{features → auth}/Auth.d.ts +0 -0
  171. /package/src/{features → auth}/Auth.js +0 -0
  172. /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":"AAQA,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;AAyHF,eAAO,MAAM,eAAe;iBACP,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;qBAuCzD,OAAO,GAAG,aAAa;EAUxC,CAAC;AAEH,eAAe,eAAe,CAAC"}
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 kind = options.kind ?? detectKindFromPayload(payload);
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(payload);
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
- await Queue.enqueue(options.queueName, payload, options.driverName);
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(payload);
184
+ const attempts = getAttempts(payloadWithoutMeta);
69
185
  try {
70
186
  if (kind === 'broadcast') {
71
- const job = payload;
187
+ const job = payloadWithoutMeta;
72
188
  await Broadcast.send(job.channel, job.event, job.data);
73
189
  }
74
190
  else {
75
- const job = payload;
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
- await Queue.enqueue(options.queueName, withAttempts(payload, nextAttempts), options.driverName);
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: "unhealthy" | "ready" | "healthy" | "alive" | "not_ready";
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: "unhealthy" | "ready" | "healthy" | "alive" | "not_ready";
58
+ status: "ready" | "unhealthy" | "healthy" | "alive" | "not_ready";
59
59
  timestamp: string;
60
60
  environment: string;
61
61
  };
@@ -10,6 +10,10 @@ export declare const appConfig: Readonly<{
10
10
  * Application name
11
11
  */
12
12
  readonly name: string;
13
+ /**
14
+ * Application prefix
15
+ */
16
+ readonly prefix: string;
13
17
  /**
14
18
  * Application environment
15
19
  */
@@ -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;AA2E1D,eAAO,MAAM,SAAS;IAjEpB;;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;;+BApEkB,MAAM,CAAC,UAAU;kCAhDd,MAAM;EA2HoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,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
  */