@arcis/node 1.3.0 → 1.4.0

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 (118) hide show
  1. package/dist/core/{index.d.mts → constants.d.ts} +21 -70
  2. package/dist/core/constants.d.ts.map +1 -0
  3. package/dist/core/errors.d.ts +53 -0
  4. package/dist/core/errors.d.ts.map +1 -0
  5. package/dist/core/index.d.ts +6 -168
  6. package/dist/core/index.d.ts.map +1 -0
  7. package/dist/{types-BOkx5YJc.d.mts → core/types.d.ts} +27 -30
  8. package/dist/core/types.d.ts.map +1 -0
  9. package/dist/index.d.ts +71 -166
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +57 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +56 -3
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/logging/index.d.ts +4 -36
  16. package/dist/logging/index.d.ts.map +1 -0
  17. package/dist/logging/{index.d.mts → redactor.d.ts} +5 -9
  18. package/dist/logging/redactor.d.ts.map +1 -0
  19. package/dist/middleware/bot-detection.d.ts +86 -0
  20. package/dist/middleware/bot-detection.d.ts.map +1 -0
  21. package/dist/middleware/cookies.d.ts +48 -0
  22. package/dist/middleware/cookies.d.ts.map +1 -0
  23. package/dist/middleware/cors.d.ts +65 -0
  24. package/dist/middleware/cors.d.ts.map +1 -0
  25. package/dist/middleware/csrf.d.ts +109 -0
  26. package/dist/middleware/csrf.d.ts.map +1 -0
  27. package/dist/middleware/error-handler.d.ts +43 -0
  28. package/dist/middleware/error-handler.d.ts.map +1 -0
  29. package/dist/middleware/headers.d.ts +29 -0
  30. package/dist/middleware/headers.d.ts.map +1 -0
  31. package/dist/middleware/hpp.d.ts +56 -0
  32. package/dist/middleware/hpp.d.ts.map +1 -0
  33. package/dist/middleware/index.d.ts +16 -3
  34. package/dist/middleware/index.d.ts.map +1 -0
  35. package/dist/middleware/index.js +6 -1
  36. package/dist/middleware/index.js.map +1 -1
  37. package/dist/middleware/index.mjs +6 -1
  38. package/dist/middleware/index.mjs.map +1 -1
  39. package/dist/middleware/main.d.ts +40 -0
  40. package/dist/middleware/main.d.ts.map +1 -0
  41. package/dist/middleware/rate-limit-sliding.d.ts +46 -0
  42. package/dist/middleware/rate-limit-sliding.d.ts.map +1 -0
  43. package/dist/middleware/rate-limit-token.d.ts +51 -0
  44. package/dist/middleware/rate-limit-token.d.ts.map +1 -0
  45. package/dist/middleware/rate-limit.d.ts +34 -0
  46. package/dist/middleware/rate-limit.d.ts.map +1 -0
  47. package/dist/sanitizers/command.d.ts +28 -0
  48. package/dist/sanitizers/command.d.ts.map +1 -0
  49. package/dist/sanitizers/encode.d.ts +46 -0
  50. package/dist/sanitizers/encode.d.ts.map +1 -0
  51. package/dist/sanitizers/headers.d.ts +46 -0
  52. package/dist/sanitizers/headers.d.ts.map +1 -0
  53. package/dist/sanitizers/index.d.ts +17 -22
  54. package/dist/sanitizers/index.d.ts.map +1 -0
  55. package/dist/sanitizers/jsonp.d.ts +34 -0
  56. package/dist/sanitizers/jsonp.d.ts.map +1 -0
  57. package/dist/sanitizers/nosql.d.ts +31 -0
  58. package/dist/sanitizers/nosql.d.ts.map +1 -0
  59. package/dist/sanitizers/path.d.ts +28 -0
  60. package/dist/sanitizers/path.d.ts.map +1 -0
  61. package/dist/sanitizers/pii.d.ts +80 -0
  62. package/dist/sanitizers/pii.d.ts.map +1 -0
  63. package/dist/sanitizers/prototype.d.ts +34 -0
  64. package/dist/sanitizers/prototype.d.ts.map +1 -0
  65. package/dist/sanitizers/sanitize.d.ts +51 -0
  66. package/dist/sanitizers/sanitize.d.ts.map +1 -0
  67. package/dist/sanitizers/sql.d.ts +28 -0
  68. package/dist/sanitizers/sql.d.ts.map +1 -0
  69. package/dist/sanitizers/ssti.d.ts +20 -0
  70. package/dist/sanitizers/ssti.d.ts.map +1 -0
  71. package/dist/sanitizers/utils.d.ts +19 -0
  72. package/dist/sanitizers/utils.d.ts.map +1 -0
  73. package/dist/sanitizers/xss.d.ts +35 -0
  74. package/dist/sanitizers/xss.d.ts.map +1 -0
  75. package/dist/sanitizers/xxe.d.ts +20 -0
  76. package/dist/sanitizers/xxe.d.ts.map +1 -0
  77. package/dist/stores/index.d.ts +6 -104
  78. package/dist/stores/index.d.ts.map +1 -0
  79. package/dist/stores/memory.d.ts +35 -0
  80. package/dist/stores/memory.d.ts.map +1 -0
  81. package/dist/stores/{index.d.mts → redis.d.ts} +6 -45
  82. package/dist/stores/redis.d.ts.map +1 -0
  83. package/dist/utils/duration.d.ts +34 -0
  84. package/dist/utils/duration.d.ts.map +1 -0
  85. package/dist/utils/fingerprint.d.ts +64 -0
  86. package/dist/utils/fingerprint.d.ts.map +1 -0
  87. package/dist/utils/index.d.ts +10 -0
  88. package/dist/utils/index.d.ts.map +1 -0
  89. package/dist/utils/index.js +188 -0
  90. package/dist/utils/index.js.map +1 -0
  91. package/dist/utils/index.mjs +182 -0
  92. package/dist/utils/index.mjs.map +1 -0
  93. package/dist/utils/ip.d.ts +70 -0
  94. package/dist/utils/ip.d.ts.map +1 -0
  95. package/dist/validation/email.d.ts +82 -0
  96. package/dist/validation/email.d.ts.map +1 -0
  97. package/dist/validation/file.d.ts +90 -0
  98. package/dist/validation/file.d.ts.map +1 -0
  99. package/dist/validation/index.d.ts +10 -3
  100. package/dist/validation/index.d.ts.map +1 -0
  101. package/dist/validation/redirect.d.ts +64 -0
  102. package/dist/validation/redirect.d.ts.map +1 -0
  103. package/dist/validation/schema.d.ts +36 -0
  104. package/dist/validation/schema.d.ts.map +1 -0
  105. package/dist/validation/url.d.ts +65 -0
  106. package/dist/validation/url.d.ts.map +1 -0
  107. package/package.json +8 -6
  108. package/dist/encode-CrQCGlBq.d.mts +0 -484
  109. package/dist/encode-jl9sOwmA.d.ts +0 -484
  110. package/dist/index-BAhgn9V2.d.ts +0 -532
  111. package/dist/index-BGNKspqH.d.ts +0 -340
  112. package/dist/index-Cd02z-0j.d.mts +0 -340
  113. package/dist/index-DgJtWMSj.d.mts +0 -532
  114. package/dist/index.d.mts +0 -175
  115. package/dist/middleware/index.d.mts +0 -3
  116. package/dist/sanitizers/index.d.mts +0 -24
  117. package/dist/types-BOkx5YJc.d.ts +0 -279
  118. package/dist/validation/index.d.mts +0 -3
