@zintrust/core 0.1.38 → 0.1.40
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 +0 -0
- package/bin/zin.js +0 -0
- package/bin/zintrust.js +0 -0
- package/bin/zt.js +0 -0
- package/package.json +2 -2
- package/public/index.html +2 -2
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +101 -74
- package/src/boot/bootstrap.js +2 -6
- package/src/cli/PromptHelper.js +2 -2
- package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateWorkerCommand.js +1 -1
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +16 -4
- package/src/cli/utils/EnvFileLoader.d.ts +2 -1
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/cli/utils/EnvFileLoader.js +8 -8
- package/src/cli/utils/spawn.d.ts.map +1 -1
- package/src/cli/utils/spawn.js +17 -10
- package/src/cli/workers/QueueWorkRunner.d.ts.map +1 -1
- package/src/cli/workers/QueueWorkRunner.js +5 -5
- package/src/common/ExternalServiceUtils.d.ts.map +1 -1
- package/src/common/ExternalServiceUtils.js +7 -2
- package/src/config/env.d.ts +5 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +7 -1
- package/src/config/index.d.ts +1 -1
- package/src/config/logger.d.ts.map +1 -1
- package/src/config/logger.js +60 -16
- package/src/config/queue.d.ts +1 -1
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +11 -6
- package/src/config/redis.d.ts.map +1 -1
- package/src/config/redis.js +3 -2
- package/src/config/type.d.ts +9 -5
- package/src/config/type.d.ts.map +1 -1
- package/src/config/workers.d.ts.map +1 -1
- package/src/config/workers.js +4 -0
- package/src/index.d.ts +3 -2
- package/src/index.d.ts.map +1 -1
- package/src/index.js +3 -4
- package/src/lang/lang.d.ts +3 -0
- package/src/lang/lang.d.ts.map +1 -1
- package/src/lang/lang.js +3 -0
- package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
- package/src/middleware/CsrfMiddleware.js +26 -11
- package/src/orm/Model.d.ts.map +1 -1
- package/src/orm/Model.js +17 -6
- package/src/routes/errorPages.js +1 -1
- package/src/runtime/PluginAutoImports.d.ts.map +1 -1
- package/src/runtime/PluginAutoImports.js +33 -7
- package/src/security/CsrfTokenManager.d.ts +18 -9
- package/src/security/CsrfTokenManager.d.ts.map +1 -1
- package/src/security/CsrfTokenManager.js +192 -11
- package/src/templates/project/basic/app/Middleware/index.ts.tpl +1 -1
- package/src/templates/project/basic/config/queue.ts.tpl +2 -2
- package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -1
- package/src/toolkit/Secrets/providers/AwsSecretsManager.js +4 -2
- package/src/tools/queue/AdvancedQueue.d.ts +2 -1
- package/src/tools/queue/AdvancedQueue.d.ts.map +1 -1
- package/src/tools/queue/AdvancedQueue.js +2 -1
- package/src/tools/queue/LockProvider.d.ts +4 -0
- package/src/tools/queue/LockProvider.d.ts.map +1 -1
- package/src/tools/queue/LockProvider.js +16 -0
- package/src/tools/queue/Queue.d.ts +38 -2
- package/src/tools/queue/Queue.d.ts.map +1 -1
- package/src/tools/queue/Queue.js +3 -2
- package/src/tools/queue/QueueExtensions.d.ts +2 -1
- package/src/tools/queue/QueueExtensions.d.ts.map +1 -1
- package/src/tools/redis/RedisKeyManager.d.ts +3 -0
- package/src/tools/redis/RedisKeyManager.d.ts.map +1 -1
- package/src/tools/redis/RedisKeyManager.js +23 -8
package/src/orm/Model.js
CHANGED
|
@@ -69,14 +69,25 @@ const runObservers = async (config, hook, model) => {
|
|
|
69
69
|
const observers = config.observers;
|
|
70
70
|
if (observers === undefined || observers.length === 0)
|
|
71
71
|
return;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
// Run "before" hooks sequentially to ensure safety and consistent state changes.
|
|
73
|
+
// This allows observers to modify the model or throw errors to cancel the operation.
|
|
74
|
+
const isBeforeHook = ['saving', 'creating', 'updating', 'deleting'].includes(hook);
|
|
75
|
+
if (isBeforeHook) {
|
|
76
|
+
for (const observer of observers) {
|
|
77
|
+
const fn = observer[hook];
|
|
78
|
+
if (typeof fn === 'function') {
|
|
79
|
+
// eslint-disable-next-line no-await-in-loop
|
|
80
|
+
await fn(model);
|
|
81
|
+
}
|
|
78
82
|
}
|
|
83
|
+
return;
|
|
79
84
|
}
|
|
85
|
+
// Run "after" hooks in parallel for better performance.
|
|
86
|
+
// These are typically side effects (logging, notifications) that don't depend on each other.
|
|
87
|
+
await Promise.all(observers.map(async (observer) => {
|
|
88
|
+
const fn = observer[hook];
|
|
89
|
+
return typeof fn === 'function' ? Promise.resolve(fn(model)) : Promise.resolve();
|
|
90
|
+
}));
|
|
80
91
|
};
|
|
81
92
|
const createModelJSON = (config, attrs) => {
|
|
82
93
|
const json = {};
|
package/src/routes/errorPages.js
CHANGED
|
@@ -31,7 +31,7 @@ const servePublicRootFile = (relativePath, response, contentType) => {
|
|
|
31
31
|
const candidates = candidateRoots.map((root) => path.join(root, relativePath));
|
|
32
32
|
const filePath = findFirstExistingFile(candidates);
|
|
33
33
|
try {
|
|
34
|
-
if (
|
|
34
|
+
if (filePath === undefined || filePath === null) {
|
|
35
35
|
response.setStatus(404);
|
|
36
36
|
response.setHeader(HTTP_HEADERS.CONTENT_TYPE, MIME_TYPES.TEXT);
|
|
37
37
|
response.send('Not Found');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAwBN,eAAO,MAAM,iBAAiB;IAC5B;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PluginAutoImports.d.ts","sourceRoot":"","sources":["../../../src/runtime/PluginAutoImports.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,eAAe,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAwBN,eAAO,MAAM,iBAAiB;IAC5B;;;;;;OAMG;mCACkC,OAAO,CAAC,YAAY,CAAC;EA2D1D,CAAC"}
|
|
@@ -33,21 +33,47 @@ export const PluginAutoImports = Object.freeze({
|
|
|
33
33
|
async tryImportProjectAutoImports() {
|
|
34
34
|
const projectRoot = resolveProjectRoot();
|
|
35
35
|
const candidates = getCandidates(projectRoot);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
// Filter out non-existent candidates first
|
|
37
|
+
const existingCandidates = candidates.filter((candidate) => existsSync(candidate));
|
|
38
|
+
if (existingCandidates.length === 0) {
|
|
39
|
+
Logger.debug('[plugins] No plugin auto-imports file found', { projectRoot, candidates });
|
|
40
|
+
return { ok: false, reason: 'not-found' };
|
|
41
|
+
}
|
|
42
|
+
// Try all existing candidates in parallel
|
|
43
|
+
const importPromises = existingCandidates.map(async (candidate) => {
|
|
39
44
|
try {
|
|
40
45
|
const url = pathToFileURL(candidate).href;
|
|
41
|
-
// eslint-disable-next-line no-await-in-loop
|
|
42
46
|
await import(url);
|
|
43
47
|
return { ok: true, loadedPath: candidate };
|
|
44
48
|
}
|
|
45
49
|
catch (error) {
|
|
46
50
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
47
|
-
return {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
loadedPath: candidate,
|
|
54
|
+
reason: 'import-failed',
|
|
55
|
+
errorMessage,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// Return the first successful import, or the first failure if none succeed
|
|
60
|
+
try {
|
|
61
|
+
const results = await Promise.allSettled(importPromises);
|
|
62
|
+
const successfulResult = results.find((result) => result.status === 'fulfilled' && result.value.ok);
|
|
63
|
+
if (successfulResult) {
|
|
64
|
+
return successfulResult.value;
|
|
48
65
|
}
|
|
66
|
+
// Return the first failed result if no success
|
|
67
|
+
const firstFailedResult = results.find((result) => result.status === 'fulfilled' && !result.value.ok);
|
|
68
|
+
return (firstFailedResult?.value ?? {
|
|
69
|
+
ok: false,
|
|
70
|
+
reason: 'import-failed',
|
|
71
|
+
errorMessage: 'All candidates failed',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
76
|
+
return { ok: false, reason: 'import-failed', errorMessage };
|
|
49
77
|
}
|
|
50
|
-
Logger.debug('[plugins] No plugin auto-imports file found', { projectRoot, candidates });
|
|
51
|
-
return { ok: false, reason: 'not-found' };
|
|
52
78
|
},
|
|
53
79
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* CSRF Token Manager
|
|
3
3
|
* Generate, validate, and bind CSRF tokens to sessions
|
|
4
4
|
*/
|
|
5
|
+
import type { Redis } from 'ioredis';
|
|
5
6
|
export interface CsrfTokenData {
|
|
6
7
|
token: string;
|
|
7
8
|
sessionId: string;
|
|
@@ -9,18 +10,26 @@ export interface CsrfTokenData {
|
|
|
9
10
|
expiresAt: Date;
|
|
10
11
|
}
|
|
11
12
|
export interface ICsrfTokenManager {
|
|
12
|
-
generateToken(sessionId: string): string
|
|
13
|
-
validateToken(sessionId: string, token: string): boolean
|
|
14
|
-
invalidateToken(sessionId: string): void
|
|
15
|
-
getTokenData(sessionId: string): CsrfTokenData | null
|
|
16
|
-
refreshToken(sessionId: string): string | null
|
|
17
|
-
cleanup(): number
|
|
18
|
-
clear(): void
|
|
19
|
-
getTokenCount(): number
|
|
13
|
+
generateToken(sessionId: string): Promise<string>;
|
|
14
|
+
validateToken(sessionId: string, token: string): Promise<boolean>;
|
|
15
|
+
invalidateToken(sessionId: string): Promise<void>;
|
|
16
|
+
getTokenData(sessionId: string): Promise<CsrfTokenData | null>;
|
|
17
|
+
refreshToken(sessionId: string): Promise<string | null>;
|
|
18
|
+
cleanup(): Promise<number>;
|
|
19
|
+
clear(): Promise<void>;
|
|
20
|
+
getTokenCount(): Promise<number>;
|
|
20
21
|
}
|
|
21
22
|
export interface CsrfTokenManagerType {
|
|
22
|
-
create(): ICsrfTokenManager;
|
|
23
|
+
create(options?: CsrfTokenManagerOptions): ICsrfTokenManager;
|
|
23
24
|
}
|
|
25
|
+
export type CsrfStoreName = 'memory' | 'redis';
|
|
26
|
+
export type CsrfTokenManagerOptions = {
|
|
27
|
+
store?: CsrfStoreName;
|
|
28
|
+
redis?: Redis;
|
|
29
|
+
keyPrefix?: string;
|
|
30
|
+
tokenLength?: number;
|
|
31
|
+
tokenTtlMs?: number;
|
|
32
|
+
};
|
|
24
33
|
/**
|
|
25
34
|
* CsrfTokenManager namespace - sealed for immutability
|
|
26
35
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CsrfTokenManager.d.ts","sourceRoot":"","sources":["../../../src/security/CsrfTokenManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CsrfTokenManager.d.ts","sourceRoot":"","sources":["../../../src/security/CsrfTokenManager.ts"],"names":[],"mappings":"AACA;;;GAGG;AAQH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC/D,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,iBAAiB,CAAC;CAC9D;AAED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/C,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAwRF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,oBAE7B,CAAC"}
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
1
2
|
/**
|
|
2
3
|
* CSRF Token Manager
|
|
3
4
|
* Generate, validate, and bind CSRF tokens to sessions
|
|
4
5
|
*/
|
|
5
6
|
import { Env } from '../config/env.js';
|
|
7
|
+
import { Logger } from '../config/logger.js';
|
|
8
|
+
import { createRedisConnection } from '../config/workers.js';
|
|
9
|
+
import { ZintrustLang } from '../lang/lang.js';
|
|
6
10
|
import { randomBytes } from '../node-singletons/crypto.js';
|
|
11
|
+
import { RedisKeys } from '../tools/redis/RedisKeyManager.js';
|
|
7
12
|
/**
|
|
8
13
|
* Create a new CSRF token manager instance
|
|
9
14
|
*/
|
|
10
|
-
const
|
|
15
|
+
const normalizeStoreName = (name) => {
|
|
16
|
+
const raw = String(name ?? '')
|
|
17
|
+
.trim()
|
|
18
|
+
.toLowerCase();
|
|
19
|
+
if (raw === 'redis')
|
|
20
|
+
return 'redis';
|
|
21
|
+
return 'memory';
|
|
22
|
+
};
|
|
23
|
+
const resolveStoreName = (options) => {
|
|
24
|
+
return normalizeStoreName(options?.store ?? Env.CSRF_STORE ?? Env.CSRF_DRIVER ?? Env.get('CSRF_STORE', 'memory'));
|
|
25
|
+
};
|
|
26
|
+
const toTokenData = (stored) => {
|
|
27
|
+
return {
|
|
28
|
+
token: stored.token,
|
|
29
|
+
sessionId: stored.sessionId,
|
|
30
|
+
createdAt: new Date(stored.createdAt),
|
|
31
|
+
expiresAt: new Date(stored.expiresAt),
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const createMemoryManager = (tokenLength, tokenTtl) => {
|
|
11
35
|
const tokens = new Map();
|
|
12
|
-
const tokenLength = Env.TOKEN_LENGTH; // 256 bits
|
|
13
|
-
const tokenTtl = Env.TOKEN_TTL; // 1 hour in milliseconds
|
|
14
36
|
return {
|
|
15
|
-
generateToken(sessionId) {
|
|
37
|
+
async generateToken(sessionId) {
|
|
16
38
|
tokens.delete(sessionId);
|
|
17
39
|
const token = randomBytes(tokenLength).toString('hex');
|
|
18
40
|
const now = new Date();
|
|
@@ -21,7 +43,7 @@ const create = () => {
|
|
|
21
43
|
tokens.set(sessionId, tokenData);
|
|
22
44
|
return token;
|
|
23
45
|
},
|
|
24
|
-
validateToken(sessionId, token) {
|
|
46
|
+
async validateToken(sessionId, token) {
|
|
25
47
|
const tokenData = tokens.get(sessionId);
|
|
26
48
|
if (!tokenData)
|
|
27
49
|
return false;
|
|
@@ -33,13 +55,13 @@ const create = () => {
|
|
|
33
55
|
}
|
|
34
56
|
return isValid;
|
|
35
57
|
},
|
|
36
|
-
invalidateToken(sessionId) {
|
|
58
|
+
async invalidateToken(sessionId) {
|
|
37
59
|
tokens.delete(sessionId);
|
|
38
60
|
},
|
|
39
|
-
getTokenData(sessionId) {
|
|
61
|
+
async getTokenData(sessionId) {
|
|
40
62
|
return tokens.get(sessionId) ?? null;
|
|
41
63
|
},
|
|
42
|
-
refreshToken(sessionId) {
|
|
64
|
+
async refreshToken(sessionId) {
|
|
43
65
|
const tokenData = tokens.get(sessionId);
|
|
44
66
|
if (!tokenData)
|
|
45
67
|
return null;
|
|
@@ -51,7 +73,7 @@ const create = () => {
|
|
|
51
73
|
tokenData.expiresAt = new Date(Date.now() + tokenTtl);
|
|
52
74
|
return tokenData.token;
|
|
53
75
|
},
|
|
54
|
-
cleanup() {
|
|
76
|
+
async cleanup() {
|
|
55
77
|
let removed = 0;
|
|
56
78
|
const now = new Date();
|
|
57
79
|
for (const [sessionId, tokenData] of tokens.entries()) {
|
|
@@ -62,14 +84,173 @@ const create = () => {
|
|
|
62
84
|
}
|
|
63
85
|
return removed;
|
|
64
86
|
},
|
|
65
|
-
clear() {
|
|
87
|
+
async clear() {
|
|
66
88
|
tokens.clear();
|
|
67
89
|
},
|
|
68
|
-
getTokenCount() {
|
|
90
|
+
async getTokenCount() {
|
|
69
91
|
return tokens.size;
|
|
70
92
|
},
|
|
71
93
|
};
|
|
72
94
|
};
|
|
95
|
+
// Helper functions for Redis CSRF manager
|
|
96
|
+
const createRedisClientFactory = (options) => {
|
|
97
|
+
let redisClient = options?.redis ?? null;
|
|
98
|
+
return () => {
|
|
99
|
+
if (redisClient)
|
|
100
|
+
return redisClient;
|
|
101
|
+
const dbFromEnv = Env.CSRF_REDIS_DB;
|
|
102
|
+
const database = dbFromEnv >= 0 ? dbFromEnv : Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB);
|
|
103
|
+
redisClient = createRedisConnection({
|
|
104
|
+
host: Env.get('REDIS_HOST', 'localhost'),
|
|
105
|
+
port: Env.getInt('REDIS_PORT', ZintrustLang.REDIS_DEFAULT_PORT),
|
|
106
|
+
password: Env.get('REDIS_PASSWORD'),
|
|
107
|
+
db: database,
|
|
108
|
+
});
|
|
109
|
+
return redisClient;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
const createRedisTokenOperations = (keyPrefix, tokenTtl, getRedisClient) => {
|
|
113
|
+
const buildKey = (sessionId) => `${keyPrefix}${sessionId}`;
|
|
114
|
+
const fetchTokenData = async (sessionId) => {
|
|
115
|
+
try {
|
|
116
|
+
const client = getRedisClient();
|
|
117
|
+
const payload = await client.get(buildKey(sessionId));
|
|
118
|
+
if (payload === null || payload === '')
|
|
119
|
+
return null;
|
|
120
|
+
const parsed = JSON.parse(payload);
|
|
121
|
+
return toTokenData(parsed);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
Logger.error('CSRF Redis fetch failed', error);
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const saveTokenData = async (data) => {
|
|
129
|
+
try {
|
|
130
|
+
const client = getRedisClient();
|
|
131
|
+
const stored = {
|
|
132
|
+
token: data.token,
|
|
133
|
+
sessionId: data.sessionId,
|
|
134
|
+
createdAt: data.createdAt.getTime(),
|
|
135
|
+
expiresAt: data.expiresAt.getTime(),
|
|
136
|
+
};
|
|
137
|
+
await client.set(buildKey(data.sessionId), JSON.stringify(stored), 'PX', tokenTtl);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
Logger.error('CSRF Redis save failed', error);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const deleteToken = async (sessionId) => {
|
|
144
|
+
try {
|
|
145
|
+
const client = getRedisClient();
|
|
146
|
+
await client.del(buildKey(sessionId));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
Logger.error('CSRF Redis delete failed', error);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const scanKeys = async () => {
|
|
153
|
+
const client = getRedisClient();
|
|
154
|
+
const keys = [];
|
|
155
|
+
const stream = client.scanStream({ match: `${keyPrefix}*`, count: 200 });
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
stream.on('data', (resultKeys) => {
|
|
158
|
+
if (Array.isArray(resultKeys) && resultKeys.length) {
|
|
159
|
+
keys.push(...resultKeys);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
stream.on('end', () => resolve(keys));
|
|
163
|
+
stream.on('error', (err) => reject(err));
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
fetchTokenData,
|
|
168
|
+
saveTokenData,
|
|
169
|
+
deleteToken,
|
|
170
|
+
scanKeys,
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
const createRedisManager = (tokenLength, tokenTtl, options) => {
|
|
174
|
+
const keyPrefix = options?.keyPrefix ?? RedisKeys.getCsrfPrefix();
|
|
175
|
+
const getRedisClient = createRedisClientFactory(options);
|
|
176
|
+
const { fetchTokenData, saveTokenData, deleteToken, scanKeys } = createRedisTokenOperations(keyPrefix, tokenTtl, getRedisClient);
|
|
177
|
+
return {
|
|
178
|
+
async generateToken(sessionId) {
|
|
179
|
+
const token = randomBytes(tokenLength).toString('hex');
|
|
180
|
+
const now = new Date();
|
|
181
|
+
const expiresAt = new Date(now.getTime() + tokenTtl);
|
|
182
|
+
const tokenData = { token, sessionId, createdAt: now, expiresAt };
|
|
183
|
+
await saveTokenData(tokenData);
|
|
184
|
+
return token;
|
|
185
|
+
},
|
|
186
|
+
async validateToken(sessionId, token) {
|
|
187
|
+
const tokenData = await fetchTokenData(sessionId);
|
|
188
|
+
if (!tokenData)
|
|
189
|
+
return false;
|
|
190
|
+
const isValid = tokenData.token === token;
|
|
191
|
+
const isExpired = new Date() > tokenData.expiresAt;
|
|
192
|
+
if (isExpired) {
|
|
193
|
+
await deleteToken(sessionId);
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
return isValid;
|
|
197
|
+
},
|
|
198
|
+
async invalidateToken(sessionId) {
|
|
199
|
+
await deleteToken(sessionId);
|
|
200
|
+
},
|
|
201
|
+
async getTokenData(sessionId) {
|
|
202
|
+
return fetchTokenData(sessionId);
|
|
203
|
+
},
|
|
204
|
+
async refreshToken(sessionId) {
|
|
205
|
+
const tokenData = await fetchTokenData(sessionId);
|
|
206
|
+
if (!tokenData)
|
|
207
|
+
return null;
|
|
208
|
+
const isExpired = new Date() > tokenData.expiresAt;
|
|
209
|
+
if (isExpired) {
|
|
210
|
+
await deleteToken(sessionId);
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
tokenData.expiresAt = new Date(Date.now() + tokenTtl);
|
|
214
|
+
await saveTokenData(tokenData);
|
|
215
|
+
return tokenData.token;
|
|
216
|
+
},
|
|
217
|
+
async cleanup() {
|
|
218
|
+
// Redis handles expiry via TTL, so nothing to do here.
|
|
219
|
+
return Promise.resolve(0); // NOSONAR
|
|
220
|
+
},
|
|
221
|
+
async clear() {
|
|
222
|
+
try {
|
|
223
|
+
const keys = await scanKeys();
|
|
224
|
+
if (keys.length === 0)
|
|
225
|
+
return;
|
|
226
|
+
const client = getRedisClient();
|
|
227
|
+
await client.del(...keys);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
Logger.error('CSRF Redis clear failed', error);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
async getTokenCount() {
|
|
234
|
+
try {
|
|
235
|
+
const keys = await scanKeys();
|
|
236
|
+
return keys.length;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
Logger.error('CSRF Redis count failed', error);
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
const create = (options) => {
|
|
246
|
+
const tokenLength = options?.tokenLength ?? Env.TOKEN_LENGTH; // 256 bits
|
|
247
|
+
const tokenTtl = options?.tokenTtlMs ?? Env.TOKEN_TTL; // 1 hour in milliseconds
|
|
248
|
+
const store = resolveStoreName(options);
|
|
249
|
+
if (store === 'redis') {
|
|
250
|
+
return createRedisManager(tokenLength, tokenTtl, options);
|
|
251
|
+
}
|
|
252
|
+
return createMemoryManager(tokenLength, tokenTtl);
|
|
253
|
+
};
|
|
73
254
|
/**
|
|
74
255
|
* CsrfTokenManager namespace - sealed for immutability
|
|
75
256
|
*/
|
|
@@ -220,7 +220,7 @@ export const csrfMiddleware = (csrfManager: CsrfManagerInput) => {
|
|
|
220
220
|
return;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
const isValid = resolveCsrfManager(csrfManager).validateToken(
|
|
223
|
+
const isValid = await resolveCsrfManager(csrfManager).validateToken(
|
|
224
224
|
String(sessionId),
|
|
225
225
|
String(csrfToken)
|
|
226
226
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Env, type QueueConfigOverrides, type QueueDriverName } from '@zintrust/core';
|
|
1
|
+
import { Env, type QueueConfigOverrides, type QueueDriverName, ZintrustLang } from '@zintrust/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Queue Configuration (default override)
|
|
@@ -41,7 +41,7 @@ export default {
|
|
|
41
41
|
host: Env.get('REDIS_HOST', 'localhost'),
|
|
42
42
|
port: Env.getInt('REDIS_PORT', 6379),
|
|
43
43
|
password: Env.get('REDIS_PASSWORD'),
|
|
44
|
-
database: Env.getInt('REDIS_QUEUE_DB',
|
|
44
|
+
database: Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB),
|
|
45
45
|
// Note: Redis driver uses BullMQ for enterprise features
|
|
46
46
|
// See BullMQ environment variables in file header for customization
|
|
47
47
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AwsSecretsManager.d.ts","sourceRoot":"","sources":["../../../../../src/toolkit/Secrets/providers/AwsSecretsManager.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AA0GF,eAAO,MAAM,iBAAiB;qBACX;QACf,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACzE,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9D;iBAsDY,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"AwsSecretsManager.d.ts","sourceRoot":"","sources":["../../../../../src/toolkit/Secrets/providers/AwsSecretsManager.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AA0GF,eAAO,MAAM,iBAAiB;qBACX;QACf,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACzE,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9D;iBAsDY,MAAM,EAAE;EAkBrB,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
|
|
@@ -117,9 +117,11 @@ export const AwsSecretsManager = Object.freeze({
|
|
|
117
117
|
},
|
|
118
118
|
doctorEnv() {
|
|
119
119
|
const missing = [];
|
|
120
|
-
const
|
|
121
|
-
|
|
120
|
+
const awsRegion = readEnvString('AWS_REGION').trim();
|
|
121
|
+
const awsDefaultRegion = readEnvString('AWS_DEFAULT_REGION').trim();
|
|
122
|
+
if (awsRegion === '' && awsDefaultRegion === '') {
|
|
122
123
|
missing.push('AWS_REGION');
|
|
124
|
+
}
|
|
123
125
|
const accessKeyId = readEnvString('AWS_ACCESS_KEY_ID').trim();
|
|
124
126
|
if (accessKeyId === '')
|
|
125
127
|
missing.push('AWS_ACCESS_KEY_ID');
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { AdvancedJobOptions, JobResult, QueueConfig } from '../../types/Queue';
|
|
6
6
|
import { type DeduplicationBuilder } from './DeduplicationBuilder';
|
|
7
|
+
import type { BullMQPayload } from './Queue';
|
|
7
8
|
export interface AdvancedQueue {
|
|
8
|
-
enqueue(name: string, payload:
|
|
9
|
+
enqueue(name: string, payload: BullMQPayload, options: AdvancedJobOptions): Promise<string>;
|
|
9
10
|
deduplicate(id: string, builder: DeduplicationBuilder): Promise<JobResult>;
|
|
10
11
|
releaseLock(key: string): Promise<void>;
|
|
11
12
|
extendLock(key: string, ttl: number): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdvancedQueue.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/AdvancedQueue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAElB,SAAS,EAGT,WAAW,EACZ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"AdvancedQueue.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/AdvancedQueue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAElB,SAAS,EAGT,WAAW,EACZ,MAAM,eAAe,CAAC;AAOvB,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5F,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3E,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAiBtE"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Env } from '../../config/env.js';
|
|
6
6
|
import { Logger } from '../../config/logger.js';
|
|
7
|
+
import { queueConfig } from '../../config/queue.js';
|
|
7
8
|
import { createValidationError } from '../../exceptions/ZintrustError.js';
|
|
8
9
|
import { ZintrustLang } from '../../lang/lang.js';
|
|
9
10
|
import { createLockProvider, getLockProvider, registerLockProvider } from './LockProvider.js';
|
|
@@ -47,7 +48,7 @@ function initializeLockProvider(lockProviderName, config) {
|
|
|
47
48
|
return provider;
|
|
48
49
|
}
|
|
49
50
|
function resolveLockProviderName(config) {
|
|
50
|
-
const envProvider =
|
|
51
|
+
const envProvider = queueConfig.default;
|
|
51
52
|
if (config.lockProvider !== undefined &&
|
|
52
53
|
config.lockProvider !== null &&
|
|
53
54
|
config.lockProvider.length > 0)
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Provides distributed lock management for job deduplication
|
|
4
4
|
*/
|
|
5
5
|
import type { LockProvider, LockProviderConfig } from '../../types/Queue';
|
|
6
|
+
/**
|
|
7
|
+
* Close Redis connection and cleanup resources
|
|
8
|
+
*/
|
|
9
|
+
export declare function closeLockProvider(): Promise<void>;
|
|
6
10
|
/**
|
|
7
11
|
* Redis-based Lock Provider Implementation
|
|
8
12
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LockProvider.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/LockProvider.ts"],"names":[],"mappings":"AACA;;;GAGG;AAGH,OAAO,KAAK,EAGV,YAAY,EACZ,kBAAkB,EAEnB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"LockProvider.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/LockProvider.ts"],"names":[],"mappings":"AACA;;;GAGG;AAGH,OAAO,KAAK,EAGV,YAAY,EACZ,kBAAkB,EAEnB,MAAM,eAAe,CAAC;AAwBvB;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUvD;AAkJD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAWhF;AAYD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CA4FjF;AAOD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAG/E;AACD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEtE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAS3E"}
|
|
@@ -23,6 +23,22 @@ function getRedisClient() {
|
|
|
23
23
|
}
|
|
24
24
|
return redisClient;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Close Redis connection and cleanup resources
|
|
28
|
+
*/
|
|
29
|
+
export async function closeLockProvider() {
|
|
30
|
+
if (redisClient) {
|
|
31
|
+
try {
|
|
32
|
+
await redisClient.quit();
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
Logger.warn('Error closing Redis lock provider connection', error);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
redisClient = null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
26
42
|
const METRICS_SUFFIX = {
|
|
27
43
|
attempts: 'metrics:attempts',
|
|
28
44
|
acquired: 'metrics:acquired',
|
|
@@ -3,13 +3,49 @@ export type QueueMessage<T = unknown> = {
|
|
|
3
3
|
payload: T;
|
|
4
4
|
attempts: number;
|
|
5
5
|
};
|
|
6
|
-
interface IQueueDriver {
|
|
6
|
+
export interface IQueueDriver {
|
|
7
7
|
enqueue<T = unknown>(queue: string, payload: T): Promise<string>;
|
|
8
8
|
dequeue<T = unknown>(queue: string): Promise<QueueMessage<T> | undefined>;
|
|
9
9
|
ack(queue: string, id: string): Promise<void>;
|
|
10
10
|
length(queue: string): Promise<number>;
|
|
11
11
|
drain(queue: string): Promise<void>;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* BullMQ payload interface with all supported JobOptions
|
|
15
|
+
*/
|
|
16
|
+
export interface BullMQPayload {
|
|
17
|
+
to?: string;
|
|
18
|
+
subject?: string;
|
|
19
|
+
template?: string;
|
|
20
|
+
templateData?: Record<string, unknown>;
|
|
21
|
+
timestamp?: number;
|
|
22
|
+
attempts?: number;
|
|
23
|
+
uniqueId?: string;
|
|
24
|
+
delay?: number;
|
|
25
|
+
priority?: number;
|
|
26
|
+
removeOnComplete?: number | boolean;
|
|
27
|
+
removeOnFail?: number | boolean;
|
|
28
|
+
backoff?: {
|
|
29
|
+
type: 'fixed' | 'exponential';
|
|
30
|
+
delay: number;
|
|
31
|
+
};
|
|
32
|
+
repeat?: {
|
|
33
|
+
every?: number;
|
|
34
|
+
cron?: string;
|
|
35
|
+
limit?: number;
|
|
36
|
+
};
|
|
37
|
+
lifo?: boolean;
|
|
38
|
+
deduplication?: {
|
|
39
|
+
id: string;
|
|
40
|
+
ttl?: number;
|
|
41
|
+
releaseAfter?: string | number | {
|
|
42
|
+
condition: string;
|
|
43
|
+
delay: number;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
uniqueVia?: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}
|
|
13
49
|
/**
|
|
14
50
|
* Resolves the lock prefix for queue operations
|
|
15
51
|
* Uses singleton RedisKeys for consistent key management
|
|
@@ -19,7 +55,7 @@ export declare const Queue: Readonly<{
|
|
|
19
55
|
register(name: string, driver: IQueueDriver): void;
|
|
20
56
|
reset(): void;
|
|
21
57
|
get(name?: string): IQueueDriver;
|
|
22
|
-
enqueue
|
|
58
|
+
enqueue(queue: string, payload: BullMQPayload, driverName?: string): Promise<string>;
|
|
23
59
|
dequeue<T = unknown>(queue: string, driverName?: string): Promise<QueueMessage<T> | undefined>;
|
|
24
60
|
ack(queue: string, id: string, driverName?: string): Promise<void>;
|
|
25
61
|
length(queue: string, driverName?: string): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Queue.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/Queue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Queue.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/Queue.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjE,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC1E,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAE5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,OAAO,GAAG,aAAa,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,aAAa,CAAC,EAAE;QACd,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KACvE,CAAC;IAGF,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAO,MAOpC,CAAC;AAIF,eAAO,MAAM,KAAK;mBACD,MAAM,UAAU,YAAY;aAIlC,IAAI;eAIF,MAAM,GAAG,YAAY;mBAYX,MAAM,WAAW,aAAa,eAAe,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAM5E,CAAC,mBACN,MAAM,eACA,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;eAKtB,MAAM,MAAM,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;kBAKpD,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;iBAK9C,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAI9D,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
package/src/tools/queue/Queue.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ZintrustLang } from '../../lang/lang.js';
|
|
1
2
|
import { Env } from '../../config/env.js';
|
|
2
3
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
3
4
|
import { RedisKeys } from '../redis/RedisKeyManager.js';
|
|
@@ -22,8 +23,8 @@ export const Queue = Object.freeze({
|
|
|
22
23
|
drivers.clear();
|
|
23
24
|
},
|
|
24
25
|
get(name) {
|
|
25
|
-
const resolved = (name ?? Env.QUEUE_CONNECTION) || Env.QUEUE_DRIVER ||
|
|
26
|
-
const driverName = (resolved !== null && resolved !== undefined ? String(resolved) :
|
|
26
|
+
const resolved = (name ?? Env.QUEUE_CONNECTION) || Env.QUEUE_DRIVER || ZintrustLang.INMEMORY;
|
|
27
|
+
const driverName = (resolved !== null && resolved !== undefined ? String(resolved) : ZintrustLang.INMEMORY)
|
|
27
28
|
.trim()
|
|
28
29
|
.toLowerCase();
|
|
29
30
|
const driver = drivers.get(driverName);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { AdvancedJobOptions, QueueConfig } from '../../types/Queue';
|
|
6
6
|
import { createDeduplicationBuilder } from './DeduplicationBuilder';
|
|
7
|
+
import type { BullMQPayload } from './Queue';
|
|
7
8
|
/**
|
|
8
9
|
* Extend existing Queue with advanced capabilities
|
|
9
10
|
* This provides a migration path for existing code
|
|
@@ -13,7 +14,7 @@ export declare function extendQueue(config: QueueConfig): void;
|
|
|
13
14
|
* Enhanced enqueue method that supports advanced options
|
|
14
15
|
* This can be used as a drop-in replacement for Queue.enqueue
|
|
15
16
|
*/
|
|
16
|
-
export declare function enqueueAdvanced(name: string, payload:
|
|
17
|
+
export declare function enqueueAdvanced(name: string, payload: BullMQPayload, options?: AdvancedJobOptions): Promise<string>;
|
|
17
18
|
/**
|
|
18
19
|
* Initialize default lock providers
|
|
19
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueueExtensions.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/QueueExtensions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAsB,WAAW,EAAE,MAAM,eAAe,CAAC;AAKzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"QueueExtensions.d.ts","sourceRoot":"","sources":["../../../../src/tools/queue/QueueExtensions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAsB,WAAW,EAAE,MAAM,eAAe,CAAC;AAKzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAWrD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAuBrD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAEvF;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE;IACvB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAkC3C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;uCAEgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aAC7B,MAAM,GAChB,kBAAkB;IAOrB;;OAEG;uCAEgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,mBACvB,MAAM,QACjB,MAAM,GACX,kBAAkB;CAStB,CAAC"}
|