skyguard-js 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +29 -7
  2. package/dist/app.d.ts +9 -0
  3. package/dist/app.js +12 -2
  4. package/dist/crypto/hasher.d.ts +19 -10
  5. package/dist/crypto/hasher.js +21 -10
  6. package/dist/crypto/jwt.d.ts +76 -14
  7. package/dist/crypto/jwt.js +217 -40
  8. package/dist/http/logger.d.ts +47 -0
  9. package/dist/http/logger.js +47 -0
  10. package/dist/http/request.d.ts +12 -0
  11. package/dist/http/request.js +19 -0
  12. package/dist/http/response.d.ts +9 -0
  13. package/dist/http/response.js +27 -0
  14. package/dist/middlewares/cors.d.ts +14 -27
  15. package/dist/middlewares/cors.js +13 -9
  16. package/dist/middlewares/index.d.ts +0 -1
  17. package/dist/middlewares/index.js +1 -3
  18. package/dist/middlewares/session.d.ts +46 -14
  19. package/dist/middlewares/session.js +71 -59
  20. package/dist/parsers/contentParserManager.d.ts +0 -6
  21. package/dist/parsers/contentParserManager.js +0 -6
  22. package/dist/parsers/jsonParser.js +1 -2
  23. package/dist/parsers/multipartParser.d.ts +86 -6
  24. package/dist/parsers/multipartParser.js +88 -9
  25. package/dist/parsers/parserInterface.d.ts +2 -13
  26. package/dist/parsers/parserInterface.js +0 -14
  27. package/dist/parsers/textParser.js +2 -3
  28. package/dist/parsers/urlEncodedParser.js +1 -2
  29. package/dist/parsers/xmlParser.d.ts +90 -0
  30. package/dist/parsers/xmlParser.js +92 -3
  31. package/dist/routing/layer.d.ts +0 -22
  32. package/dist/routing/layer.js +5 -23
  33. package/dist/routing/router.d.ts +0 -36
  34. package/dist/routing/router.js +0 -36
  35. package/dist/routing/routerGroup.d.ts +0 -15
  36. package/dist/routing/routerGroup.js +0 -15
  37. package/dist/sessions/{cookieOptions.d.ts → cookies.d.ts} +37 -18
  38. package/dist/sessions/cookies.js +73 -0
  39. package/dist/sessions/fileSessionStorage.d.ts +133 -81
  40. package/dist/sessions/fileSessionStorage.js +199 -135
  41. package/dist/sessions/index.d.ts +1 -1
  42. package/dist/sessions/index.js +4 -1
  43. package/dist/sessions/memorySessionStorage.d.ts +108 -59
  44. package/dist/sessions/memorySessionStorage.js +156 -73
  45. package/dist/sessions/session.d.ts +11 -71
  46. package/dist/sessions/session.js +23 -72
  47. package/dist/sessions/sessionStorage.d.ts +24 -65
  48. package/dist/sessions/sessionStorage.js +3 -0
  49. package/dist/static/contentDisposition.d.ts +78 -19
  50. package/dist/static/contentDisposition.js +78 -19
  51. package/dist/static/fileDownload.d.ts +0 -14
  52. package/dist/static/fileDownload.js +0 -14
  53. package/dist/static/fileStaticHandler.d.ts +0 -11
  54. package/dist/static/fileStaticHandler.js +1 -12
  55. package/dist/storage/storage.d.ts +17 -31
  56. package/dist/storage/storage.js +102 -35
  57. package/dist/storage/types.d.ts +23 -6
  58. package/dist/storage/uploader.d.ts +21 -0
  59. package/dist/storage/uploader.js +45 -8
  60. package/dist/validators/validationSchema.d.ts +7 -6
  61. package/dist/validators/validationSchema.js +7 -6
  62. package/dist/validators/validator.d.ts +0 -23
  63. package/dist/validators/validator.js +0 -23
  64. package/dist/views/engineTemplate.js +4 -3
  65. package/package.json +2 -2
  66. package/dist/middlewares/auth.d.ts +0 -34
  67. package/dist/middlewares/auth.js +0 -57
  68. package/dist/sessions/cookieOptions.js +0 -2
package/README.md CHANGED
@@ -55,12 +55,14 @@ import { createApp, Response } from "skyguard-js";
55
55
 
56
56
  const app = createApp();
57
57
 
58
+ const PORT = 3000;
59
+
58
60
  app.get("/health", () => {
59
61
  return Response.json({ status: "ok" });
60
62
  });
61
63
 