@@ -1,38 +1,6 @@
1
- import { L as LogOptions, S as SafeLogger } from '../types-BOkx5YJc.js';
2
- import 'express';
3
-
4
1
  /**
5
- * @module @arcis/node/logging/redactor
6
- * Safe logging with PII/secret redaction
2
+ * @module @arcis/node/logging
3
+ * Safe logging for Arcis
7
4
  */
8
-
9
- /**
10
- * Create a safe logger that redacts sensitive data and prevents log injection.
11
- *
12
- * @param options - Logger configuration
13
- * @returns SafeLogger instance
14
- *
15
- * @example
16
- * const logger = createSafeLogger();
17
- * logger.info('User login', { email: 'user@test.com', password: 'secret' });
18
- * // Logs: { "email": "user@test.com", "password": "[REDACTED]" }
19
- *
20
- * @example
21
- * // With custom redact keys
22
- * const logger = createSafeLogger({ redactKeys: ['customToken', 'internalId'] });
23
- */
24
- declare function createSafeLogger(options?: LogOptions): SafeLogger;
25
- /**
26
- * Create a redactor function for custom use.
27
- *
28
- * @param sensitiveKeys - Keys to redact
29
- * @returns Redactor function
30
- */
31
- declare function createRedactor(sensitiveKeys?: string[]): (obj: unknown) => unknown;
32
- /**
33
- * Alias for createSafeLogger
34
- * @see createSafeLogger
35
- */
36
- declare const safeLog: typeof createSafeLogger;
37
-
38
- export { createRedactor, createSafeLogger, safeLog };
5
+ export { createSafeLogger, createRedactor, safeLog } from './redactor';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logging/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
@@ -1,11 +1,8 @@
1
- import { L as LogOptions, S as SafeLogger } from '../types-BOkx5YJc.mjs';
2
- import 'express';
3
-
4
1
  /**
5
2
  * @module @arcis/node/logging/redactor
6
3
  * Safe logging with PII/secret redaction
7
4
  */
