@seip/blue-bird 1.0.2 → 1.1.1
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/.env_example +26 -12
- package/AGENTS.md +98 -26
- package/README.md +80 -23
- package/core/app.js +42 -0
- package/core/cache.js +62 -30
- package/core/cli/docker.js +236 -59
- package/core/cli/init.js +135 -9
- package/core/database.js +205 -20
- package/core/hash.js +201 -0
- package/core/index.d.ts +194 -137
- package/core/upload.js +83 -57
- package/core/ws.js +227 -210
- package/docker/docker-compose.sqlite.yml +69 -0
- package/frontend/js/utils.js +557 -557
- package/package.json +68 -66
package/core/hash.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
let bcryptModule = null;
|
|
4
|
+
try {
|
|
5
|
+
bcryptModule = (await import("bcrypt")).default || (await import("bcrypt"));
|
|
6
|
+
} catch {
|
|
7
|
+
// bcrypt not installed, scrypt native is used
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* High-performance Password Hashing class.
|
|
12
|
+
* Uses native node:crypto scrypt by default (zero npm dependencies, NIST recommended),
|
|
13
|
+
* with seamless support for bcrypt when installed or verifying bcrypt hashes.
|
|
14
|
+
*/
|
|
15
|
+
class Hash {
|
|
16
|
+
/**
|
|
17
|
+
* Hashes a plain text password using scrypt (default) or bcrypt.
|
|
18
|
+
* @param {string} password - The plain text password.
|
|
19
|
+
* @param {Object} [options={}] - Hashing options.
|
|
20
|
+
* @param {string} [options.driver="scrypt"] - Hashing driver ('scrypt' or 'bcrypt').
|
|
21
|
+
* @param {number} [options.rounds=10] - Salt rounds for bcrypt (if driver is 'bcrypt').
|
|
22
|
+
* @param {number} [options.N=16384] - CPU/memory cost parameter for scrypt.
|
|
23
|
+
* @param {number} [options.r=8] - Block size for scrypt.
|
|
24
|
+
* @param {number} [options.p=1] - Parallelization parameter for scrypt.
|
|
25
|
+
* @returns {Promise<string>} Formatted password hash string.
|
|
26
|
+
* @example
|
|
27
|
+
* const hash = await Hash.make("mySecretPassword");
|
|
28
|
+
* // Using bcrypt:
|
|
29
|
+
* const bcryptHash = await Hash.make("mySecretPassword", { driver: "bcrypt" });
|
|
30
|
+
*/
|
|
31
|
+
static async make(password, options = {}) {
|
|
32
|
+
if (typeof password !== "string" || !password) {
|
|
33
|
+
throw new Error("[HASH ERROR] Password must be a non-empty string.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const driver = (options.driver || "scrypt").toLowerCase();
|
|
37
|
+
|
|
38
|
+
if (driver === "bcrypt") {
|
|
39
|
+
if (!bcryptModule) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"[HASH ERROR] 'bcrypt' package is not installed. Run 'npm install bcrypt' or 'npx blue-bird add bcrypt', or use the default scrypt driver.",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const rounds = options.rounds || 10;
|
|
45
|
+
return bcryptModule.hash(password, rounds);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Default: native scrypt with random salt
|
|
49
|
+
const N = options.N || 16384;
|
|
50
|
+
const r = options.r || 8;
|
|
51
|
+
const p = options.p || 1;
|
|
52
|
+
const keylen = 64;
|
|
53
|
+
const salt = crypto.randomBytes(16);
|
|
54
|
+
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
crypto.scrypt(
|
|
57
|
+
password,
|
|
58
|
+
salt,
|
|
59
|
+
keylen,
|
|
60
|
+
{ N, r, p, maxmem: 32 * 1024 * 1024 },
|
|
61
|
+
(err, derivedKey) => {
|
|
62
|
+
if (err) return reject(err);
|
|
63
|
+
const hashString = `$scrypt$N=${N},r=${r},p=${p}$${salt.toString("hex")}$${derivedKey.toString("hex")}`;
|
|
64
|
+
resolve(hashString);
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Alias for make().
|
|
72
|
+
* @param {string} password - The plain text password.
|
|
73
|
+
* @param {Object} [options={}] - Options.
|
|
74
|
+
* @returns {Promise<string>}
|
|
75
|
+
*/
|
|
76
|
+
static async hash(password, options = {}) {
|
|
77
|
+
return this.make(password, options);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Verifies a plain text password against a hash string.
|
|
82
|
+
* Automatically detects scrypt or bcrypt hash formats.
|
|
83
|
+
* Uses timing-safe comparison to protect against side-channel attacks.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} password - The plain text password to check.
|
|
86
|
+
* @param {string} hash - The stored hash string.
|
|
87
|
+
* @returns {Promise<boolean>} True if password matches, false otherwise.
|
|
88
|
+
* @example
|
|
89
|
+
* const isValid = await Hash.verify("mySecretPassword", storedHash);
|
|
90
|
+
*/
|
|
91
|
+
static async verify(password, hash) {
|
|
92
|
+
if (
|
|
93
|
+
typeof password !== "string" ||
|
|
94
|
+
!password ||
|
|
95
|
+
typeof hash !== "string" ||
|
|
96
|
+
!hash
|
|
97
|
+
) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 1. Detect bcrypt hash format ($2a$, $2b$, $2y$)
|
|
102
|
+
if (/^\$2[aby]\$\d{2}\$/.test(hash)) {
|
|
103
|
+
if (!bcryptModule) {
|
|
104
|
+
console.error(
|
|
105
|
+
"[HASH ERROR] A bcrypt hash was detected, but the 'bcrypt' package is not installed. Run 'npm install bcrypt' or 'npx blue-bird add bcrypt'.",
|
|
106
|
+
);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
return await bcryptModule.compare(password, hash);
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 2. Detect native scrypt format ($scrypt$N=...,r=...,p=...$salt$hash)
|
|
117
|
+
if (hash.startsWith("$scrypt$")) {
|
|
118
|
+
const parts = hash.split("$");
|
|
119
|
+
// Format: ["", "scrypt", "N=16384,r=8,p=1", "saltHex", "hashHex"]
|
|
120
|
+
if (parts.length !== 5) return false;
|
|
121
|
+
|
|
122
|
+
const paramsStr = parts[2];
|
|
123
|
+
const saltHex = parts[3];
|
|
124
|
+
const originalHashHex = parts[4];
|
|
125
|
+
|
|
126
|
+
if (!paramsStr || !saltHex || !originalHashHex) return false;
|
|
127
|
+
|
|
128
|
+
let N = 16384,
|
|
129
|
+
r = 8,
|
|
130
|
+
p = 1;
|
|
131
|
+
paramsStr.split(",").forEach((param) => {
|
|
132
|
+
const [k, v] = param.split("=");
|
|
133
|
+
if (k === "N") N = parseInt(v, 10) || N;
|
|
134
|
+
if (k === "r") r = parseInt(v, 10) || r;
|
|
135
|
+
if (k === "p") p = parseInt(v, 10) || p;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const salt = Buffer.from(saltHex, "hex");
|
|
139
|
+
const originalHash = Buffer.from(originalHashHex, "hex");
|
|
140
|
+
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
crypto.scrypt(
|
|
143
|
+
password,
|
|
144
|
+
salt,
|
|
145
|
+
originalHash.length,
|
|
146
|
+
{ N, r, p, maxmem: 32 * 1024 * 1024 },
|
|
147
|
+
(err, derivedKey) => {
|
|
148
|
+
if (err) return resolve(false);
|
|
149
|
+
try {
|
|
150
|
+
const matches = crypto.timingSafeEqual(originalHash, derivedKey);
|
|
151
|
+
resolve(matches);
|
|
152
|
+
} catch {
|
|
153
|
+
resolve(false);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Alias for verify().
|
|
165
|
+
* @param {string} password - The plain text password.
|
|
166
|
+
* @param {string} hash - The stored hash string.
|
|
167
|
+
* @returns {Promise<boolean>}
|
|
168
|
+
*/
|
|
169
|
+
static async check(password, hash) {
|
|
170
|
+
return this.verify(password, hash);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Checks if a given hash needs to be rehashed to match updated security parameters.
|
|
175
|
+
* @param {string} hash - The stored hash string.
|
|
176
|
+
* @param {Object} [options={}] - Target options.
|
|
177
|
+
* @returns {boolean} True if the hash should be regenerated.
|
|
178
|
+
*/
|
|
179
|
+
static needsRehash(hash, options = {}) {
|
|
180
|
+
if (!hash || typeof hash !== "string") return true;
|
|
181
|
+
const targetDriver = (options.driver || "scrypt").toLowerCase();
|
|
182
|
+
|
|
183
|
+
if (targetDriver === "bcrypt") {
|
|
184
|
+
return !/^\$2[aby]\$\d{2}\$/.test(hash);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!hash.startsWith("$scrypt$")) return true;
|
|
188
|
+
|
|
189
|
+
const parts = hash.split("$");
|
|
190
|
+
if (parts.length !== 5) return true;
|
|
191
|
+
|
|
192
|
+
const paramsStr = parts[2];
|
|
193
|
+
const targetN = options.N || 16384;
|
|
194
|
+
const targetR = options.r || 8;
|
|
195
|
+
const targetP = options.p || 1;
|
|
196
|
+
|
|
197
|
+
return !paramsStr.includes(`N=${targetN},r=${targetR},p=${targetP}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export default Hash;
|
package/core/index.d.ts
CHANGED
|
@@ -1,137 +1,194 @@
|
|
|
1
|
-
import { Router as ExpressRouter, Request, Response, NextFunction } from "express";
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
namespace Express {
|
|
5
|
-
interface Response {
|
|
6
|
-
/**
|
|
7
|
-
* Sends a standardized JSON success response.
|
|
8
|
-
* @param data Data payload to return.
|
|
9
|
-
* @param message Success message.
|
|
10
|
-
* @param statusCode HTTP status code (default: 200).
|
|
11
|
-
*/
|
|
12
|
-
success(data?: any, message?: string, statusCode?: number): Response;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Sends a standardized
|
|
16
|
-
* @param
|
|
17
|
-
* @param
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* @param
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export class
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
options
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
static
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
1
|
+
import { Router as ExpressRouter, Request, Response, NextFunction } from "express";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Response {
|
|
6
|
+
/**
|
|
7
|
+
* Sends a standardized JSON success response.
|
|
8
|
+
* @param data Data payload to return.
|
|
9
|
+
* @param message Success message.
|
|
10
|
+
* @param statusCode HTTP status code (default: 200).
|
|
11
|
+
*/
|
|
12
|
+
success(data?: any, message?: string, statusCode?: number): Response;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sends a standardized HTTP 200 OK success response.
|
|
16
|
+
* @param data Data payload.
|
|
17
|
+
* @param message Success message.
|
|
18
|
+
*/
|
|
19
|
+
ok(data?: any, message?: string): Response;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Sends a standardized HTTP 201 Created success response.
|
|
23
|
+
* @param data Data payload.
|
|
24
|
+
* @param message Success message.
|
|
25
|
+
*/
|
|
26
|
+
created(data?: any, message?: string): Response;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sends a standardized HTTP 400 Bad Request error response.
|
|
30
|
+
* @param message Error message.
|
|
31
|
+
* @param errors Detailed errors array or object.
|
|
32
|
+
*/
|
|
33
|
+
badRequest(message?: string, errors?: any): Response;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sends a standardized HTTP 401 Unauthorized error response.
|
|
37
|
+
* @param message Error message.
|
|
38
|
+
*/
|
|
39
|
+
unauthorized(message?: string): Response;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Sends a standardized HTTP 403 Forbidden error response.
|
|
43
|
+
* @param message Error message.
|
|
44
|
+
*/
|
|
45
|
+
forbidden(message?: string): Response;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Sends a standardized HTTP 404 Not Found error response.
|
|
49
|
+
* @param message Error message.
|
|
50
|
+
*/
|
|
51
|
+
notFound(message?: string): Response;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Sends a standardized HTTP 500 Internal Server Error response.
|
|
55
|
+
* @param message Error message.
|
|
56
|
+
* @param errors Error details.
|
|
57
|
+
*/
|
|
58
|
+
serverError(message?: string, errors?: any): Response;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sends a standardized JSON error response.
|
|
62
|
+
* @param message Error message.
|
|
63
|
+
* @param statusCode HTTP status code (default: 400).
|
|
64
|
+
* @param errors Array or object of detailed errors.
|
|
65
|
+
*/
|
|
66
|
+
error(message?: string, statusCode?: number, errors?: any): Response;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Sends a standardized paginated JSON response.
|
|
70
|
+
* @param data Array of records for current page.
|
|
71
|
+
* @param pagination Object containing page, limit, and total count.
|
|
72
|
+
* @param message Success message.
|
|
73
|
+
*/
|
|
74
|
+
paginate(
|
|
75
|
+
data?: any[],
|
|
76
|
+
pagination?: { page?: number; limit?: number; total?: number },
|
|
77
|
+
message?: string
|
|
78
|
+
): Response;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class AppError extends Error {
|
|
84
|
+
statusCode: number;
|
|
85
|
+
errors: any;
|
|
86
|
+
isOperational: boolean;
|
|
87
|
+
|
|
88
|
+
constructor(message: string, statusCode?: number, errors?: any);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class App {
|
|
92
|
+
constructor(options?: {
|
|
93
|
+
routes?: any[];
|
|
94
|
+
cors?: any;
|
|
95
|
+
middlewares?: any[];
|
|
96
|
+
port?: number | string;
|
|
97
|
+
host?: string;
|
|
98
|
+
logger?: boolean;
|
|
99
|
+
notFound?: boolean;
|
|
100
|
+
json?: boolean;
|
|
101
|
+
urlencoded?: boolean;
|
|
102
|
+
static?: { path: string; options?: any };
|
|
103
|
+
cookieParser?: boolean;
|
|
104
|
+
rateLimit?: boolean | any;
|
|
105
|
+
swagger?: boolean | any;
|
|
106
|
+
compression?: boolean;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
use(record: any): void;
|
|
110
|
+
set(key: string, value: any): void;
|
|
111
|
+
websocket(
|
|
112
|
+
options?:
|
|
113
|
+
| ((ws: any, req: any) => void)
|
|
114
|
+
| { path?: string; auth?: boolean }
|
|
115
|
+
): WebSocketManager;
|
|
116
|
+
run(): void;
|
|
117
|
+
|
|
118
|
+
static helmet(options?: any): any;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class WebSocketManager {
|
|
122
|
+
constructor(server: any, options?: { path?: string; auth?: boolean });
|
|
123
|
+
onConnection(handler: (ws: any, req: any) => void): void;
|
|
124
|
+
join(room: string, ws: any): void;
|
|
125
|
+
leave(room: string, ws: any): void;
|
|
126
|
+
broadcast(data: any, room?: string | null): void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class Router {
|
|
130
|
+
constructor(path?: string, options?: { seo?: boolean; languages?: string[] });
|
|
131
|
+
|
|
132
|
+
use(...middleware: any[]): void;
|
|
133
|
+
get(path: string | RegExp, ...callback: any[]): void;
|
|
134
|
+
post(path: string | RegExp, ...callback: any[]): void;
|
|
135
|
+
put(path: string | RegExp, ...callback: any[]): void;
|
|
136
|
+
delete(path: string | RegExp, ...callback: any[]): void;
|
|
137
|
+
patch(path: string | RegExp, ...callback: any[]): void;
|
|
138
|
+
options(path: string | RegExp, ...callback: any[]): void;
|
|
139
|
+
getRouter(): ExpressRouter;
|
|
140
|
+
getPath(): string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class Validator {
|
|
144
|
+
constructor(schema: Record<string, any>, lang?: string);
|
|
145
|
+
middleware(): (req: Request, res: Response, next: NextFunction) => void;
|
|
146
|
+
validate(data: Record<string, any>): { valid: boolean; errors: any[] };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export class Hash {
|
|
150
|
+
static make(password: string, options?: { driver?: "scrypt" | "bcrypt"; rounds?: number; N?: number; r?: number; p?: number }): Promise<string>;
|
|
151
|
+
static hash(password: string, options?: { driver?: "scrypt" | "bcrypt"; rounds?: number; N?: number; r?: number; p?: number }): Promise<string>;
|
|
152
|
+
static verify(password: string, hash: string): Promise<boolean>;
|
|
153
|
+
static check(password: string, hash: string): Promise<boolean>;
|
|
154
|
+
static needsRehash(hash: string, options?: { driver?: "scrypt" | "bcrypt"; N?: number; r?: number; p?: number }): boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export class Auth {
|
|
158
|
+
static encrypt(payload: any, secret: string): string;
|
|
159
|
+
static decrypt(data: string, secret: string): any;
|
|
160
|
+
static generateToken(payload: any, secret?: string, expiresIn?: string | number): string;
|
|
161
|
+
static verifyToken(token: string, secret?: string): any;
|
|
162
|
+
static protect(options?: { redirect?: string | null; key?: string; cookieKey?: string }): (req: Request, res: Response, next: NextFunction) => Promise<any>;
|
|
163
|
+
static login(res: Response, data: any, key?: string, options?: { expiresIn?: string | number; cookie?: any }): Promise<string>;
|
|
164
|
+
static logout(res: Response, key?: string, options?: any, req?: Request): Promise<boolean>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export class Cache {
|
|
168
|
+
static middleware(seconds?: number): (req: Request, res: Response, next: NextFunction) => Promise<any>;
|
|
169
|
+
static get(key: string): Promise<any | null>;
|
|
170
|
+
static set(key: string, value: any, seconds?: number): Promise<boolean>;
|
|
171
|
+
static delete(keys: string | string[]): Promise<boolean>;
|
|
172
|
+
static del(keys: string | string[]): Promise<boolean>;
|
|
173
|
+
static clear(): Promise<boolean>;
|
|
174
|
+
static getMode(): string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function getRedisClient(): any;
|
|
178
|
+
|
|
179
|
+
export class Database {
|
|
180
|
+
constructor(connectionLimit?: number, queueLimit?: number, config?: any);
|
|
181
|
+
init(retries?: number): Promise<boolean>;
|
|
182
|
+
query(sql: string, params?: any[], options?: any): Promise<any>;
|
|
183
|
+
paginate(
|
|
184
|
+
sql: string,
|
|
185
|
+
params?: any[],
|
|
186
|
+
options?: { page?: number; limit?: number; cache?: number }
|
|
187
|
+
): Promise<{ data: any[]; total: number; page: number; limit: number; totalPages: number }>;
|
|
188
|
+
transaction<T = any>(callback: (tx: { query: (sql: string, params?: any[], options?: any) => Promise<any> }) => Promise<T>): Promise<T>;
|
|
189
|
+
executeTransaction<T = any>(callback: (tx: { query: (sql: string, params?: any[], options?: any) => Promise<any> }) => Promise<T>): Promise<T>;
|
|
190
|
+
close(): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export default App;
|
|
194
|
+
|