62
- app.run(3000, () => {
63
- console.log(`Server running in port: http://localhost:${3000}`);
64
+ app.run(PORT, () => {
65
+ console.log(`Server running in port: http://localhost:${PORT}`);
64
66
  });
65
67
  ```
66
68
 
@@ -136,11 +138,12 @@ To enable CORS, use the built-in `cors` middleware.
136
138
 
137
139
  ```ts
138
140
  import { cors } from "skyguard-js/middlewares";
141
+ import { HttpMethods } from "skyguard-js";
139
142
 
140
143
  app.middlewares([
141
144
  cors({
142
145
  origin: ["http://localhost:3000", "https://myapp.com"],
143
- methods: ["GET", "POST"],
146
+ methods: [HttpMethods.get, HttpMethods.post],
144
147
  allowedHeaders: ["Content-Type", "Authorization"],
145
148
  credentials: true,
146
149
  }),
@@ -242,7 +245,20 @@ To handle sessions, you must use the framework’s built-in middleware. Dependin
242
245
  import { sessions } from "skyguard-js/middlewares";
243
246
  import { FileSessionStorage } from "skyguard-js";
244
247
 
245
- app.middlewares([sessions(FileSessionStorage)]);
248
+ app.middlewares([
249
+ sessions(FileSessionStorage, {
250
+ name: "connect.sid",
251
+ rolling: true,
252
+ saveUninitialized: false,
253
+ cookie: {
254
+ maxAge: 60 * 60 * 24,
255
+ httpOnly: true,
256
+ sameSite: "Lax",
257
+ secure: false,
258
+ path: "/",
259
+ },
260
+ }),
261
+ ]);
246
262
 
247
263
  app.post("/login", (request: Request) => {
248
264
  const { username, password } = request.data;
@@ -276,7 +292,6 @@ The framework includes some password hashing and JWT token generation functions,
276
292
 
277
293
  ```ts
278
294
  import { hash, verify, createJWT } from "skyguard-js/security";
279
- import { authJWT } from "skyguard-js/middlewares";
280
295
 
281
296
  app.post("/register", async (request: Request) => {
282
297
  const { username, password } = request.data;
@@ -300,7 +315,10 @@ app.post("/login", async (request: Request) => {
300
315
  throw new UnauthorizedError("Invalid credentials");
301
316
  }
302
317
 
303
- const token = createJWT({ sub: user.id, role: user.role }, "1h");
318
+ const token = createJWT({ sub: "123" }, "secret-key", {
319
+ algorithm: "HS256",
320
+ expiresIn: "1h",
321
+ });
304
322
 
305
323
  return Response.json({ token });
306
324
  });
@@ -318,7 +336,9 @@ import { createUploader, StorageType } from "skyguard-js";
318
336
  const uploader = createUploader({
319
337
  storageType: StorageType.DISK,
320
338
  storageOptions: {
321
- destination: "./uploads",
339
+ disk: {
340
+ destination: "./uploads",
341
+ },
322
342
  },
323
343
  });
324
344
 
@@ -334,6 +354,8 @@ app.post(
334
354
  );
335
355
  ```
336
356
 
357
+ Depending on the `Storage Type` you have selected, the storage options will contain two properties: `disk` and `memory`
358
+
337
359
  ---
338
360
 
339
361
  ## 📄 Views & Template Engine
package/dist/app.d.ts CHANGED
@@ -62,6 +62,7 @@ export declare class App {
62
62
  *
63
63
  * @example
64
64
  * app.staticFiles("public");
65
+ * app.staticFiles(join(__dirname, "..", "public"));
65
66
  * // /public/css/style.css → /css/style.css
66
67
  */
67
68
  staticFiles(publicPath: string): void;
@@ -134,6 +135,14 @@ export declare class App {
134
135
  * Registers global middlewares.
135
136
  *
136
137
  * These are executed for every route.
138
+ *
139
+ * @example
140
+ * const auth = async (request, next) => {
141
+ * console.log(request.header);
142
+ * return await next(request);
143
+ * }
144
+ *
145
+ * app.middlewares(auth);
137
146
  */
138
147
  middlewares(middlewares: Middleware[]): void;
139
148
  /**
package/dist/app.js CHANGED
@@ -50,8 +50,8 @@ class App {
50
50
  */
51
51
  static bootstrap() {
52
52
  const app = container_1.Container.singleton(App);
53
- app.router = new routing_1.Router();
54
- app.logger = new http_1.Logger();
53
+ app.router = container_1.Container.singleton(routing_1.Router);
54
+ app.logger = container_1.Container.singleton(http_1.Logger);
55
55
  app.viewEngine = container_1.Container.singleton(engineTemplate_1.ViewEngine);
56
56
  return app;
57
57
  }
@@ -93,6 +93,7 @@ class App {
93
93
  *
94
94
  * @example
95
95
  * app.staticFiles("public");
96
+ * app.staticFiles(join(__dirname, "..", "public"));
96
97
  * // /public/css/style.css → /css/style.css
97
98
  */
98
99
  staticFiles(publicPath) {
@@ -192,6 +193,14 @@ class App {
192
193
  * Registers global middlewares.
193
194
  *
194
195
  * These are executed for every route.
196
+ *
197
+ * @example
198
+ * const auth = async (request, next) => {
199
+ * console.log(request.header);
200
+ * return await next(request);
201
+ * }
202
+ *
203
+ * app.middlewares(auth);
195
204
  */
196
205
  middlewares(middlewares) {
197
206
  this.router.middlewares(middlewares);
@@ -228,6 +237,7 @@ class App {
228
237
  statusCode: 500,
229
238
  message: "Internal Server Error",
230
239
  }).setStatusCode(500));
240
+ // eslint-disable-next-line no-console
231
241
  console.error(error);
232
242
  }
233
243
  }
@@ -15,6 +15,9 @@ type ScryptOptions = {
15
15
  * @param params - Scrypt work-factor params. Defaults to `DEFAULT_PARAMS`.
16
16
  * @param pepper - Optional server secret mixed into the password (e.g., from env var).
17
17
  * @returns A compact encoded hash string containing algorithm parameters + salt + derived key.
18
+ *
19
+ * @example
20
+ * const passwordHash = await hash("password", 16);
18
21
  */
19
22
  export declare const hash: (password: string, saltLength?: number, params?: ScryptOptions, pepper?: string) => Promise<string>;
20
23
  /**
@@ -28,6 +31,9 @@ export declare const hash: (password: string, saltLength?: number, params?: Scry
28
31
  * @param storedHash - Stored hash string in the compact format.
29
32
  * @param pepper - Optional server secret; must match the one used when hashing.
30
33
  * @returns `true` if the password matches, otherwise `false`.
34
+ *
35
+ * @example
36
+ * const validPassword = await verify("password", "passwordHashed");
31
37
  */
32
38
  export declare const verify: (password: string, storedHash: string, pepper?: string) => Promise<boolean>;
33
39
  /**
@@ -42,6 +48,9 @@ export declare const verify: (password: string, storedHash: string, pepper?: str
42
48
  * @param storedHash - Stored hash string in compact format.
43
49
  * @param params - Desired/current scrypt params. Defaults to `DEFAULT_PARAMS`.
44
50
  * @returns `true` if the hash is missing/invalid or was produced with different parameters.
51
+ *
52
+ * @example
53
+ * const passwordRehash = needsRehash("passwordHashed");
45
54
  */
46
55
  export declare const needsRehash: (storedHash: string, params?: ScryptOptions) => boolean;
47
56
  /**
@@ -62,13 +71,13 @@ export declare const needsRehash: (storedHash: string, params?: ScryptOptions) =
62
71
  * - pepper: optional server secret
63
72
  * - concurrency: max simultaneous operations (default 4)
64
73
  * @returns Array of compact hash strings in the same order as input.
74
+ *
75
+ * @example
76
+ *
77
+ * const listPasswords = ["password1", "password2", "password3"];
78
+ * const passwordsHasherList = await hashBatch(listPasswords, 16);
65
79
  */
66
- export declare const hashBatch: (passwords: string[], options?: {
67
- saltLength?: number;
68
- params?: ScryptOptions;
69
- pepper?: string;
70
- concurrency?: number;
71
- }) => Promise<string[]>;
80
+ export declare const hashBatch: (passwords: string[], saltLength?: number, concurrency?: number, params?: ScryptOptions, pepper?: string) => Promise<string[]>;
72
81
  /**
73
82
  * Verifies multiple password/hash pairs using controlled concurrency.
74
83
  *
@@ -80,12 +89,12 @@ export declare const hashBatch: (passwords: string[], options?: {
80
89
  * - pepper: optional server secret
81
90
  * - concurrency: max simultaneous operations (default 8)
82
91
  * @returns Array of booleans in the same order as input.
92
+ *
93
+ * @example
94
+ * const verifyPasswords = await verifyBatch([{ password: "test", hash: "testHash" }, { password: "test2", hash: "testHash2" }]);
83
95
  */
84
96
  export declare const verifyBatch: (credentials: Array<{
85
97
  password: string;
86
98
  hash: string;
87
- }>, options?: {
88
- pepper?: string;
89
- concurrency?: number;
90
- }) => Promise<boolean[]>;
99
+ }>, concurrency?: number, pepper?: string) => Promise<boolean[]>;
91
100
  export {};
@@ -87,6 +87,9 @@ const parseHash = (hash) => {
87
87
  * @param params - Scrypt work-factor params. Defaults to `DEFAULT_PARAMS`.
88
88
  * @param pepper - Optional server secret mixed into the password (e.g., from env var).
89
89
  * @returns A compact encoded hash string containing algorithm parameters + salt + derived key.
90
+ *
91
+ * @example
92
+ * const passwordHash = await hash("password", 16);
90
93
  */
91
94
  const hash = async (password, saltLength = 16, params = DEFAULT_PARAMS, pepper) => {
92
95
  const salt = (0, node_crypto_1.randomBytes)(saltLength);
@@ -111,6 +114,9 @@ exports.hash = hash;
111
114
  * @param storedHash - Stored hash string in the compact format.
112
115
  * @param pepper - Optional server secret; must match the one used when hashing.
113
116
  * @returns `true` if the password matches, otherwise `false`.
117
+ *
118
+ * @example
119
+ * const validPassword = await verify("password", "passwordHashed");
114
120
  */
115
121
  const verify = async (password, storedHash, pepper) => {
116
122
  const parsed = parseHash(storedHash);
@@ -145,6 +151,9 @@ exports.verify = verify;
145
151
  * @param storedHash - Stored hash string in compact format.
146
152
  * @param params - Desired/current scrypt params. Defaults to `DEFAULT_PARAMS`.
147
153
  * @returns `true` if the hash is missing/invalid or was produced with different parameters.
154
+ *
155
+ * @example
156
+ * const passwordRehash = needsRehash("passwordHashed");
148
157
  */
149
158
  const needsRehash = (storedHash, params = DEFAULT_PARAMS) => {
150
159
  const parsed = parseHash(storedHash);
@@ -191,13 +200,14 @@ const mapLimit = async (items, limit, fn) => {
191
200
  * - pepper: optional server secret
192
201
  * - concurrency: max simultaneous operations (default 4)
193
202
  * @returns Array of compact hash strings in the same order as input.
203
+ *
204
+ * @example
205
+ *
206
+ * const listPasswords = ["password1", "password2", "password3"];
207
+ * const passwordsHasherList = await hashBatch(listPasswords, 16);
194
208
  */
195
- const hashBatch = async (passwords, options) => {
196
- const saltLength = options?.saltLength ?? 16;
197
- const params = options?.params ?? DEFAULT_PARAMS;
198
- const pepper = options?.pepper;
199
- const concurrency = options?.concurrency ?? 4;
200
- return mapLimit(passwords, concurrency, p => (0, exports.hash)(p, saltLength, params, pepper));
209
+ const hashBatch = async (passwords, saltLength = 16, concurrency = 4, params = DEFAULT_PARAMS, pepper) => {
210
+ return mapLimit(passwords, concurrency, password => (0, exports.hash)(password, saltLength, params, pepper));
201
211
  };
202
212
  exports.hashBatch = hashBatch;
203
213
  /**
@@ -211,10 +221,11 @@ exports.hashBatch = hashBatch;
211
221
  * - pepper: optional server secret
212
222
  * - concurrency: max simultaneous operations (default 8)
213
223
  * @returns Array of booleans in the same order as input.
224
+ *
225
+ * @example
226
+ * const verifyPasswords = await verifyBatch([{ password: "test", hash: "testHash" }, { password: "test2", hash: "testHash2" }]);
214
227
  */
215
- const verifyBatch = async (credentials, options) => {
216
- const pepper = options?.pepper;
217
- const concurrency = options?.concurrency ?? 8;
218
- return mapLimit(credentials, concurrency, c => (0, exports.verify)(c.password, c.hash, pepper));
228
+ const verifyBatch = async (credentials, concurrency = 8, pepper) => {
229
+ return mapLimit(credentials, concurrency, credential => (0, exports.verify)(credential.password, credential.hash, pepper));
219
230
  };
220
231
  exports.verifyBatch = verifyBatch;
@@ -1,31 +1,93 @@
1
+ /**
2
+ * Represents the payload (claims set) of a JSON Web Token.
3
+ *
4
+ * A JWT payload may contain arbitrary custom claims.
5
+ * Common registered claims:
6
+ * - `exp` (Expiration Time) – Unix timestamp (seconds)
7
+ * - `iat` (Issued At) – Unix timestamp (seconds)
8
+ *
9
+ * Additional claims may be added depending on the application.
10
+ */
1
11
  interface JWTPayload {
2
12
  [key: string]: any;
3
13
  exp?: number;
4
14
  iat?: number;
5
15
  }
16
+ /**
17
+ * Represents the header section of a JWT.
18
+ *
19
+ * - `alg` – Signing algorithm used
20
+ * - `typ` – Token type (typically `"JWT"`)
21
+ */
6
22
  interface JWTHeader {
7
23
  alg: string;
8
24
  typ: string;
9
25
  }
10
26
  /**
11
- * Crea un JSON Web Token
12
- * @param payload - Datos a incluir en el token
13
- * @param secret - Clave secreta para firmar
14
- * @param expiresIn - Tiempo de expiración en segundos (opcional)
15
- * @returns JWT string
27
+ * Supported JWT signing algorithms.
28
+ *
29
+ * - HS* HMAC (symmetric secret)
30
+ * - RS* RSA (asymmetric public/private key)
31
+ */
32
+ type Algorithm = "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512";
33
+ /**
34
+ * Options used when creating a JWT.
35
+ */
36
+ interface CreateJWTOptions {
37
+ /**
38
+ * Signing algorithm.
39
+ * Defaults to `"HS256"` if not provided.
40
+ */
41
+ algorithm?: Algorithm;
42
+ /**
43
+ * Token expiration:
44
+ * - Number → seconds
45
+ * - String → time expression (e.g. `"1h"`, `"30m"`, `"2d"`)
46
+ */
47
+ expiresIn?: number | string;
48
+ }
49
+ /**
50
+ * Creates a JSON Web Token (JWT) signed using HMAC-SHA256 (HS256).
51
+ *
52
+ * Note:
53
+ * This implementation produces **stateless signed tokens** and does not
54
+ * encrypt the payload. Anyone can decode the payload, but only holders of
55
+ * the secret can generate a valid signature.
56
+ *
57
+ * @param payload - Custom claims to include in the token.
58
+ * @param secret - Secret key used to sign the token.
59
+ * @param expiresIn - Optional expiration time in seconds.
60
+ * @returns Signed JWT string.
61
+ *
62
+ * @example
63
+ * const jwt = createJWT({ sub: "123" }, "secret", { algorithm: "HS512", expiresIn: "1h" });
16
64
  */
17
- export declare const createJWT: (payload: JWTPayload, secret: string, expiresIn?: number) => string;
65
+ export declare const createJWT: (payload: JWTPayload, secret: string | Buffer, opts?: number | string | CreateJWTOptions) => string;
18
66
  /**
19
- * Verifica y decodifica un JSON Web Token
20
- * @param token - JWT a verificar
21
- * @param secret - Clave secreta usada para firmar
22
- * @returns Payload decodificado o null si es inválido
67
+ * Verifies the signature and validity of a JWT.
68
+ *
69
+ * Returns `null` if validation fails at any step.
70
+ *
71
+ * @param token - JWT string.
72
+ * @param secret - Secret (HMAC) or public key (RSA).
73
+ * @returns Decoded payload if valid, otherwise `null`.
74
+ *
75
+ * @example
76
+ * const verifyToken = verifyJWT("token", "secret-key");
23
77
  */
24
- export declare const verifyJWT: (token: string, secret: string) => JWTPayload | null;
78
+ export declare const verifyJWT: (token: string, secret: string | Buffer) => JWTPayload | null;
25
79
  /**
26
- * Decodifica un JWT sin verificar la firma (útil para debugging)
27
- * @param token - JWT a decodificar
28
- * @returns Objeto con header y payload decodificados
80
+ * Decodes a JWT without verifying its signature.
81
+ *
82
+ * ⚠️ Security warning:
83
+ * This function MUST NOT be used for authentication or authorization.
84
+ * It is intended only for debugging, logging, or inspecting token contents.
85
+ *
86
+ * @param token - JWT string to decode.
87
+ * @returns Object containing decoded header and payload, or `null` if malformed.
88
+ *
89
+ * @example
90
+ * conste decodeToken = decodeJWT("token");
29
91
  */
30
92
  export declare const decodeJWT: (token: string) => {
31
93
  header: JWTHeader;