8
-
5
+ import type { LogOptions, SafeLogger } from '../core/types';
9
6
  /**
10
7
  * Create a safe logger that redacts sensitive data and prevents log injection.
11
8
  *
@@ -21,18 +18,17 @@ import 'express';
21
18
  * // With custom redact keys
22
19
  * const logger = createSafeLogger({ redactKeys: ['customToken', 'internalId'] });
23
20
  */
24
- declare function createSafeLogger(options?: LogOptions): SafeLogger;
21
+ export declare function createSafeLogger(options?: LogOptions): SafeLogger;
25
22
  /**
26
23
  * Create a redactor function for custom use.
27
24
  *
28
25
  * @param sensitiveKeys - Keys to redact
29
26
  * @returns Redactor function
30
27
  */
31
- declare function createRedactor(sensitiveKeys?: string[]): (obj: unknown) => unknown;
28
+ export declare function createRedactor(sensitiveKeys?: string[]): (obj: unknown) => unknown;
32
29
  /**
33
30
  * Alias for createSafeLogger
34
31
  * @see createSafeLogger
35
32
  */
36
- declare const safeLog: typeof createSafeLogger;
37
-
38
- export { createRedactor, createSafeLogger, safeLog };
33
+ export declare const safeLog: typeof createSafeLogger;
34
+ //# sourceMappingURL=redactor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactor.d.ts","sourceRoot":"","sources":["../../src/logging/redactor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAU5D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,UAAe,GAAG,UAAU,CAwErE;AA2BD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,aAAa,GAAE,MAAM,EAAO,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CA2BtF;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,yBAAmB,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module @arcis/node/middleware/bot-detection
3
+ * Local-only bot detection using User-Agent and behavioral signals.
4
+ *
5
+ * Categorizes requests into bot types and allows/denies based on config.
6
+ * No cloud calls — everything runs locally.
7
+ *
8
+ * @example
9
+ * // Block automated tools, allow search engines
10
+ * app.use(botProtection({
11
+ * allow: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'],
12
+ * deny: ['AUTOMATED', 'SCRAPER'],
13
+ * }));
14
+ */
15
+ import type { Request, Response, RequestHandler } from 'express';
16
+ export type BotCategory = 'SEARCH_ENGINE' | 'SOCIAL' | 'MONITORING' | 'AI_CRAWLER' | 'SCRAPER' | 'AUTOMATED' | 'UNKNOWN' | 'HUMAN';
17
+ export interface BotDetectionResult {
18
+ /** Whether the request appears to be from a bot */
19
+ isBot: boolean;
20
+ /** Bot category */
21
+ category: BotCategory;
22
+ /** Matched bot name (e.g. 'Googlebot', 'curl') or null */
23
+ name: string | null;
24
+ /** Confidence score: 0-1 */
25
+ confidence: number;
26
+ /** Behavioral signals detected */
27
+ signals: string[];
28
+ }
29
+ export interface BotProtectionOptions {
30
+ /** Categories to explicitly allow. Default: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'] */
31
+ allow?: BotCategory[];
32
+ /** Categories to explicitly deny. Default: ['AUTOMATED'] */
33
+ deny?: BotCategory[];
34
+ /** Action for categories not in allow or deny. Default: 'allow' */
35
+ defaultAction?: 'allow' | 'deny';
36
+ /** HTTP status code for denied bots. Default: 403 */
37
+ statusCode?: number;
38
+ /** Error message for denied bots */
39
+ message?: string;
40
+ /** Enable behavioral signal detection. Default: true */
41
+ detectBehavior?: boolean;
42
+ /** Custom handler called on detection (instead of default deny response) */
43
+ onDetected?: (req: Request, res: Response, result: BotDetectionResult) => void;
44
+ }
45
+ /**
46
+ * Detect what kind of bot (if any) is making the request.
47
+ *
48
+ * @param req - HTTP request object
49
+ * @returns Detection result with category, name, confidence, and signals
50
+ *
51
+ * @example
52
+ * const result = detectBot(req);
53
+ * if (result.isBot && result.category === 'AUTOMATED') {
54
+ * // Block automated tools
55
+ * }
56
+ */
57
+ export declare function detectBot(req: Request): BotDetectionResult;
58
+ /**
59
+ * Create Express middleware for bot protection.
60
+ *
61
+ * @example
62
+ * // Block automated tools and scrapers
63
+ * app.use(botProtection({
64
+ * allow: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'],
65
+ * deny: ['AUTOMATED', 'SCRAPER'],
66
+ * }));
67
+ *
68
+ * @example
69
+ * // Block everything except search engines
70
+ * app.use(botProtection({
71
+ * allow: ['SEARCH_ENGINE'],
72
+ * defaultAction: 'deny',
73
+ * }));
74
+ *
75
+ * @example
76
+ * // Custom handler
77
+ * app.use(botProtection({
78
+ * deny: ['AUTOMATED'],
79
+ * onDetected: (req, res, result) => {
80
+ * console.log(`Bot blocked: ${result.name} (${result.category})`);
81
+ * res.status(403).json({ error: 'Bots not allowed' });
82
+ * },
83
+ * }));
84
+ */
85
+ export declare function botProtection(options?: BotProtectionOptions): RequestHandler;
86
+ //# sourceMappingURL=bot-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-detection.d.ts","sourceRoot":"","sources":["../../src/middleware/bot-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAM/E,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,WAAW,GACX,SAAS,GACT,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,mBAAmB;IACnB,QAAQ,EAAE,WAAW,CAAC;IACtB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,yFAAyF;IACzF,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrB,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAChF;AA4JD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAmD1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAgDhF"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @module @arcis/node/middleware/cookies
3
+ * Secure cookie defaults middleware
4
+ */
5
+ import type { RequestHandler } from 'express';
6
+ /** Cookie security configuration */
7
+ export interface SecureCookieOptions {
8
+ /** Force HttpOnly on all cookies. Default: true */
9
+ httpOnly?: boolean;
10
+ /** Force Secure flag (HTTPS only). Default: true in production, false in dev */
11
+ secure?: boolean;
12
+ /** SameSite attribute. Default: 'Lax' */
13
+ sameSite?: 'Strict' | 'Lax' | 'None' | false;
14
+ /** Override Path attribute. Default: undefined (keep original) */
15
+ path?: string;
16
+ }
17
+ /**
18
+ * Enforce secure defaults on a Set-Cookie header value.
19
+ */
20
+ export declare function enforceSecureCookie(cookieStr: string, options: Required<Omit<SecureCookieOptions, 'path'>> & {
21
+ path?: string;
22
+ }): string;
23
+ /**
24
+ * Create middleware that enforces secure cookie defaults.
25
+ *
26
+ * Intercepts Set-Cookie headers and adds missing security attributes:
27
+ * - HttpOnly: prevents JavaScript access (XSS cookie theft)
28
+ * - Secure: cookies only sent over HTTPS
29
+ * - SameSite: CSRF protection
30
+ *
31
+ * @param options - Cookie security configuration
32
+ * @returns Express middleware
33
+ *
34
+ * @example
35
+ * // Enforce defaults on all cookies
36
+ * app.use(secureCookieDefaults());
37
+ *
38
+ * @example
39
+ * // Strict SameSite for sensitive apps
40
+ * app.use(secureCookieDefaults({ sameSite: 'Strict' }));
41
+ */
42
+ export declare function secureCookieDefaults(options?: SecureCookieOptions): RequestHandler;
43
+ /**
44
+ * Alias for secureCookieDefaults
45
+ * @see secureCookieDefaults
46
+ */
47
+ export declare const createSecureCookies: typeof secureCookieDefaults;
48
+ //# sourceMappingURL=cookies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/middleware/cookies.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC7C,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAUD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,MAAM,CA4CR;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,mBAAwB,GAAG,cAAc,CA0BtF;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,6BAAuB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @module @arcis/node/middleware/cors
3
+ * Safe CORS middleware with secure defaults
4
+ */
5
+ import type { RequestHandler } from 'express';
6
+ /** CORS configuration options */
7
+ export interface CorsOptions {
8
+ /**
9
+ * Allowed origins. Can be:
10
+ * - A string: exact match (e.g., 'https://example.com')
11
+ * - An array: whitelist of allowed origins
12
+ * - A RegExp: pattern match (use with care)
13
+ * - A function: custom validation `(origin) => boolean`
14
+ * - `true`: reflect the request origin (DANGEROUS — only for dev)
15
+ *
16
+ * Default: none (no origin allowed). You must explicitly set this.
17
+ */
18
+ origin: string | string[] | RegExp | ((origin: string) => boolean) | true;
19
+ /** Allowed HTTP methods. Default: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] */
20
+ methods?: string[];
21
+ /** Allowed headers. Default: ['Content-Type', 'Authorization'] */
22
+ allowedHeaders?: string[];
23
+ /** Headers exposed to the browser. Default: [] */
24
+ exposedHeaders?: string[];
25
+ /** Allow credentials (cookies, authorization headers). Default: false */
26
+ credentials?: boolean;
27
+ /** Preflight cache duration in seconds. Default: 600 (10 minutes) */
28
+ maxAge?: number;
29
+ /** Respond to preflight with 204 (no content). Default: true */
30
+ preflightContinue?: boolean;
31
+ }
32
+ /**
33
+ * Create safe CORS middleware.
34
+ *
35
+ * Unlike permissive CORS libraries, this enforces secure defaults:
36
+ * - No wildcard `*` when credentials are enabled
37
+ * - `null` origin is always blocked
38
+ * - `Vary: Origin` is always set for proper caching
39
+ * - You must explicitly configure allowed origins
40
+ *
41
+ * @param options - CORS configuration
42
+ * @returns Express middleware
43
+ *
44
+ * @example
45
+ * // Allow a single origin
46
+ * app.use(safeCors({ origin: 'https://myapp.com' }));
47
+ *
48
+ * @example
49
+ * // Allow multiple origins with credentials
50
+ * app.use(safeCors({
51
+ * origin: ['https://myapp.com', 'https://admin.myapp.com'],
52
+ * credentials: true,
53
+ * }));
54
+ *
55
+ * @example
56
+ * // Development: allow all (NOT for production)
57
+ * app.use(safeCors({ origin: true }));
58
+ */
59
+ export declare function safeCors(options: CorsOptions): RequestHandler;
60
+ /**
61
+ * Alias for safeCors
62
+ * @see safeCors
63
+ */
64
+ export declare const createCors: typeof safeCors;
65
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;IAE1E,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAsD7D;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,iBAAW,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @module @arcis/node/middleware/csrf
3
+ * CSRF (Cross-Site Request Forgery) protection middleware
4
+ *
5
+ * Implements the double-submit cookie pattern:
6
+ * 1. Server sets a CSRF token in a cookie
7
+ * 2. Client must send the same token in a header or form field
8
+ * 3. Middleware rejects requests where cookie token !== header/field token
9
+ *
10
+ * This works because an attacker's cross-origin form submission will include
11
+ * the cookie automatically, but cannot read it (same-origin policy) to set
12
+ * the matching header.
13
+ */
14
+ import type { Request, Response, NextFunction, RequestHandler } from 'express';
15
+ /** CSRF protection configuration */
16
+ export interface CsrfOptions {
17
+ /** Cookie name for the CSRF token. Default: '_csrf' */
18
+ cookieName?: string;
19
+ /** Header name to check for the token. Default: 'x-csrf-token' */
20
+ headerName?: string;
21
+ /** Form field name to check for the token. Default: '_csrf' */
22
+ fieldName?: string;
23
+ /** Token byte length (hex-encoded = 2x chars). Default: 32 */
24
+ tokenLength?: number;
25
+ /** HTTP methods to protect. Default: ['POST', 'PUT', 'PATCH', 'DELETE'] */
26
+ protectedMethods?: string[];
27
+ /** Paths to exclude from CSRF checks (e.g., webhook endpoints) */
28
+ excludePaths?: string[];
29
+ /**
30
+ * Per-request skip function. If it returns true, CSRF check is skipped
31
+ * for that request. Useful for API key auth or signed webhooks.
32
+ *
33
+ * @example
34
+ * skipCsrf: (req) => Boolean(req.headers['x-api-key'])
35
+ */
36
+ skipCsrf?: (req: Request) => boolean;
37
+ /**
38
+ * Use the __Host- cookie prefix for stronger cookie security.
39
+ * When enabled, the browser enforces: Secure=true, no Domain, Path=/.
40
+ * This prevents CSRF cookie theft across subdomains.
41
+ * Default: false
42
+ */
43
+ useHostPrefix?: boolean;
44
+ /** Cookie options */
45
+ cookie?: {
46
+ /** Cookie path. Default: '/' */
47
+ path?: string;
48
+ /** HttpOnly — set false so client JS can read it for headers. Default: false */
49
+ httpOnly?: boolean;
50
+ /** Secure flag (HTTPS only). Default: true in production */
51
+ secure?: boolean;
52
+ /** SameSite attribute. Default: 'Lax' */
53
+ sameSite?: 'Strict' | 'Lax' | 'None';
54
+ /** Cookie domain */
55
+ domain?: string;
56
+ };
57
+ /** Custom error handler when CSRF validation fails */
58
+ onError?: (req: Request, res: Response, next: NextFunction) => void;
59
+ }
60
+ /**
61
+ * Generate a cryptographically random CSRF token.
62
+ *
63
+ * @param length - Byte length (output is hex, so 2x chars). Default: 32
64
+ * @returns Hex-encoded random token
65
+ *
66
+ * @example
67
+ * const token = generateCsrfToken(); // 64 hex chars
68
+ */
69
+ export declare function generateCsrfToken(length?: number): string;
70
+ /**
71
+ * Validate that two CSRF tokens match using constant-time comparison.
72
+ *
73
+ * @param cookieToken - Token from the cookie
74
+ * @param requestToken - Token from the header or form field
75
+ * @returns true if tokens match
76
+ */
77
+ export declare function validateCsrfToken(cookieToken: string, requestToken: string): boolean;
78
+ /**
79
+ * Create CSRF protection middleware using double-submit cookie pattern.
80
+ *
81
+ * For safe methods (GET, HEAD, OPTIONS), sets a CSRF token cookie if not present.
82
+ * For unsafe methods (POST, PUT, PATCH, DELETE), validates the token.
83
+ *
84
+ * @param options - CSRF configuration
85
+ * @returns Express middleware
86
+ *
87
+ * @example
88
+ * // Basic usage
89
+ * app.use(csrfProtection());
90
+ *
91
+ * @example
92
+ * // Exclude webhook paths
93
+ * app.use(csrfProtection({
94
+ * excludePaths: ['/api/webhooks/stripe', '/api/webhooks/github']
95
+ * }));
96
+ *
97
+ * @example
98
+ * // Client-side: read cookie + set header
99
+ * const token = document.cookie.match(/_csrf=([^;]+)/)?.[1];
100
+ * fetch('/api/data', {
101
+ * method: 'POST',
102
+ * headers: { 'X-CSRF-Token': token },
103
+ * credentials: 'same-origin'
104
+ * });
105
+ */
106
+ export declare function csrfProtection(options?: CsrfOptions): RequestHandler;
107
+ /** Alias for csrfProtection */
108
+ export declare const createCsrf: typeof csrfProtection;
109
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/middleware/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACrC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB;IACrB,MAAM,CAAC,EAAE;QACP,gCAAgC;QAChC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,gFAAgF;QAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,4DAA4D;QAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,yCAAyC;QACzC,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QACrC,oBAAoB;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,sDAAsD;IACtD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACrE;AAUD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM,CAE7D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAUpF;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,WAAgB,GAAG,cAAc,CAmFxE;AA6CD,+BAA+B;AAC/B,eAAO,MAAM,UAAU,uBAAiB,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @module @arcis/node/middleware/error-handler
3
+ * Production-safe error handler middleware
4
+ */
5
+ import type { Request, Response, NextFunction } from 'express';
6
+ import type { ErrorHandlerOptions } from '../core/types';
7
+ /**
8
+ * Check if an error message contains sensitive infrastructure details.
9
+ */
10
+ export declare function containsSensitiveInfo(message: string): boolean;
11
+ /**
12
+ * Create Express error handler that hides sensitive details in production.
13
+ *
14
+ * Prevents information leakage by:
15
+ * - Hiding stack traces in production
16
+ * - Hiding error messages unless explicitly exposed
17
+ * - Scrubbing database errors, connection strings, and internal IPs
18
+ *
19
+ * @param options - Error handler configuration (or boolean for isDev)
20
+ * @returns Express error handling middleware
21
+ *
22
+ * @example
23
+ * // Production mode (default) - hides error details
24
+ * app.use(errorHandler());
25
+ *
26
+ * @example
27
+ * // Development mode - shows error details and stack traces
28
+ * app.use(errorHandler({ isDev: true }));
29
+ *
30
+ * @example
31
+ * // With custom logger
32
+ * app.use(errorHandler({
33
+ * isDev: false,
34
+ * logger: arcis.logger()
35
+ * }));
36
+ */
37
+ export declare function errorHandler(options?: ErrorHandlerOptions | boolean): (err: Error, req: Request, res: Response, next: NextFunction) => void;
38
+ /**
39
+ * Alias for errorHandler
40
+ * @see errorHandler
41
+ */
42
+ export declare const createErrorHandler: typeof errorHandler;
43
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,mBAAmB,EAAa,MAAM,eAAe,CAAC;AAyBpE;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAmB,GAAG,OAAe,GAC7C,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CA2DvE;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,qBAAe,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @module @arcis/node/middleware/headers
3
+ * Security headers middleware
4
+ */
5
+ import type { RequestHandler } from 'express';
6
+ import type { HeaderOptions } from '../core/types';
7
+ /**
8
+ * Create Express middleware for security headers.
9
+ * Sets CSP, HSTS, X-Frame-Options, and other security headers.
10
+ *
11
+ * @param options - Header configuration
12
+ * @returns Express middleware
13
+ *
14
+ * @example
15
+ * app.use(createHeaders());
16
+ *
17
+ * @example
18
+ * app.use(createHeaders({
19
+ * frameOptions: 'SAMEORIGIN',
20
+ * contentSecurityPolicy: "default-src 'self'"
21
+ * }));
22
+ */
23
+ export declare function createHeaders(options?: HeaderOptions): RequestHandler;
24
+ /**
25
+ * Alias for createHeaders
26
+ * @see createHeaders
27
+ */
28
+ export declare const securityHeaders: typeof createHeaders;
29
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/middleware/headers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,eAAe,CAAC;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,cAAc,CAwHzE;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,sBAAgB,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @module @arcis/node/middleware/hpp
3
+ * HTTP Parameter Pollution (HPP) protection middleware
4
+ *
5
+ * Normalizes duplicate query and body parameters to their last value,
6
+ * preventing attackers from bypassing validation by repeating parameters.
7
+ *
8
+ * Attack example:
9
+ * GET /search?role=user&role=admin
10
+ * Without HPP: req.query.role = ['user', 'admin']
11
+ * With HPP: req.query.role = 'admin' (last value wins)
12
+ *
13
+ * Originals are preserved in req.queryPolluted / req.bodyPolluted
14
+ * for logging or auditing without blocking the request.
15
+ */
16
+ import type { RequestHandler } from 'express';
17
+ /** HPP protection configuration */
18
+ export interface HppOptions {
19
+ /**
20
+ * Parameters that legitimately accept arrays and should not be normalized.
21
+ * Example: ['tags', 'ids', 'filter']
22
+ */
23
+ whitelist?: string[];
24
+ /** Normalize duplicate query string parameters. Default: true */
25
+ checkQuery?: boolean;
26
+ /** Normalize duplicate body parameters. Default: true */
27
+ checkBody?: boolean;
28
+ }
29
+ /**
30
+ * HTTP Parameter Pollution protection middleware.
31
+ *
32
+ * Normalizes duplicate query/body parameters to a single value (last wins).
33
+ * Whitelisted parameters are allowed to remain as arrays.
34
+ *
35
+ * @param options - HPP configuration
36
+ * @returns Express middleware
37
+ *
38
+ * @example
39
+ * // Basic — normalize all duplicates
40
+ * app.use(hpp());
41
+ *
42
+ * @example
43
+ * // Allow arrays for specific params (e.g., tag filters, IDs)
44
+ * app.use(hpp({ whitelist: ['tags', 'ids'] }));
45
+ *
46
+ * @example
47
+ * // Inspect what was removed (for logging)
48
+ * app.use((req, res, next) => {
49
+ * const polluted = (req as any).queryPolluted;
50
+ * if (Object.keys(polluted).length) logger.warn('HPP detected', polluted);
51
+ * next();
52
+ * });
53
+ */
54
+ export declare function hpp(options?: HppOptions): RequestHandler;
55
+ export declare const createHpp: typeof hpp;
56
+ //# sourceMappingURL=hpp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hpp.d.ts","sourceRoot":"","sources":["../../src/middleware/hpp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,GAAG,CAAC,OAAO,GAAE,UAAe,GAAG,cAAc,CAwD5D;AAED,eAAO,MAAM,SAAS,YAAM,CAAC"}
@@ -1,3 +1,16 @@
1
- export { g as arcis, h as arcisFunction, i as botProtection, j as createCors, k as createCsrf, l as createErrorHandler, m as createHeaders, n as createRateLimiter, o as createSecureCookies, p as createSlidingWindowLimiter, q as createTokenBucketLimiter, r as csrfProtection, h as default, s as detectBot, t as enforceSecureCookie, u as errorHandler, v as generateCsrfToken, w as rateLimit, x as safeCors, y as secureCookieDefaults, z as securityHeaders, A as validateCsrfToken } from '../index-BAhgn9V2.js';
2
- import '../types-BOkx5YJc.js';
3
- import 'express';
1
+ /**
2
+ * @module @arcis/node/middleware
3
+ * All middleware for Arcis
4
+ */
5
+ export { arcis, arcisFunction } from './main';
6
+ export { default } from './main';
7
+ export { createRateLimiter, rateLimit } from './rate-limit';
8
+ export { createSlidingWindowLimiter } from './rate-limit-sliding';
9
+ export { createTokenBucketLimiter } from './rate-limit-token';
10
+ export { createHeaders, securityHeaders } from './headers';
11
+ export { errorHandler, createErrorHandler } from './error-handler';
12
+ export { safeCors, createCors } from './cors';
13
+ export { secureCookieDefaults, createSecureCookies, enforceSecureCookie } from './cookies';
14
+ export { botProtection, detectBot } from './bot-detection';
15
+ export { csrfProtection, createCsrf, generateCsrfToken, validateCsrfToken } from './csrf';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGjC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC"}
@@ -1606,12 +1606,14 @@ function getRequestToken(req, headerName, fieldName) {
1606
1606
  return void 0;
1607
1607
  }
