skyguard-js 1.2.1 → 1.2.3
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/README.md +11 -680
- package/dist/app.d.ts +14 -9
- package/dist/app.js +37 -30
- package/dist/http/context.d.ts +115 -0
- package/dist/http/context.js +147 -0
- package/dist/http/httpAdapter.d.ts +4 -4
- package/dist/http/index.d.ts +3 -1
- package/dist/http/index.js +5 -1
- package/dist/http/logger.d.ts +9 -2
- package/dist/http/logger.js +49 -1
- package/dist/http/nodeNativeHttp.d.ts +4 -4
- package/dist/http/nodeNativeHttp.js +11 -4
- package/dist/http/request.d.ts +4 -0
- package/dist/http/request.js +8 -0
- package/dist/http/response.d.ts +21 -2
- package/dist/http/response.js +30 -2
- package/dist/http/webHttp.d.ts +19 -0
- package/dist/http/webHttp.js +95 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/middlewares/cors.d.ts +10 -4
- package/dist/middlewares/cors.js +35 -18
- package/dist/middlewares/csrf.js +33 -33
- package/dist/middlewares/index.d.ts +1 -1
- package/dist/middlewares/rateLimiter.d.ts +58 -6
- package/dist/middlewares/rateLimiter.js +149 -40
- package/dist/middlewares/session.js +4 -4
- package/dist/parsers/contentParserManager.d.ts +4 -2
- package/dist/parsers/contentParserManager.js +22 -3
- package/dist/routing/routeResolveFunc.d.ts +10 -0
- package/dist/routing/routeResolveFunc.js +21 -0
- package/dist/routing/router.d.ts +16 -10
- package/dist/routing/router.js +32 -25
- package/dist/routing/routerGroup.d.ts +10 -5
- package/dist/routing/routerGroup.js +11 -10
- package/dist/server/bunRuntimeServer.d.ts +7 -0
- package/dist/server/bunRuntimeServer.js +28 -0
- package/dist/server/createRuntimeServer.d.ts +4 -0
- package/dist/server/createRuntimeServer.js +23 -0
- package/dist/server/denoRuntimeServer.d.ts +7 -0
- package/dist/server/denoRuntimeServer.js +27 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.js +19 -0
- package/dist/server/modulePath.d.ts +6 -0
- package/dist/server/modulePath.js +18 -0
- package/dist/server/nodeRuntimeServer.d.ts +7 -0
- package/dist/server/nodeRuntimeServer.js +21 -0
- package/dist/server/runtimeDetector.d.ts +4 -0
- package/dist/server/runtimeDetector.js +15 -0
- package/dist/server/types.d.ts +11 -0
- package/dist/server/types.js +2 -0
- package/dist/sessions/index.d.ts +2 -2
- package/dist/storage/storage.d.ts +3 -3
- package/dist/storage/storage.js +7 -7
- package/dist/storage/types.d.ts +5 -5
- package/dist/storage/uploader.d.ts +9 -9
- package/dist/storage/uploader.js +62 -62
- package/dist/types/index.d.ts +11 -10
- package/dist/validators/index.d.ts +2 -2
- package/dist/validators/rules/index.d.ts +5 -5
- package/dist/validators/validationSchema.js +8 -8
- package/package.json +2 -2
- package/dist/helpers/http.d.ts +0 -95
- package/dist/helpers/http.js +0 -112
package/dist/storage/uploader.js
CHANGED
|
@@ -63,7 +63,7 @@ class Uploader {
|
|
|
63
63
|
* - If the file field does not exist, it does not error; it only attaches text
|
|
64
64
|
* fields and continues.
|
|
65
65
|
* - If present, the file is validated, filtered (optional), stored via the
|
|
66
|
-
* configured {@link Storage}, and attached as `
|
|
66
|
+
* configured {@link Storage}, and attached as `ctx.req.files`.
|
|
67
67
|
*
|
|
68
68
|
* @param fieldName Multipart field name expected to contain a file.
|
|
69
69
|
* @returns A framework {@link Middleware} to be used in the route pipeline.
|
|
@@ -74,22 +74,22 @@ class Uploader {
|
|
|
74
74
|
* - INVALID_FILE_TYPE if rejected by the filter
|
|
75
75
|
*/
|
|
76
76
|
single(fieldName) {
|
|
77
|
-
return async (
|
|
78
|
-
const multipartData = this.getMultipartData(
|
|
77
|
+
return async (context, next) => {
|
|
78
|
+
const multipartData = this.getMultipartData(context);
|
|
79
79
|
if (!multipartData)
|
|
80
|
-
return await next(
|
|
80
|
+
return await next(context);
|
|
81
81
|
this.validateFieldLimits(multipartData);
|
|
82
82
|
const fileData = multipartData.files.find(f => f.fieldName === fieldName);
|
|
83
83
|
if (!fileData) {
|
|
84
|
-
this.attachFieldsToRequest(
|
|
85
|
-
return await next(
|
|
84
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
85
|
+
return await next(context);
|
|
86
86
|
}
|
|
87
87
|
this.validateFileSize(fileData);
|
|
88
|
-
await this.applyFileFilter(
|
|
89
|
-
const file = await this.processFile(
|
|
90
|
-
|
|
91
|
-
this.attachFieldsToRequest(
|
|
92
|
-
return await next(
|
|
88
|
+
await this.applyFileFilter(context, fileData);
|
|
89
|
+
const file = await this.processFile(context, fileData);
|
|
90
|
+
context.req.files = file;
|
|
91
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
92
|
+
return await next(context);
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
@@ -97,11 +97,11 @@ class Uploader {
|
|
|
97
97
|
*
|
|
98
98
|
* Behavior:
|
|
99
99
|
* - If no multipart payload is present, it passes through.
|
|
100
|
-
* - If no files exist for the given field, it sets `
|
|
100
|
+
* - If no files exist for the given field, it sets `ctx.req.files = []`,
|
|
101
101
|
* attaches text fields, and continues.
|
|
102
102
|
* - If the number of files exceeds `maxCount`, it throws.
|
|
103
103
|
* - Each file is validated, filtered (optional), stored, and collected into
|
|
104
|
-
* `
|
|
104
|
+
* `ctx.req.files` as an array of {@link UploadedFile}.
|
|
105
105
|
*
|
|
106
106
|
* @param fieldName Multipart field name expected to contain files.
|
|
107
107
|
* @param maxCount Maximum number of files allowed for this field.
|
|
@@ -114,16 +114,16 @@ class Uploader {
|
|
|
114
114
|
* - INVALID_FILE_TYPE if any file is rejected by the filter
|
|
115
115
|
*/
|
|
116
116
|
array(fieldName, maxCount = 10) {
|
|
117
|
-
return async (
|
|
118
|
-
const multipartData = this.getMultipartData(
|
|
117
|
+
return async (context, next) => {
|
|
118
|
+
const multipartData = this.getMultipartData(context);
|
|
119
119
|
if (!multipartData)
|
|
120
|
-
return await next(
|
|
120
|
+
return await next(context);
|
|
121
121
|
this.validateFieldLimits(multipartData);
|
|
122
122
|
const filesData = multipartData.files.filter(file => file.fieldName === fieldName);
|
|
123
123
|
if (filesData.length === 0) {
|
|
124
|
-
|
|
125
|
-
this.attachFieldsToRequest(
|
|
126
|
-
return await next(
|
|
124
|
+
context.req.files = [];
|
|
125
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
126
|
+
return await next(context);
|
|
127
127
|
}
|
|
128
128
|
if (filesData.length > maxCount) {
|
|
129
129
|
throw new uploadException_1.UploadException(`Too many files. Expected max ${maxCount} but got ${filesData.length}`, types_1.UploadErrorCode.LIMIT_FILE_COUNT, fieldName);
|
|
@@ -131,12 +131,12 @@ class Uploader {
|
|
|
131
131
|
const files = [];
|
|
132
132
|
for (const fileData of filesData) {
|
|
133
133
|
this.validateFileSize(fileData);
|
|
134
|
-
await this.applyFileFilter(
|
|
135
|
-
files.push(await this.processFile(
|
|
134
|
+
await this.applyFileFilter(context, fileData);
|
|
135
|
+
files.push(await this.processFile(context, fileData));
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
this.attachFieldsToRequest(
|
|
139
|
-
return await next(
|
|
137
|
+
context.req.files = files;
|
|
138
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
139
|
+
return await next(context);
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
@@ -145,7 +145,7 @@ class Uploader {
|
|
|
145
145
|
* Behavior:
|
|
146
146
|
* - Rejects any file whose field name is not declared in `fields`.
|
|
147
147
|
* - Enforces `maxCount` per declared field (defaults to 1).
|
|
148
|
-
* - Aggregates results as `
|
|
148
|
+
* - Aggregates results as `ctx.req.files` in a map:
|
|
149
149
|
* `{ [fieldName]: UploadedFile[] }`.
|
|
150
150
|
*
|
|
151
151
|
* @param fields List of allowed fields and their per-field maximum counts.
|
|
@@ -159,10 +159,10 @@ class Uploader {
|
|
|
159
159
|
* - INVALID_FILE_TYPE if rejected by the filter
|
|
160
160
|
*/
|
|
161
161
|
fields(fields) {
|
|
162
|
-
return async (
|
|
163
|
-
const multipartData = this.getMultipartData(
|
|
162
|
+
return async (context, next) => {
|
|
163
|
+
const multipartData = this.getMultipartData(context);
|
|
164
164
|
if (!multipartData)
|
|
165
|
-
return await next(
|
|
165
|
+
return await next(context);
|
|
166
166
|
this.validateFieldLimits(multipartData);
|
|
167
167
|
const filesMap = {};
|
|
168
168
|
const fieldMap = new Map(fields.map(field => [field.name, field.maxCount || 1]));
|
|
@@ -176,12 +176,12 @@ class Uploader {
|
|
|
176
176
|
throw new uploadException_1.UploadException(`Too many files for field "${fileData.fieldName}". Max ${maxCount}`, types_1.UploadErrorCode.LIMIT_FILE_COUNT, fileData.fieldName);
|
|
177
177
|
}
|
|
178
178
|
this.validateFileSize(fileData);
|
|
179
|
-
await this.applyFileFilter(
|
|
180
|
-
filesMap[fileData.fieldName].push(await this.processFile(
|
|
179
|
+
await this.applyFileFilter(context, fileData);
|
|
180
|
+
filesMap[fileData.fieldName].push(await this.processFile(context, fileData));
|
|
181
181
|
}
|
|
182
|
-
|
|
183
|
-
this.attachFieldsToRequest(
|
|
184
|
-
return await next(
|
|
182
|
+
context.req.files = filesMap;
|
|
183
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
184
|
+
return await next(context);
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
/**
|
|
@@ -189,7 +189,7 @@ class Uploader {
|
|
|
189
189
|
*
|
|
190
190
|
* Behavior:
|
|
191
191
|
* - Enforces the global total file limit: `limits.files`.
|
|
192
|
-
* - Stores all files and attaches them as `
|
|
192
|
+
* - Stores all files and attaches them as `ctx.req.files` (array).
|
|
193
193
|
*
|
|
194
194
|
* @returns A framework {@link Middleware}.
|
|
195
195
|
*
|
|
@@ -200,22 +200,22 @@ class Uploader {
|
|
|
200
200
|
* - INVALID_FILE_TYPE if rejected by the filter
|
|
201
201
|
*/
|
|
202
202
|
any() {
|
|
203
|
-
return async (
|
|
204
|
-
const multipartData = this.getMultipartData(
|
|
203
|
+
return async (context, next) => {
|
|
204
|
+
const multipartData = this.getMultipartData(context);
|
|
205
205
|
if (!multipartData)
|
|
206
|
-
return await next(
|
|
206
|
+
return await next(context);
|
|
207
207
|
this.validateFieldLimits(multipartData);
|
|
208
208
|
if (multipartData.files.length > this.limits.files)
|
|
209
209
|
throw new uploadException_1.UploadException(`Too many files. Max ${this.limits.files}`, types_1.UploadErrorCode.LIMIT_FILE_COUNT);
|
|
210
210
|
const files = [];
|
|
211
211
|
for (const fileData of multipartData.files) {
|
|
212
212
|
this.validateFileSize(fileData);
|
|
213
|
-
await this.applyFileFilter(
|
|
214
|
-
files.push(await this.processFile(
|
|
213
|
+
await this.applyFileFilter(context, fileData);
|
|
214
|
+
files.push(await this.processFile(context, fileData));
|
|
215
215
|
}
|
|
216
|
-
|
|
217
|
-
this.attachFieldsToRequest(
|
|
218
|
-
return await next(
|
|
216
|
+
context.req.files = files;
|
|
217
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
218
|
+
return await next(context);
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
/**
|
|
@@ -231,15 +231,15 @@ class Uploader {
|
|
|
231
231
|
* - LIMIT_UNEXPECTED_FILE if at least one file is received
|
|
232
232
|
*/
|
|
233
233
|
none() {
|
|
234
|
-
return async (
|
|
235
|
-
const multipartData = this.getMultipartData(
|
|
234
|
+
return async (context, next) => {
|
|
235
|
+
const multipartData = this.getMultipartData(context);
|
|
236
236
|
if (!multipartData)
|
|
237
|
-
return await next(
|
|
237
|
+
return await next(context);
|
|
238
238
|
if (multipartData.files.length > 0) {
|
|
239
239
|
throw new uploadException_1.UploadException("No files expected", types_1.UploadErrorCode.LIMIT_UNEXPECTED_FILE, multipartData.files[0].fieldName);
|
|
240
240
|
}
|
|
241
|
-
this.attachFieldsToRequest(
|
|
242
|
-
return await next(
|
|
241
|
+
this.attachFieldsToRequest(context, multipartData);
|
|
242
|
+
return await next(context);
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
245
|
/**
|
|
@@ -249,14 +249,14 @@ class Uploader {
|
|
|
249
249
|
* @param fileData File descriptor from {@link MultipartData}.
|
|
250
250
|
* @returns The stored file metadata returned by the storage engine.
|
|
251
251
|
*/
|
|
252
|
-
async processFile(
|
|
252
|
+
async processFile(context, fileData) {
|
|
253
253
|
const partialFile = {
|
|
254
254
|
fieldName: fileData.fieldName,
|
|
255
255
|
originalname: fileData.filename,
|
|
256
256
|
mimetype: fileData.mimetype,
|
|
257
257
|
size: fileData.size,
|
|
258
258
|
};
|
|
259
|
-
return await this.storage.handleFile(
|
|
259
|
+
return await this.storage.handleFile(context, partialFile, fileData.data);
|
|
260
260
|
}
|
|
261
261
|
/**
|
|
262
262
|
* Extracts multipart data from the request if available.
|
|
@@ -264,10 +264,10 @@ class Uploader {
|
|
|
264
264
|
* @param request Current HTTP request.
|
|
265
265
|
* @returns Parsed multipart data or null if not present.
|
|
266
266
|
*/
|
|
267
|
-
getMultipartData(
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
return
|
|
267
|
+
getMultipartData(context) {
|
|
268
|
+
if (context.headers["content-type"] &&
|
|
269
|
+
context.headers["content-type"].startsWith("multipart/form-data"))
|
|
270
|
+
return context.body;
|
|
271
271
|
return null;
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
@@ -282,7 +282,7 @@ class Uploader {
|
|
|
282
282
|
* @throws UploadException when the filter rejects the file
|
|
283
283
|
* @throws Error when the filter throws or returns an error
|
|
284
284
|
*/
|
|
285
|
-
applyFileFilter(
|
|
285
|
+
applyFileFilter(context, fileData) {
|
|
286
286
|
if (!this.fileFilter)
|
|
287
287
|
return Promise.resolve();
|
|
288
288
|
const partialFile = {
|
|
@@ -301,7 +301,7 @@ class Uploader {
|
|
|
301
301
|
};
|
|
302
302
|
// Call the filter; it may use the callback or return a Promise.
|
|
303
303
|
try {
|
|
304
|
-
const result = this.fileFilter(
|
|
304
|
+
const result = this.fileFilter(context, partialFile, (error, acceptFile) => {
|
|
305
305
|
finish(error, acceptFile);
|
|
306
306
|
});
|
|
307
307
|
// If the filter returned a Promise and didn't use the callback,
|
|
@@ -349,13 +349,13 @@ class Uploader {
|
|
|
349
349
|
* @param req Current HTTP request.
|
|
350
350
|
* @param multipartData Parsed multipart payload containing text fields.
|
|
351
351
|
*/
|
|
352
|
-
attachFieldsToRequest(
|
|
353
|
-
const currentData =
|
|
352
|
+
attachFieldsToRequest(context, multipartData) {
|
|
353
|
+
const currentData = context.body || {};
|
|
354
354
|
const newData = {
|
|
355
355
|
...currentData,
|
|
356
356
|
...multipartData.fields,
|
|
357
357
|
};
|
|
358
|
-
|
|
358
|
+
context.req.setBody(newData);
|
|
359
359
|
}
|
|
360
360
|
/**
|
|
361
361
|
* Creates a storage engine instance from the selected {@link StorageType}.
|
|
@@ -397,10 +397,10 @@ class Uploader {
|
|
|
397
397
|
},
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
-
//
|
|
401
|
-
app.post("/file", (
|
|
402
|
-
return json({ file:
|
|
403
|
-
}
|
|
400
|
+
// Assign middleware to a route
|
|
401
|
+
app.post("/file", [uploader.single("file")], context => {
|
|
402
|
+
return context.json({ file: context.req.files });
|
|
403
|
+
})
|
|
404
404
|
*/
|
|
405
405
|
const createUploader = (config) => {
|
|
406
406
|
return new Uploader(config);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Response,
|
|
1
|
+
import { Response, Context, HttpMethods } from "../http/index";
|
|
2
2
|
import { Layer } from "../routing/layer";
|
|
3
3
|
/**
|
|
4
4
|
* Route controller function.
|
|
5
5
|
*
|
|
6
6
|
* Represents the final endpoint in the execution pipeline.
|
|
7
|
-
* Receives a normalized {@link
|
|
7
|
+
* Receives a normalized {@link Context} and must return
|
|
8
8
|
* a {@link Response}.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
|
-
* const handler: RouteHandler =
|
|
12
|
-
* return
|
|
11
|
+
* const handler: RouteHandler = context => {
|
|
12
|
+
* return context.json({ message: "Hello world" });
|
|
13
13
|
* };
|
|
14
14
|
*/
|
|
15
|
-
export type RouteHandler = (
|
|
15
|
+
export type RouteHandler = (context: Context) => Promise<Response> | Response;
|
|
16
16
|
/**
|
|
17
17
|
* Internal routing table structure.
|
|
18
18
|
*
|
|
@@ -82,19 +82,20 @@ export type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
|
|
82
82
|
*
|
|
83
83
|
* Can be synchronous or asynchronous.
|
|
84
84
|
*
|
|
85
|
-
* @param
|
|
85
|
+
* @param context - Current {@link Context} instance
|
|
86
86
|
* @param next - Function that executes the next middleware
|
|
87
87
|
* or the route handler
|
|
88
88
|
* @returns A {@link Response} or a Promise resolving to {@link Response}
|
|
89
89
|
*
|
|
90
90
|
* @example
|
|
91
|
-
* const loggerMiddleware: Middleware = async (
|
|
92
|
-
* console.log(
|
|
91
|
+
* const loggerMiddleware: Middleware = async (context, next) => {
|
|
92
|
+
* console.log(context.req.method, context.req.url);
|
|
93
93
|
*
|
|
94
|
-
* const response = await next(
|
|
94
|
+
* const response = await next(context);
|
|
95
95
|
* return response;
|
|
96
96
|
* };
|
|
97
97
|
*
|
|
98
98
|
* app.middlewares(loggerMiddleware);
|
|
99
99
|
*/
|
|
100
|
-
export type Middleware = (
|
|
100
|
+
export type Middleware = (context: Context, next: RouteHandler) => Response | Promise<Response>;
|
|
101
|
+
export type HandlerOrMiddlewares = RouteHandler | Middleware[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ValidationRule } from "./validationRule";
|
|
1
|
+
export type { ValidationRule } from "./validationRule";
|
|
2
2
|
export { Validator } from "./validator";
|
|
3
3
|
export * from "./rules";
|
|
4
|
-
export { RuleOptions, ValidationContext, ValidationError, ValidationResult, FieldDefinition, } from "./types";
|
|
4
|
+
export type { RuleOptions, ValidationContext, ValidationError, ValidationResult, FieldDefinition, } from "./types";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { BooleanRule } from "./booleanRule";
|
|
2
|
-
export { DateRule, DateRuleOptions } from "./dateRule";
|
|
3
|
-
export { NumberRule, NumberRuleOptions } from "./numberRule";
|
|
4
|
-
export { StringRule, StringRuleOptions } from "./stringRule";
|
|
5
|
-
export { ArrayRule, ArrayRuleOptions } from "./arrayRule";
|
|
2
|
+
export { DateRule, type DateRuleOptions } from "./dateRule";
|
|
3
|
+
export { NumberRule, type NumberRuleOptions } from "./numberRule";
|
|
4
|
+
export { StringRule, type StringRuleOptions } from "./stringRule";
|
|
5
|
+
export { ArrayRule, type ArrayRuleOptions } from "./arrayRule";
|
|
6
6
|
export { LiteralRule } from "./literalRule";
|
|
7
7
|
export { ObjectRule } from "./objectRule";
|
|
8
8
|
export { UnionRule } from "./unionRule";
|
|
9
|
-
export { BigIntRule, BigIntRuleOptions } from "./bigIntRule";
|
|
9
|
+
export { BigIntRule, type BigIntRuleOptions } from "./bigIntRule";
|
|
@@ -340,20 +340,20 @@ exports.v = new ValidatorRules();
|
|
|
340
340
|
* @param schema - Validation rules mapped by field name
|
|
341
341
|
*/
|
|
342
342
|
const validateRequest = (schema) => {
|
|
343
|
-
return (
|
|
343
|
+
return (context, next) => {
|
|
344
344
|
if (schema.body) {
|
|
345
|
-
const validBody = validator_1.Validator.validateOrFail(
|
|
346
|
-
|
|
345
|
+
const validBody = validator_1.Validator.validateOrFail(context.body, schema.body);
|
|
346
|
+
context.req.setBody(validBody);
|
|
347
347
|
}
|
|
348
348
|
if (schema.params) {
|
|
349
|
-
const validParams = validator_1.Validator.validateOrFail(
|
|
350
|
-
|
|
349
|
+
const validParams = validator_1.Validator.validateOrFail(context.params, schema.params);
|
|
350
|
+
context.req.setParams(validParams);
|
|
351
351
|
}
|
|
352
352
|
if (schema.query) {
|
|
353
|
-
const validQuery = validator_1.Validator.validateOrFail(
|
|
354
|
-
|
|
353
|
+
const validQuery = validator_1.Validator.validateOrFail(context.query, schema.query);
|
|
354
|
+
context.req.setQuery(validQuery);
|
|
355
355
|
}
|
|
356
|
-
return next(
|
|
356
|
+
return next(context);
|
|
357
357
|
};
|
|
358
358
|
};
|
|
359
359
|
exports.validateRequest = validateRequest;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skyguard-js",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "A lightweight, dependency-free TypeScript backend framework",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"bugs": {
|
|
30
30
|
"url": "https://github.com/Pipe930/Skyguard-js/issues"
|
|
31
31
|
},
|
|
32
|
-
"homepage": "https://github.
|
|
32
|
+
"homepage": "https://pipe930.github.io/skyguard-documentation/",
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=22"
|
|
35
35
|
},
|
package/dist/helpers/http.d.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { Response } from "../http/response";
|
|
2
|
-
/**
|
|
3
|
-
* Creates an HTTP response with a JSON body.
|
|
4
|
-
*
|
|
5
|
-
* @typeParam T - Type of the payload to be serialized.
|
|
6
|
-
* @param data - Data to be serialized as JSON.
|
|
7
|
-
* @returns A `Response` instance with `Content-Type: application/json`.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* return json({ ok: true, userId: 1 });
|
|
11
|
-
*/
|
|
12
|
-
export declare function json(data: unknown): Response;
|
|
13
|
-
/**
|
|
14
|
-
* Creates an HTTP response with a plain text body.
|
|
15
|
-
*
|
|
16
|
-
* @param data - Text to be sent as the response body.
|
|
17
|
-
* @returns A `Response` instance with a text-based `Content-Type`.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* return text("Hello world");
|
|
21
|
-
*/
|
|
22
|
-
export declare function text(data: string): Response;
|
|
23
|
-
/**
|
|
24
|
-
* Creates an HTTP redirect response to the given URL.
|
|
25
|
-
*
|
|
26
|
-
* @param url - Target URL for the redirection (absolute or relative).
|
|
27
|
-
* @returns A `Response` instance configured as a redirect.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* return redirect("/login");
|
|
31
|
-
*/
|
|
32
|
-
export declare function redirect(url: string): Response;
|
|
33
|
-
/**
|
|
34
|
-
* Returns a file as a downloadable response.
|
|
35
|
-
*
|
|
36
|
-
* @param path - File system path to the file (relative or absolute, depending on the runtime).
|
|
37
|
-
* @param filename - Optional filename suggested to the client for the download.
|
|
38
|
-
* @param headers - Optional additional headers to include in the response.
|
|
39
|
-
* @returns A `Promise<Response>` ready to be returned by a route handler.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* return await download("./storage/reports/sales.pdf", "report.pdf", {
|
|
43
|
-
* "Cache-Control": "no-store",
|
|
44
|
-
* });
|
|
45
|
-
*/
|
|
46
|
-
export declare function download(path: string, filename?: string, headers?: Record<string, string>): Promise<Response>;
|
|
47
|
-
/**
|
|
48
|
-
* Renders a template/view and returns an HTTP response with the generated HTML.
|
|
49
|
-
*
|
|
50
|
-
* @param view - View identifier or template path, depending on the template system.
|
|
51
|
-
* @param params - Context variables available inside the template.
|
|
52
|
-
* @param layout - Optional layout name used to wrap the rendered view.
|
|
53
|
-
* @returns A `Promise<Response>` containing the rendered HTML.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* return await render("users/profile", { user }, "main");
|
|
57
|
-
*/
|
|
58
|
-
export declare function render(data: string, params?: Record<string, unknown>): Promise<Response>;
|
|
59
|
-
/**
|
|
60
|
-
* Sends a file as an HTTP response.
|
|
61
|
-
*
|
|
62
|
-
* This helper is a thin wrapper around `Response.sendFile`, allowing a file
|
|
63
|
-
* to be streamed to the client while optionally applying custom headers
|
|
64
|
-
* and resolving the file path relative to a root directory.
|
|
65
|
-
*
|
|
66
|
-
* @param filePath - Path to the file to send.
|
|
67
|
-
* @param options - Optional configuration for the file response.
|
|
68
|
-
* @param options.headers - Additional HTTP headers to include in the response
|
|
69
|
-
* (e.g. `Content-Type`, `Cache-Control`, `Content-Disposition`).
|
|
70
|
-
* @param options.root - Base directory used to resolve `filePath`.
|
|
71
|
-
* @returns A `Response` object that streams the requested file to the client.
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* // Send a file using an absolute path
|
|
75
|
-
* const response = await sendFile("/var/www/files/report.pdf", {});
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* // Send a file relative to a root directory
|
|
79
|
-
* const response = await sendFile("report.pdf", {
|
|
80
|
-
* root: "/var/www/files",
|
|
81
|
-
* });
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* // Send a downloadable file
|
|
85
|
-
* const response = await sendFile("report.pdf", {
|
|
86
|
-
* root: "/var/www/files",
|
|
87
|
-
* headers: {
|
|
88
|
-
* "Content-Disposition": "attachment; filename=\"report.pdf\"",
|
|
89
|
-
* },
|
|
90
|
-
* });
|
|
91
|
-
*/
|
|
92
|
-
export declare function sendFile(filePath: string, options: {
|
|
93
|
-
headers?: Record<string, string>;
|
|
94
|
-
root?: string;
|
|
95
|
-
}): Promise<Response>;
|
package/dist/helpers/http.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.json = json;
|
|
4
|
-
exports.text = text;
|
|
5
|
-
exports.redirect = redirect;
|
|
6
|
-
exports.download = download;
|
|
7
|
-
exports.render = render;
|
|
8
|
-
exports.sendFile = sendFile;
|
|
9
|
-
const response_1 = require("../http/response");
|
|
10
|
-
/**
|
|
11
|
-
* Creates an HTTP response with a JSON body.
|
|
12
|
-
*
|
|
13
|
-
* @typeParam T - Type of the payload to be serialized.
|
|
14
|
-
* @param data - Data to be serialized as JSON.
|
|
15
|
-
* @returns A `Response` instance with `Content-Type: application/json`.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* return json({ ok: true, userId: 1 });
|
|
19
|
-
*/
|
|
20
|
-
function json(data) {
|
|
21
|
-
return response_1.Response.json(data);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Creates an HTTP response with a plain text body.
|
|
25
|
-
*
|
|
26
|
-
* @param data - Text to be sent as the response body.
|
|
27
|
-
* @returns A `Response` instance with a text-based `Content-Type`.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* return text("Hello world");
|
|
31
|
-
*/
|
|
32
|
-
function text(data) {
|
|
33
|
-
return response_1.Response.text(data);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Creates an HTTP redirect response to the given URL.
|
|
37
|
-
*
|
|
38
|
-
* @param url - Target URL for the redirection (absolute or relative).
|
|
39
|
-
* @returns A `Response` instance configured as a redirect.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* return redirect("/login");
|
|
43
|
-
*/
|
|
44
|
-
function redirect(url) {
|
|
45
|
-
return response_1.Response.redirect(url);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Returns a file as a downloadable response.
|
|
49
|
-
*
|
|
50
|
-
* @param path - File system path to the file (relative or absolute, depending on the runtime).
|
|
51
|
-
* @param filename - Optional filename suggested to the client for the download.
|
|
52
|
-
* @param headers - Optional additional headers to include in the response.
|
|
53
|
-
* @returns A `Promise<Response>` ready to be returned by a route handler.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* return await download("./storage/reports/sales.pdf", "report.pdf", {
|
|
57
|
-
* "Cache-Control": "no-store",
|
|
58
|
-
* });
|
|
59
|
-
*/
|
|
60
|
-
async function download(path, filename, headers) {
|
|
61
|
-
return await response_1.Response.download(path, filename, headers);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Renders a template/view and returns an HTTP response with the generated HTML.
|
|
65
|
-
*
|
|
66
|
-
* @param view - View identifier or template path, depending on the template system.
|
|
67
|
-
* @param params - Context variables available inside the template.
|
|
68
|
-
* @param layout - Optional layout name used to wrap the rendered view.
|
|
69
|
-
* @returns A `Promise<Response>` containing the rendered HTML.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* return await render("users/profile", { user }, "main");
|
|
73
|
-
*/
|
|
74
|
-
async function render(data, params) {
|
|
75
|
-
return await response_1.Response.render(data, params);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Sends a file as an HTTP response.
|
|
79
|
-
*
|
|
80
|
-
* This helper is a thin wrapper around `Response.sendFile`, allowing a file
|
|
81
|
-
* to be streamed to the client while optionally applying custom headers
|
|
82
|
-
* and resolving the file path relative to a root directory.
|
|
83
|
-
*
|
|
84
|
-
* @param filePath - Path to the file to send.
|
|
85
|
-
* @param options - Optional configuration for the file response.
|
|
86
|
-
* @param options.headers - Additional HTTP headers to include in the response
|
|
87
|
-
* (e.g. `Content-Type`, `Cache-Control`, `Content-Disposition`).
|
|
88
|
-
* @param options.root - Base directory used to resolve `filePath`.
|
|
89
|
-
* @returns A `Response` object that streams the requested file to the client.
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* // Send a file using an absolute path
|
|
93
|
-
* const response = await sendFile("/var/www/files/report.pdf", {});
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* // Send a file relative to a root directory
|
|
97
|
-
* const response = await sendFile("report.pdf", {
|
|
98
|
-
* root: "/var/www/files",
|
|
99
|
-
* });
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* // Send a downloadable file
|
|
103
|
-
* const response = await sendFile("report.pdf", {
|
|
104
|
-
* root: "/var/www/files",
|
|
105
|
-
* headers: {
|
|
106
|
-
* "Content-Disposition": "attachment; filename=\"report.pdf\"",
|
|
107
|
-
* },
|
|
108
|
-
* });
|
|
109
|
-
*/
|
|
110
|
-
async function sendFile(filePath, options) {
|
|
111
|
-
return await response_1.Response.sendFile(filePath, options);
|
|
112
|
-
}
|