sprint-es 0.0.34 → 0.0.36
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/dist/cjs/index.cjs +33 -2
- package/dist/cjs/modules/cronjobs/index.cjs +26 -0
- package/dist/cjs/modules/jwt/index.cjs +138 -0
- package/dist/cjs/modules/schemas/index.cjs +0 -6
- package/dist/esm/index.js +33 -2
- package/dist/esm/modules/cronjobs/index.js +26 -0
- package/dist/esm/modules/jwt/index.js +138 -0
- package/dist/esm/modules/schemas/index.js +0 -6
- package/dist/types/modules/cronjobs/index.d.ts +11 -0
- package/dist/types/modules/cronjobs/index.d.ts.map +1 -0
- package/dist/types/modules/jwt/index.d.ts +29 -0
- package/dist/types/modules/jwt/index.d.ts.map +1 -0
- package/dist/types/modules/schemas/index.d.ts.map +1 -1
- package/dist/types/sprint.d.ts +3 -1
- package/dist/types/sprint.d.ts.map +1 -1
- package/dist/types/types.d.ts +3 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +13 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -25,7 +25,12 @@ function matchPattern(pattern, routePath) {
|
|
|
25
25
|
const normalizedPattern = pattern.replace(/\/$/, "") || "/";
|
|
26
26
|
const normalizedRoute = routePath.replace(/\/$/, "") || "/";
|
|
27
27
|
if (normalizedPattern === normalizedRoute) return true;
|
|
28
|
-
|
|
28
|
+
if (normalizedPattern.endsWith("/**")) {
|
|
29
|
+
const basePattern = normalizedPattern.slice(0, -3);
|
|
30
|
+
if (normalizedRoute === basePattern) return true;
|
|
31
|
+
return normalizedRoute.startsWith(basePattern + "/");
|
|
32
|
+
}
|
|
33
|
+
let regexPattern = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLE}}").replace(/\*/g, "[^/]+").replace(/{{DOUBLE}}/g, "(.+/?)*");
|
|
29
34
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
30
35
|
return regex.test(normalizedRoute);
|
|
31
36
|
}
|
|
@@ -55,6 +60,7 @@ class Sprint {
|
|
|
55
60
|
port = process.env.PORT,
|
|
56
61
|
routesPath = "./routes",
|
|
57
62
|
middlewaresPath = "./middlewares",
|
|
63
|
+
cronjobsPath = "./cronjobs",
|
|
58
64
|
jsonLimit = "50mb",
|
|
59
65
|
urlEncodedLimit = "50mb",
|
|
60
66
|
prefix = "",
|
|
@@ -65,6 +71,7 @@ class Sprint {
|
|
|
65
71
|
this.port = port;
|
|
66
72
|
this.routesPath = routesPath;
|
|
67
73
|
this.middlewaresPath = middlewaresPath;
|
|
74
|
+
this.cronjobsPath = cronjobsPath;
|
|
68
75
|
this.jsonLimit = jsonLimit;
|
|
69
76
|
this.urlEncodedLimit = urlEncodedLimit;
|
|
70
77
|
this.prefix = prefix ? "/" + prefix.replace(/^\/+|\/+$/g, "") : "";
|
|
@@ -92,12 +99,20 @@ class Sprint {
|
|
|
92
99
|
} catch (err) {
|
|
93
100
|
console.error("[Sprint] Failed to load routes:", err);
|
|
94
101
|
}
|
|
102
|
+
try {
|
|
103
|
+
const cronjobsCandidate = path.isAbsolute(this.cronjobsPath) ? this.cronjobsPath : path.join(callerDir, this.cronjobsPath);
|
|
104
|
+
if (fs.existsSync(cronjobsCandidate) && fs.statSync(cronjobsCandidate).isDirectory()) await this.loadCronJobs(cronjobsCandidate);
|
|
105
|
+
else if (isVerbose) console.log(`[Sprint] Cronjobs folder not found at: ${cronjobsCandidate}, skipping.`);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error("[Sprint] Failed to load cronjobs:", err);
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
loadDefaults() {
|
|
97
111
|
this.app.disable("x-powered-by");
|
|
98
112
|
this.app.use((req, res, next) => {
|
|
99
113
|
const getAuthorization = (sources) => {
|
|
100
|
-
const
|
|
114
|
+
const defaultSources = ["query:token", "headers:authorization"];
|
|
115
|
+
const sourceList = sources ? Array.isArray(sources) ? sources : [sources] : defaultSources;
|
|
101
116
|
for (const source of sourceList) {
|
|
102
117
|
const [type, key] = source.split(":");
|
|
103
118
|
if (type === "query") {
|
|
@@ -231,6 +246,22 @@ class Sprint {
|
|
|
231
246
|
};
|
|
232
247
|
await walkDir(routesPath);
|
|
233
248
|
}
|
|
249
|
+
async loadCronJobs(cronjobsPath) {
|
|
250
|
+
const files = await fs.promises.readdir(cronjobsPath);
|
|
251
|
+
for (const file of files) {
|
|
252
|
+
const filePath = path.join(cronjobsPath, file);
|
|
253
|
+
const stat = await fs.promises.stat(filePath);
|
|
254
|
+
if (stat.isFile() && (file.endsWith(".ts") || file.endsWith(".js"))) {
|
|
255
|
+
try {
|
|
256
|
+
const moduleUrl = url.pathToFileURL(filePath).href;
|
|
257
|
+
await import(moduleUrl);
|
|
258
|
+
console.log(`[Sprint] Loaded cronjob: ${file.replace(/\.(ts|js)$/, "")}`);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
console.warn(`[Sprint] Failed to load cronjob ${filePath}:`, err);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
234
265
|
loadNotFound() {
|
|
235
266
|
this.app.use((req, res, _next) => {
|
|
236
267
|
const originalSend = res.send.bind(res);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const cron = require("node-cron");
|
|
4
|
+
const registeredJobs = [];
|
|
5
|
+
function defineCronJob(options) {
|
|
6
|
+
const name = options.name || `cronjob-${registeredJobs.length}`;
|
|
7
|
+
if (options.enabled !== false && cron.validate(options.cronExpression)) {
|
|
8
|
+
const task = cron.schedule(options.cronExpression, options.handler, {
|
|
9
|
+
timezone: options.timezone
|
|
10
|
+
});
|
|
11
|
+
registeredJobs.push({ name, task });
|
|
12
|
+
}
|
|
13
|
+
return options;
|
|
14
|
+
}
|
|
15
|
+
function stopAllCronJobs() {
|
|
16
|
+
for (const job of registeredJobs) {
|
|
17
|
+
job.task.stop();
|
|
18
|
+
}
|
|
19
|
+
registeredJobs.length = 0;
|
|
20
|
+
}
|
|
21
|
+
function getCronJobs() {
|
|
22
|
+
return registeredJobs.map((j) => j.name);
|
|
23
|
+
}
|
|
24
|
+
exports.defineCronJob = defineCronJob;
|
|
25
|
+
exports.getCronJobs = getCronJobs;
|
|
26
|
+
exports.stopAllCronJobs = stopAllCronJobs;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const ALGORITHM = "dir";
|
|
5
|
+
const ENC_ALGORITHM = "A256GCM";
|
|
6
|
+
const KEY_LENGTH = 32;
|
|
7
|
+
const IV_LENGTH = 12;
|
|
8
|
+
function base64UrlEncode(buffer) {
|
|
9
|
+
return buffer.toString("base64url");
|
|
10
|
+
}
|
|
11
|
+
function base64UrlDecodeSafe(str) {
|
|
12
|
+
const pad = str.length % 4;
|
|
13
|
+
const padded = pad ? str + "=".repeat(4 - pad) : str;
|
|
14
|
+
return Buffer.from(padded.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
15
|
+
}
|
|
16
|
+
function decodeBase64Url(str) {
|
|
17
|
+
return Buffer.from(str, "base64url").toString();
|
|
18
|
+
}
|
|
19
|
+
function importKey(key) {
|
|
20
|
+
if (key.length === 32) return Buffer.from(key, "utf8");
|
|
21
|
+
if (/^[A-Za-z0-9_-]+$/.test(key) && key.length >= 32) {
|
|
22
|
+
const hash = crypto.createHash("sha256");
|
|
23
|
+
hash.update(key);
|
|
24
|
+
return hash.digest();
|
|
25
|
+
}
|
|
26
|
+
return Buffer.from(key, "utf8").slice(0, KEY_LENGTH);
|
|
27
|
+
}
|
|
28
|
+
function encodeBase64Url(str) {
|
|
29
|
+
return Buffer.from(str).toString("base64url");
|
|
30
|
+
}
|
|
31
|
+
function sign(payload, secret, options = {}) {
|
|
32
|
+
const header = { alg: "HS256", typ: "JWT" };
|
|
33
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
34
|
+
const claims = { ...payload };
|
|
35
|
+
if (options.expiresIn) {
|
|
36
|
+
claims.exp = typeof options.expiresIn === "number" ? now + options.expiresIn : now + parseInt(options.expiresIn);
|
|
37
|
+
}
|
|
38
|
+
if (options.issuer) claims.iss = options.issuer;
|
|
39
|
+
if (options.subject) claims.sub = options.subject;
|
|
40
|
+
if (options.audience) claims.aud = options.audience;
|
|
41
|
+
claims.iat = now;
|
|
42
|
+
const encodedHeader = encodeBase64Url(JSON.stringify(header));
|
|
43
|
+
const encodedPayload = encodeBase64Url(JSON.stringify(claims));
|
|
44
|
+
const signature = crypto.createHmac("sha256", secret).update(`${encodedHeader}.${encodedPayload}`).digest();
|
|
45
|
+
return `${encodedHeader}.${encodedPayload}.${base64UrlEncode(signature)}`;
|
|
46
|
+
}
|
|
47
|
+
function verify(token, secret) {
|
|
48
|
+
try {
|
|
49
|
+
const parts = token.split(".");
|
|
50
|
+
if (parts.length !== 3) return null;
|
|
51
|
+
const [encodedHeader, encodedPayload, signature] = parts;
|
|
52
|
+
const expectedSig = crypto.createHmac("sha256", secret).update(`${encodedHeader}.${encodedPayload}`).digest();
|
|
53
|
+
const sigBuffer = base64UrlDecodeSafe(signature);
|
|
54
|
+
if (!crypto.timingSafeEqual(sigBuffer, expectedSig)) return null;
|
|
55
|
+
const payload = JSON.parse(decodeBase64Url(encodedPayload));
|
|
56
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1e3)) return null;
|
|
57
|
+
return payload;
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function encrypt(payload, secret, options = { secret }) {
|
|
63
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
64
|
+
const key = importKey(secret);
|
|
65
|
+
const header = {
|
|
66
|
+
alg: ALGORITHM,
|
|
67
|
+
enc: ENC_ALGORITHM,
|
|
68
|
+
typ: "JWT"
|
|
69
|
+
};
|
|
70
|
+
const claims = { ...payload };
|
|
71
|
+
if (options.expiresIn) {
|
|
72
|
+
claims.exp = now + parseInt(String(options.expiresIn));
|
|
73
|
+
}
|
|
74
|
+
if (options.issuer) claims.iss = options.issuer;
|
|
75
|
+
claims.iat = now;
|
|
76
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
77
|
+
const aad = Buffer.from(JSON.stringify(header));
|
|
78
|
+
const cipher = crypto.createCipheriv(ENC_ALGORITHM, key, iv);
|
|
79
|
+
cipher.setAAD(aad);
|
|
80
|
+
const plaintext = Buffer.from(JSON.stringify(claims));
|
|
81
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
82
|
+
const authTag = cipher.getAuthTag();
|
|
83
|
+
const encodedHeader = encodeBase64Url(JSON.stringify(header));
|
|
84
|
+
const encodedIv = base64UrlEncode(iv);
|
|
85
|
+
const encodedEncrypted = base64UrlEncode(encrypted);
|
|
86
|
+
const encodedAuthTag = base64UrlEncode(authTag);
|
|
87
|
+
return `${encodedHeader}.${encodedIv}.${encodedEncrypted}.${encodedAuthTag}`;
|
|
88
|
+
}
|
|
89
|
+
function decrypt(token, secret) {
|
|
90
|
+
try {
|
|
91
|
+
const parts = token.split(".");
|
|
92
|
+
if (parts.length !== 4) return null;
|
|
93
|
+
const [encodedHeader, encodedIv, encodedEncrypted, encodedAuthTag] = parts;
|
|
94
|
+
const key = importKey(secret);
|
|
95
|
+
const header = JSON.parse(decodeBase64Url(encodedHeader));
|
|
96
|
+
if (header.alg !== ALGORITHM || header.enc !== ENC_ALGORITHM) return null;
|
|
97
|
+
const iv = base64UrlDecodeSafe(encodedIv);
|
|
98
|
+
const encrypted = base64UrlDecodeSafe(encodedEncrypted);
|
|
99
|
+
const authTag = base64UrlDecodeSafe(encodedAuthTag);
|
|
100
|
+
const aad = Buffer.from(encodedHeader);
|
|
101
|
+
const decipher = crypto.createDecipheriv(ENC_ALGORITHM, key, iv);
|
|
102
|
+
decipher.setAAD(aad);
|
|
103
|
+
decipher.setAuthTag(authTag);
|
|
104
|
+
const plaintext = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
105
|
+
const payload = JSON.parse(plaintext.toString());
|
|
106
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1e3)) return null;
|
|
107
|
+
return payload;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function signEncrypted(payload, secret, options = { secret }) {
|
|
113
|
+
return encrypt(payload, secret, options);
|
|
114
|
+
}
|
|
115
|
+
function verifyEncrypted(token, secret) {
|
|
116
|
+
return decrypt(token, secret);
|
|
117
|
+
}
|
|
118
|
+
function createTokenPair(payload, secret, options = {}) {
|
|
119
|
+
const accessToken = sign(payload, secret, options);
|
|
120
|
+
const refreshPayload = { ...payload, type: "refresh" };
|
|
121
|
+
const refreshToken = sign(refreshPayload, secret, { ...options, expiresIn: "7d" });
|
|
122
|
+
return { accessToken, refreshToken };
|
|
123
|
+
}
|
|
124
|
+
function verifyTokenPair(token, secret) {
|
|
125
|
+
const [accessToken, refreshToken] = token.split(".");
|
|
126
|
+
return {
|
|
127
|
+
accessToken: verify(accessToken, secret),
|
|
128
|
+
refreshToken: verify(refreshToken, secret)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
exports.createTokenPair = createTokenPair;
|
|
132
|
+
exports.decrypt = decrypt;
|
|
133
|
+
exports.encrypt = encrypt;
|
|
134
|
+
exports.sign = sign;
|
|
135
|
+
exports.signEncrypted = signEncrypted;
|
|
136
|
+
exports.verify = verify;
|
|
137
|
+
exports.verifyEncrypted = verifyEncrypted;
|
|
138
|
+
exports.verifyTokenPair = verifyTokenPair;
|
|
@@ -21,24 +21,18 @@ function defineRouteSchema(schema) {
|
|
|
21
21
|
const result = parseSchema(schema.body, req.body);
|
|
22
22
|
if (!result.success) {
|
|
23
23
|
errors.push(...result.errors.map((e) => ({ location: "body", ...e })));
|
|
24
|
-
} else {
|
|
25
|
-
req.body = result.data;
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
26
|
if (schema.queryParams && req.query) {
|
|
29
27
|
const result = parseSchema(schema.queryParams, req.query);
|
|
30
28
|
if (!result.success) {
|
|
31
29
|
errors.push(...result.errors.map((e) => ({ location: "queryParams", ...e })));
|
|
32
|
-
} else {
|
|
33
|
-
req.query = result.data;
|
|
34
30
|
}
|
|
35
31
|
}
|
|
36
32
|
if (schema.params && req.params) {
|
|
37
33
|
const result = parseSchema(schema.params, req.params);
|
|
38
34
|
if (!result.success) {
|
|
39
35
|
errors.push(...result.errors.map((e) => ({ location: "params", ...e })));
|
|
40
|
-
} else {
|
|
41
|
-
req.params = result.data;
|
|
42
36
|
}
|
|
43
37
|
}
|
|
44
38
|
if (errors.length > 0) {
|
package/dist/esm/index.js
CHANGED
|
@@ -22,7 +22,12 @@ function matchPattern(pattern, routePath) {
|
|
|
22
22
|
const normalizedPattern = pattern.replace(/\/$/, "") || "/";
|
|
23
23
|
const normalizedRoute = routePath.replace(/\/$/, "") || "/";
|
|
24
24
|
if (normalizedPattern === normalizedRoute) return true;
|
|
25
|
-
|
|
25
|
+
if (normalizedPattern.endsWith("/**")) {
|
|
26
|
+
const basePattern = normalizedPattern.slice(0, -3);
|
|
27
|
+
if (normalizedRoute === basePattern) return true;
|
|
28
|
+
return normalizedRoute.startsWith(basePattern + "/");
|
|
29
|
+
}
|
|
30
|
+
let regexPattern = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLE}}").replace(/\*/g, "[^/]+").replace(/{{DOUBLE}}/g, "(.+/?)*");
|
|
26
31
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
27
32
|
return regex.test(normalizedRoute);
|
|
28
33
|
}
|
|
@@ -52,6 +57,7 @@ class Sprint {
|
|
|
52
57
|
port = process.env.PORT,
|
|
53
58
|
routesPath = "./routes",
|
|
54
59
|
middlewaresPath = "./middlewares",
|
|
60
|
+
cronjobsPath = "./cronjobs",
|
|
55
61
|
jsonLimit = "50mb",
|
|
56
62
|
urlEncodedLimit = "50mb",
|
|
57
63
|
prefix = "",
|
|
@@ -62,6 +68,7 @@ class Sprint {
|
|
|
62
68
|
this.port = port;
|
|
63
69
|
this.routesPath = routesPath;
|
|
64
70
|
this.middlewaresPath = middlewaresPath;
|
|
71
|
+
this.cronjobsPath = cronjobsPath;
|
|
65
72
|
this.jsonLimit = jsonLimit;
|
|
66
73
|
this.urlEncodedLimit = urlEncodedLimit;
|
|
67
74
|
this.prefix = prefix ? "/" + prefix.replace(/^\/+|\/+$/g, "") : "";
|
|
@@ -89,12 +96,20 @@ class Sprint {
|
|
|
89
96
|
} catch (err) {
|
|
90
97
|
console.error("[Sprint] Failed to load routes:", err);
|
|
91
98
|
}
|
|
99
|
+
try {
|
|
100
|
+
const cronjobsCandidate = path.isAbsolute(this.cronjobsPath) ? this.cronjobsPath : path.join(callerDir, this.cronjobsPath);
|
|
101
|
+
if (fs.existsSync(cronjobsCandidate) && fs.statSync(cronjobsCandidate).isDirectory()) await this.loadCronJobs(cronjobsCandidate);
|
|
102
|
+
else if (isVerbose) console.log(`[Sprint] Cronjobs folder not found at: ${cronjobsCandidate}, skipping.`);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.error("[Sprint] Failed to load cronjobs:", err);
|
|
105
|
+
}
|
|
92
106
|
}
|
|
93
107
|
loadDefaults() {
|
|
94
108
|
this.app.disable("x-powered-by");
|
|
95
109
|
this.app.use((req, res, next) => {
|
|
96
110
|
const getAuthorization = (sources) => {
|
|
97
|
-
const
|
|
111
|
+
const defaultSources = ["query:token", "headers:authorization"];
|
|
112
|
+
const sourceList = sources ? Array.isArray(sources) ? sources : [sources] : defaultSources;
|
|
98
113
|
for (const source of sourceList) {
|
|
99
114
|
const [type, key] = source.split(":");
|
|
100
115
|
if (type === "query") {
|
|
@@ -228,6 +243,22 @@ class Sprint {
|
|
|
228
243
|
};
|
|
229
244
|
await walkDir(routesPath);
|
|
230
245
|
}
|
|
246
|
+
async loadCronJobs(cronjobsPath) {
|
|
247
|
+
const files = await fs.promises.readdir(cronjobsPath);
|
|
248
|
+
for (const file of files) {
|
|
249
|
+
const filePath = path.join(cronjobsPath, file);
|
|
250
|
+
const stat = await fs.promises.stat(filePath);
|
|
251
|
+
if (stat.isFile() && (file.endsWith(".ts") || file.endsWith(".js"))) {
|
|
252
|
+
try {
|
|
253
|
+
const moduleUrl = pathToFileURL(filePath).href;
|
|
254
|
+
await import(moduleUrl);
|
|
255
|
+
console.log(`[Sprint] Loaded cronjob: ${file.replace(/\.(ts|js)$/, "")}`);
|
|
256
|
+
} catch (err) {
|
|
257
|
+
console.warn(`[Sprint] Failed to load cronjob ${filePath}:`, err);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
231
262
|
loadNotFound() {
|
|
232
263
|
this.app.use((req, res, _next) => {
|
|
233
264
|
const originalSend = res.send.bind(res);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import cron from "node-cron";
|
|
2
|
+
const registeredJobs = [];
|
|
3
|
+
function defineCronJob(options) {
|
|
4
|
+
const name = options.name || `cronjob-${registeredJobs.length}`;
|
|
5
|
+
if (options.enabled !== false && cron.validate(options.cronExpression)) {
|
|
6
|
+
const task = cron.schedule(options.cronExpression, options.handler, {
|
|
7
|
+
timezone: options.timezone
|
|
8
|
+
});
|
|
9
|
+
registeredJobs.push({ name, task });
|
|
10
|
+
}
|
|
11
|
+
return options;
|
|
12
|
+
}
|
|
13
|
+
function stopAllCronJobs() {
|
|
14
|
+
for (const job of registeredJobs) {
|
|
15
|
+
job.task.stop();
|
|
16
|
+
}
|
|
17
|
+
registeredJobs.length = 0;
|
|
18
|
+
}
|
|
19
|
+
function getCronJobs() {
|
|
20
|
+
return registeredJobs.map((j) => j.name);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
defineCronJob,
|
|
24
|
+
getCronJobs,
|
|
25
|
+
stopAllCronJobs
|
|
26
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
const ALGORITHM = "dir";
|
|
3
|
+
const ENC_ALGORITHM = "A256GCM";
|
|
4
|
+
const KEY_LENGTH = 32;
|
|
5
|
+
const IV_LENGTH = 12;
|
|
6
|
+
function base64UrlEncode(buffer) {
|
|
7
|
+
return buffer.toString("base64url");
|
|
8
|
+
}
|
|
9
|
+
function base64UrlDecodeSafe(str) {
|
|
10
|
+
const pad = str.length % 4;
|
|
11
|
+
const padded = pad ? str + "=".repeat(4 - pad) : str;
|
|
12
|
+
return Buffer.from(padded.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
13
|
+
}
|
|
14
|
+
function decodeBase64Url(str) {
|
|
15
|
+
return Buffer.from(str, "base64url").toString();
|
|
16
|
+
}
|
|
17
|
+
function importKey(key) {
|
|
18
|
+
if (key.length === 32) return Buffer.from(key, "utf8");
|
|
19
|
+
if (/^[A-Za-z0-9_-]+$/.test(key) && key.length >= 32) {
|
|
20
|
+
const hash = crypto.createHash("sha256");
|
|
21
|
+
hash.update(key);
|
|
22
|
+
return hash.digest();
|
|
23
|
+
}
|
|
24
|
+
return Buffer.from(key, "utf8").slice(0, KEY_LENGTH);
|
|
25
|
+
}
|
|
26
|
+
function encodeBase64Url(str) {
|
|
27
|
+
return Buffer.from(str).toString("base64url");
|
|
28
|
+
}
|
|
29
|
+
function sign(payload, secret, options = {}) {
|
|
30
|
+
const header = { alg: "HS256", typ: "JWT" };
|
|
31
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
32
|
+
const claims = { ...payload };
|
|
33
|
+
if (options.expiresIn) {
|
|
34
|
+
claims.exp = typeof options.expiresIn === "number" ? now + options.expiresIn : now + parseInt(options.expiresIn);
|
|
35
|
+
}
|
|
36
|
+
if (options.issuer) claims.iss = options.issuer;
|
|
37
|
+
if (options.subject) claims.sub = options.subject;
|
|
38
|
+
if (options.audience) claims.aud = options.audience;
|
|
39
|
+
claims.iat = now;
|
|
40
|
+
const encodedHeader = encodeBase64Url(JSON.stringify(header));
|
|
41
|
+
const encodedPayload = encodeBase64Url(JSON.stringify(claims));
|
|
42
|
+
const signature = crypto.createHmac("sha256", secret).update(`${encodedHeader}.${encodedPayload}`).digest();
|
|
43
|
+
return `${encodedHeader}.${encodedPayload}.${base64UrlEncode(signature)}`;
|
|
44
|
+
}
|
|
45
|
+
function verify(token, secret) {
|
|
46
|
+
try {
|
|
47
|
+
const parts = token.split(".");
|
|
48
|
+
if (parts.length !== 3) return null;
|
|
49
|
+
const [encodedHeader, encodedPayload, signature] = parts;
|
|
50
|
+
const expectedSig = crypto.createHmac("sha256", secret).update(`${encodedHeader}.${encodedPayload}`).digest();
|
|
51
|
+
const sigBuffer = base64UrlDecodeSafe(signature);
|
|
52
|
+
if (!crypto.timingSafeEqual(sigBuffer, expectedSig)) return null;
|
|
53
|
+
const payload = JSON.parse(decodeBase64Url(encodedPayload));
|
|
54
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1e3)) return null;
|
|
55
|
+
return payload;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function encrypt(payload, secret, options = { secret }) {
|
|
61
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
62
|
+
const key = importKey(secret);
|
|
63
|
+
const header = {
|
|
64
|
+
alg: ALGORITHM,
|
|
65
|
+
enc: ENC_ALGORITHM,
|
|
66
|
+
typ: "JWT"
|
|
67
|
+
};
|
|
68
|
+
const claims = { ...payload };
|
|
69
|
+
if (options.expiresIn) {
|
|
70
|
+
claims.exp = now + parseInt(String(options.expiresIn));
|
|
71
|
+
}
|
|
72
|
+
if (options.issuer) claims.iss = options.issuer;
|
|
73
|
+
claims.iat = now;
|
|
74
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
75
|
+
const aad = Buffer.from(JSON.stringify(header));
|
|
76
|
+
const cipher = crypto.createCipheriv(ENC_ALGORITHM, key, iv);
|
|
77
|
+
cipher.setAAD(aad);
|
|
78
|
+
const plaintext = Buffer.from(JSON.stringify(claims));
|
|
79
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
80
|
+
const authTag = cipher.getAuthTag();
|
|
81
|
+
const encodedHeader = encodeBase64Url(JSON.stringify(header));
|
|
82
|
+
const encodedIv = base64UrlEncode(iv);
|
|
83
|
+
const encodedEncrypted = base64UrlEncode(encrypted);
|
|
84
|
+
const encodedAuthTag = base64UrlEncode(authTag);
|
|
85
|
+
return `${encodedHeader}.${encodedIv}.${encodedEncrypted}.${encodedAuthTag}`;
|
|
86
|
+
}
|
|
87
|
+
function decrypt(token, secret) {
|
|
88
|
+
try {
|
|
89
|
+
const parts = token.split(".");
|
|
90
|
+
if (parts.length !== 4) return null;
|
|
91
|
+
const [encodedHeader, encodedIv, encodedEncrypted, encodedAuthTag] = parts;
|
|
92
|
+
const key = importKey(secret);
|
|
93
|
+
const header = JSON.parse(decodeBase64Url(encodedHeader));
|
|
94
|
+
if (header.alg !== ALGORITHM || header.enc !== ENC_ALGORITHM) return null;
|
|
95
|
+
const iv = base64UrlDecodeSafe(encodedIv);
|
|
96
|
+
const encrypted = base64UrlDecodeSafe(encodedEncrypted);
|
|
97
|
+
const authTag = base64UrlDecodeSafe(encodedAuthTag);
|
|
98
|
+
const aad = Buffer.from(encodedHeader);
|
|
99
|
+
const decipher = crypto.createDecipheriv(ENC_ALGORITHM, key, iv);
|
|
100
|
+
decipher.setAAD(aad);
|
|
101
|
+
decipher.setAuthTag(authTag);
|
|
102
|
+
const plaintext = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
103
|
+
const payload = JSON.parse(plaintext.toString());
|
|
104
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1e3)) return null;
|
|
105
|
+
return payload;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function signEncrypted(payload, secret, options = { secret }) {
|
|
111
|
+
return encrypt(payload, secret, options);
|
|
112
|
+
}
|
|
113
|
+
function verifyEncrypted(token, secret) {
|
|
114
|
+
return decrypt(token, secret);
|
|
115
|
+
}
|
|
116
|
+
function createTokenPair(payload, secret, options = {}) {
|
|
117
|
+
const accessToken = sign(payload, secret, options);
|
|
118
|
+
const refreshPayload = { ...payload, type: "refresh" };
|
|
119
|
+
const refreshToken = sign(refreshPayload, secret, { ...options, expiresIn: "7d" });
|
|
120
|
+
return { accessToken, refreshToken };
|
|
121
|
+
}
|
|
122
|
+
function verifyTokenPair(token, secret) {
|
|
123
|
+
const [accessToken, refreshToken] = token.split(".");
|
|
124
|
+
return {
|
|
125
|
+
accessToken: verify(accessToken, secret),
|
|
126
|
+
refreshToken: verify(refreshToken, secret)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
createTokenPair,
|
|
131
|
+
decrypt,
|
|
132
|
+
encrypt,
|
|
133
|
+
sign,
|
|
134
|
+
signEncrypted,
|
|
135
|
+
verify,
|
|
136
|
+
verifyEncrypted,
|
|
137
|
+
verifyTokenPair
|
|
138
|
+
};
|
|
@@ -19,24 +19,18 @@ function defineRouteSchema(schema) {
|
|
|
19
19
|
const result = parseSchema(schema.body, req.body);
|
|
20
20
|
if (!result.success) {
|
|
21
21
|
errors.push(...result.errors.map((e) => ({ location: "body", ...e })));
|
|
22
|
-
} else {
|
|
23
|
-
req.body = result.data;
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
if (schema.queryParams && req.query) {
|
|
27
25
|
const result = parseSchema(schema.queryParams, req.query);
|
|
28
26
|
if (!result.success) {
|
|
29
27
|
errors.push(...result.errors.map((e) => ({ location: "queryParams", ...e })));
|
|
30
|
-
} else {
|
|
31
|
-
req.query = result.data;
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
if (schema.params && req.params) {
|
|
35
31
|
const result = parseSchema(schema.params, req.params);
|
|
36
32
|
if (!result.success) {
|
|
37
33
|
errors.push(...result.errors.map((e) => ({ location: "params", ...e })));
|
|
38
|
-
} else {
|
|
39
|
-
req.params = result.data;
|
|
40
34
|
}
|
|
41
35
|
}
|
|
42
36
|
if (errors.length > 0) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CronJobOptions {
|
|
2
|
+
cronExpression: string;
|
|
3
|
+
handler: () => any;
|
|
4
|
+
name?: string;
|
|
5
|
+
timezone?: string;
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function defineCronJob(options: CronJobOptions): CronJobOptions;
|
|
9
|
+
export declare function stopAllCronJobs(): void;
|
|
10
|
+
export declare function getCronJobs(): string[];
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/cronjobs/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AASD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAYrE;AAED,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface JWTPayload {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
export interface JWTOptions {
|
|
5
|
+
expiresIn?: string | number;
|
|
6
|
+
issuer?: string;
|
|
7
|
+
subject?: string;
|
|
8
|
+
audience?: string | string[];
|
|
9
|
+
}
|
|
10
|
+
export interface EncryptedJWTOptions {
|
|
11
|
+
secret: string;
|
|
12
|
+
expiresIn?: string | number;
|
|
13
|
+
issuer?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function sign(payload: JWTPayload, secret: string, options?: JWTOptions): string;
|
|
16
|
+
export declare function verify(token: string, secret: string): JWTPayload | null;
|
|
17
|
+
export declare function encrypt(payload: JWTPayload, secret: string, options?: EncryptedJWTOptions): string;
|
|
18
|
+
export declare function decrypt(token: string, secret: string): JWTPayload | null;
|
|
19
|
+
export declare function signEncrypted(payload: JWTPayload, secret: string, options?: EncryptedJWTOptions): string;
|
|
20
|
+
export declare function verifyEncrypted(token: string, secret: string): JWTPayload | null;
|
|
21
|
+
export declare function createTokenPair(payload: JWTPayload, secret: string, options?: JWTOptions): {
|
|
22
|
+
accessToken: string;
|
|
23
|
+
refreshToken: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function verifyTokenPair(token: string, secret: string): {
|
|
26
|
+
accessToken: JWTPayload | null;
|
|
27
|
+
refreshToken: JWTPayload | null;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/jwt/index.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,UAAU;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,wBAAgB,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAsB1F;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAsBvE;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAgC,GAAG,MAAM,CAiC9G;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA6BxE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAgC,GAAG,MAAM,CAEpH;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhF;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAM5I;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE,CAMlI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,aAAa,EAAE,UAAU,EAAY,MAAM,KAAK,CAAC;AAE1E,OAAO,EAAE,CAAC,EAAE,CAAC;AAEb,MAAM,WAAW,kBAAkB;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;CAChD;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,aAAa,EAAE,UAAU,EAAY,MAAM,KAAK,CAAC;AAE1E,OAAO,EAAE,CAAC,EAAE,CAAC;AAEb,MAAM,WAAW,kBAAkB;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;CAChD;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,CA+BzF;AAED,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/types/sprint.d.ts
CHANGED
|
@@ -7,13 +7,14 @@ export declare class Sprint {
|
|
|
7
7
|
private port;
|
|
8
8
|
private routesPath;
|
|
9
9
|
private middlewaresPath;
|
|
10
|
+
private cronjobsPath;
|
|
10
11
|
private jsonLimit;
|
|
11
12
|
private urlEncodedLimit;
|
|
12
13
|
private prefix;
|
|
13
14
|
private routesLoaded;
|
|
14
15
|
private server;
|
|
15
16
|
private loadedMiddlewares;
|
|
16
|
-
constructor({ port, routesPath, middlewaresPath, jsonLimit, urlEncodedLimit, prefix, autoListen }?: SprintOptions);
|
|
17
|
+
constructor({ port, routesPath, middlewaresPath, cronjobsPath, jsonLimit, urlEncodedLimit, prefix, autoListen }?: SprintOptions);
|
|
17
18
|
private init;
|
|
18
19
|
private loadDefaults;
|
|
19
20
|
/**
|
|
@@ -26,6 +27,7 @@ export declare class Sprint {
|
|
|
26
27
|
private loadMiddlewares;
|
|
27
28
|
private loadHealthcheck;
|
|
28
29
|
private loadRoutes;
|
|
30
|
+
private loadCronJobs;
|
|
29
31
|
private loadNotFound;
|
|
30
32
|
/** Applies prefix to a path */
|
|
31
33
|
private applyPrefix;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprint.d.ts","sourceRoot":"","sources":["../../src/sprint.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAsC,MAAM,SAAS,CAAC;AACrF,OAAO,OAAO,EAAE,EAAE,WAAW,EAAoD,MAAM,SAAS,CAAC;AAmBjG,eAAO,MAAM,aAAa,SAAQ,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,qBAAa,MAAM;IACR,GAAG,EAAE,WAAW,CAAC;IACxB,OAAO,CAAC,IAAI,CAAqC;IACjD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,iBAAiB,CAA0B;gBAEvC,EACR,IAAuB,EACvB,UAAuB,EACvB,eAAiC,EACjC,SAAkB,EAClB,eAAwB,EACxB,MAAW,EACX,UAAiB,EACpB,GAAE,aAAkB;
|
|
1
|
+
{"version":3,"file":"sprint.d.ts","sourceRoot":"","sources":["../../src/sprint.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAsC,MAAM,SAAS,CAAC;AACrF,OAAO,OAAO,EAAE,EAAE,WAAW,EAAoD,MAAM,SAAS,CAAC;AAmBjG,eAAO,MAAM,aAAa,SAAQ,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,qBAAa,MAAM;IACR,GAAG,EAAE,WAAW,CAAC;IACxB,OAAO,CAAC,IAAI,CAAqC;IACjD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,iBAAiB,CAA0B;gBAEvC,EACR,IAAuB,EACvB,UAAuB,EACvB,eAAiC,EACjC,YAA2B,EAC3B,SAAkB,EAClB,eAAwB,EACxB,MAAW,EACX,UAAiB,EACpB,GAAE,aAAkB;YAoBP,IAAI;IA+BtB,OAAO,CAAC,YAAY;IAgDhB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;YACW,eAAe;IAgC7B,OAAO,CAAC,eAAe;YAcT,UAAU;YAgDV,YAAY;IAmB1B,OAAO,CAAC,YAAY;IAgCpB,+BAA+B;IAC/B,OAAO,CAAC,WAAW;IAMZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO;IAK3D,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI;CAgB7C"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
|
2
2
|
export type Handler = (req: Request, res: Response, next: NextFunction) => any;
|
|
3
3
|
export type AuthorizationSource = `query:${string}` | `headers:${string}`;
|
|
4
4
|
export interface SprintRequest {
|
|
5
|
-
getAuthorization: (sources
|
|
5
|
+
getAuthorization: (sources?: AuthorizationSource | AuthorizationSource[]) => string | undefined;
|
|
6
6
|
}
|
|
7
7
|
declare global {
|
|
8
8
|
namespace Express {
|
|
@@ -50,6 +50,8 @@ export interface SprintOptions {
|
|
|
50
50
|
routesPath?: string;
|
|
51
51
|
/** Path to middlewares folder. Default: "./middlewares" */
|
|
52
52
|
middlewaresPath?: string;
|
|
53
|
+
/** Path to cronjobs folder. Default: "./cronjobs" */
|
|
54
|
+
cronjobsPath?: string;
|
|
53
55
|
/** Maximum request body size. Default: "50mb" */
|
|
54
56
|
jsonLimit?: string;
|
|
55
57
|
/** Maximum request body size. Default: "50mb" */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE1E,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,GAAG,CAAC;AAE/E,MAAM,MAAM,mBAAmB,GACzB,SAAS,MAAM,EAAE,GACjB,WAAW,MAAM,EAAE,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC1B,gBAAgB,EAAE,CAAC,OAAO,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,KAAK,MAAM,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE1E,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,GAAG,CAAC;AAE/E,MAAM,MAAM,mBAAmB,GACzB,SAAS,MAAM,EAAE,GACjB,WAAW,MAAM,EAAE,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC1B,gBAAgB,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,KAAK,MAAM,GAAG,SAAS,CAAC;CACnG;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC;QACd,UAAU,OAAO;YACb,MAAM,EAAE,aAAa,CAAC;SACzB;KACJ;CACJ;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IAC3C;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,SAAiC,CAAC;AACpD,eAAO,MAAM,SAAS,SAAqC,CAAC;AAE5D,QAAA,IAAI,UAAU,EAAE,MAAM,CAAC;AACvB,QAAA,IAAI,SAAS,EAAE,MAAM,CAAC;AAYtB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAEjC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,SAAiC,CAAC;AACpD,eAAO,MAAM,SAAS,SAAqC,CAAC;AAE5D,QAAA,IAAI,UAAU,EAAE,MAAM,CAAC;AACvB,QAAA,IAAI,SAAS,EAAE,MAAM,CAAC;AAYtB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAEjC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAoBxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprint-es",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.36",
|
|
4
4
|
"description": "Sprint - Quickly API",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -32,6 +32,16 @@
|
|
|
32
32
|
"types": "./dist/types/modules/schemas/index.d.ts",
|
|
33
33
|
"require": "./dist/cjs/modules/schemas/index.cjs",
|
|
34
34
|
"import": "./dist/esm/modules/schemas/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./cronjobs": {
|
|
37
|
+
"types": "./dist/types/modules/cronjobs/index.d.ts",
|
|
38
|
+
"require": "./dist/cjs/modules/cronjobs/index.cjs",
|
|
39
|
+
"import": "./dist/esm/modules/cronjobs/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./jwt": {
|
|
42
|
+
"types": "./dist/types/modules/jwt/index.d.ts",
|
|
43
|
+
"require": "./dist/cjs/modules/jwt/index.cjs",
|
|
44
|
+
"import": "./dist/esm/modules/jwt/index.js"
|
|
35
45
|
}
|
|
36
46
|
},
|
|
37
47
|
"files": [
|
|
@@ -68,6 +78,7 @@
|
|
|
68
78
|
"cors": "^2.8.5",
|
|
69
79
|
"express": "^5.1.0",
|
|
70
80
|
"morgan": "^1.10.1",
|
|
81
|
+
"node-cron": "^3.0.3",
|
|
71
82
|
"path": "^0.12.7",
|
|
72
83
|
"serve-favicon": "^2.5.1",
|
|
73
84
|
"toolkitify": "^0.0.26",
|
|
@@ -84,6 +95,7 @@
|
|
|
84
95
|
"@types/jest": "^30.0.0",
|
|
85
96
|
"@types/morgan": "^1.9.10",
|
|
86
97
|
"@types/node": "^22.18.7",
|
|
98
|
+
"@types/node-cron": "^3.0.11",
|
|
87
99
|
"@types/serve-favicon": "^2.5.7",
|
|
88
100
|
"dotenv": "^17.2.3",
|
|
89
101
|
"jest": "^30.1.3",
|