1608
1608
  function csrfProtection(options = {}) {
1609
- const cookieName = options.cookieName ?? DEFAULTS.cookieName;
1609
+ const baseCookieName = options.cookieName ?? DEFAULTS.cookieName;
1610
+ const cookieName = options.useHostPrefix ? `__Host-${baseCookieName}` : baseCookieName;
1610
1611
  const headerName = options.headerName ?? DEFAULTS.headerName;
1611
1612
  const fieldName = options.fieldName ?? DEFAULTS.fieldName;
1612
1613
  const tokenLength = options.tokenLength ?? DEFAULTS.tokenLength;
1613
1614
  const protectedMethods = options.protectedMethods ?? [...DEFAULTS.protectedMethods];
1614
1615
  const excludePaths = options.excludePaths ?? [];
1616
+ const skipCsrf = options.skipCsrf;
1615
1617
  const isProduction = process.env.NODE_ENV === "production";
1616
1618
  const cookieOpts = {
1617
1619
  path: options.cookie?.path ?? "/",
@@ -1631,6 +1633,9 @@ function csrfProtection(options = {}) {
1631
1633
  const protectedSet = new Set(protectedMethods.map((m) => m.toUpperCase()));
1632
1634
  return (req, res, next) => {
1633
1635
  const method = req.method.toUpperCase();
1636
+ if (skipCsrf && skipCsrf(req)) {
1637
+ return next();
1638
+ }
1634
1639
  const requestPath = req.path || req.url;
1635
1640
  if (excludePaths.some((p) => requestPath === p || requestPath.startsWith(p + "/"))) {
1636
1641
  return next();