mates-fullstack 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +311 -0
  2. package/dist/arctic-auth.d.ts +101 -0
  3. package/dist/arctic-auth.d.ts.map +1 -0
  4. package/dist/arctic-auth.js +538 -0
  5. package/dist/arctic-auth.js.map +1 -0
  6. package/dist/asset-manifest.d.ts +14 -0
  7. package/dist/asset-manifest.d.ts.map +1 -0
  8. package/dist/asset-manifest.js +102 -0
  9. package/dist/asset-manifest.js.map +1 -0
  10. package/dist/browser.d.ts +18 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +25 -0
  13. package/dist/browser.js.map +1 -0
  14. package/dist/build-esbuild.d.ts +29 -0
  15. package/dist/build-esbuild.d.ts.map +1 -0
  16. package/dist/build-esbuild.js +699 -0
  17. package/dist/build-esbuild.js.map +1 -0
  18. package/dist/build-prod.d.ts +126 -0
  19. package/dist/build-prod.d.ts.map +1 -0
  20. package/dist/build-prod.js +1014 -0
  21. package/dist/build-prod.js.map +1 -0
  22. package/dist/cli-new.d.ts +14 -0
  23. package/dist/cli-new.d.ts.map +1 -0
  24. package/dist/cli-new.js +637 -0
  25. package/dist/cli-new.js.map +1 -0
  26. package/dist/client.d.ts +43 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +130 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/cors.d.ts +16 -0
  31. package/dist/cors.d.ts.map +1 -0
  32. package/dist/cors.js +60 -0
  33. package/dist/cors.js.map +1 -0
  34. package/dist/ctx.d.ts +78 -0
  35. package/dist/ctx.d.ts.map +1 -0
  36. package/dist/ctx.js +280 -0
  37. package/dist/ctx.js.map +1 -0
  38. package/dist/dev-watcher.d.ts +23 -0
  39. package/dist/dev-watcher.d.ts.map +1 -0
  40. package/dist/dev-watcher.js +136 -0
  41. package/dist/dev-watcher.js.map +1 -0
  42. package/dist/docs-generator.d.ts +69 -0
  43. package/dist/docs-generator.d.ts.map +1 -0
  44. package/dist/docs-generator.js +557 -0
  45. package/dist/docs-generator.js.map +1 -0
  46. package/dist/docs-page.d.ts +20 -0
  47. package/dist/docs-page.d.ts.map +1 -0
  48. package/dist/docs-page.js +1152 -0
  49. package/dist/docs-page.js.map +1 -0
  50. package/dist/download.d.ts +78 -0
  51. package/dist/download.d.ts.map +1 -0
  52. package/dist/download.js +202 -0
  53. package/dist/download.js.map +1 -0
  54. package/dist/env-loader.d.ts +76 -0
  55. package/dist/env-loader.d.ts.map +1 -0
  56. package/dist/env-loader.js +213 -0
  57. package/dist/env-loader.js.map +1 -0
  58. package/dist/errors.d.ts +146 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +386 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/head.d.ts +31 -0
  63. package/dist/head.d.ts.map +1 -0
  64. package/dist/head.js +245 -0
  65. package/dist/head.js.map +1 -0
  66. package/dist/index.d.ts +30 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +30 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/internal-prefixes.d.ts +16 -0
  71. package/dist/internal-prefixes.d.ts.map +1 -0
  72. package/dist/internal-prefixes.js +16 -0
  73. package/dist/internal-prefixes.js.map +1 -0
  74. package/dist/internal.d.ts +25 -0
  75. package/dist/internal.d.ts.map +1 -0
  76. package/dist/internal.js +25 -0
  77. package/dist/internal.js.map +1 -0
  78. package/dist/jwt.d.ts +166 -0
  79. package/dist/jwt.d.ts.map +1 -0
  80. package/dist/jwt.js +261 -0
  81. package/dist/jwt.js.map +1 -0
  82. package/dist/log.d.ts +44 -0
  83. package/dist/log.d.ts.map +1 -0
  84. package/dist/log.js +66 -0
  85. package/dist/log.js.map +1 -0
  86. package/dist/logger.d.ts +76 -0
  87. package/dist/logger.d.ts.map +1 -0
  88. package/dist/logger.js +138 -0
  89. package/dist/logger.js.map +1 -0
  90. package/dist/main-runner.d.ts +59 -0
  91. package/dist/main-runner.d.ts.map +1 -0
  92. package/dist/main-runner.js +157 -0
  93. package/dist/main-runner.js.map +1 -0
  94. package/dist/mates-auth.d.ts +82 -0
  95. package/dist/mates-auth.d.ts.map +1 -0
  96. package/dist/mates-auth.js +323 -0
  97. package/dist/mates-auth.js.map +1 -0
  98. package/dist/middleware.d.ts +30 -0
  99. package/dist/middleware.d.ts.map +1 -0
  100. package/dist/middleware.js +67 -0
  101. package/dist/middleware.js.map +1 -0
  102. package/dist/project-resolver.d.ts +102 -0
  103. package/dist/project-resolver.d.ts.map +1 -0
  104. package/dist/project-resolver.js +271 -0
  105. package/dist/project-resolver.js.map +1 -0
  106. package/dist/rate-limit.d.ts +37 -0
  107. package/dist/rate-limit.d.ts.map +1 -0
  108. package/dist/rate-limit.js +109 -0
  109. package/dist/rate-limit.js.map +1 -0
  110. package/dist/redirect.d.ts +84 -0
  111. package/dist/redirect.d.ts.map +1 -0
  112. package/dist/redirect.js +105 -0
  113. package/dist/redirect.js.map +1 -0
  114. package/dist/renderer.d.ts +91 -0
  115. package/dist/renderer.d.ts.map +1 -0
  116. package/dist/renderer.js +630 -0
  117. package/dist/renderer.js.map +1 -0
  118. package/dist/request-logger.d.ts +12 -0
  119. package/dist/request-logger.d.ts.map +1 -0
  120. package/dist/request-logger.js +55 -0
  121. package/dist/request-logger.js.map +1 -0
  122. package/dist/rest.d.ts +25 -0
  123. package/dist/rest.d.ts.map +1 -0
  124. package/dist/rest.js +93 -0
  125. package/dist/rest.js.map +1 -0
  126. package/dist/router.d.ts +71 -0
  127. package/dist/router.d.ts.map +1 -0
  128. package/dist/router.js +222 -0
  129. package/dist/router.js.map +1 -0
  130. package/dist/rpc-registry.d.ts +84 -0
  131. package/dist/rpc-registry.d.ts.map +1 -0
  132. package/dist/rpc-registry.js +271 -0
  133. package/dist/rpc-registry.js.map +1 -0
  134. package/dist/rpc-runner.d.ts +82 -0
  135. package/dist/rpc-runner.d.ts.map +1 -0
  136. package/dist/rpc-runner.js +564 -0
  137. package/dist/rpc-runner.js.map +1 -0
  138. package/dist/sanitize.d.ts +61 -0
  139. package/dist/sanitize.d.ts.map +1 -0
  140. package/dist/sanitize.js +193 -0
  141. package/dist/sanitize.js.map +1 -0
  142. package/dist/security-headers.d.ts +114 -0
  143. package/dist/security-headers.d.ts.map +1 -0
  144. package/dist/security-headers.js +121 -0
  145. package/dist/security-headers.js.map +1 -0
  146. package/dist/server-fn.d.ts +323 -0
  147. package/dist/server-fn.d.ts.map +1 -0
  148. package/dist/server-fn.js +373 -0
  149. package/dist/server-fn.js.map +1 -0
  150. package/dist/server-public.d.ts +13 -0
  151. package/dist/server-public.d.ts.map +1 -0
  152. package/dist/server-public.js +12 -0
  153. package/dist/server-public.js.map +1 -0
  154. package/dist/server-timeout.d.ts +38 -0
  155. package/dist/server-timeout.d.ts.map +1 -0
  156. package/dist/server-timeout.js +46 -0
  157. package/dist/server-timeout.js.map +1 -0
  158. package/dist/server.d.ts +100 -0
  159. package/dist/server.d.ts.map +1 -0
  160. package/dist/server.js +1218 -0
  161. package/dist/server.js.map +1 -0
  162. package/dist/socket-router.d.ts +153 -0
  163. package/dist/socket-router.d.ts.map +1 -0
  164. package/dist/socket-router.js +612 -0
  165. package/dist/socket-router.js.map +1 -0
  166. package/dist/sso.d.ts +90 -0
  167. package/dist/sso.d.ts.map +1 -0
  168. package/dist/sso.js +261 -0
  169. package/dist/sso.js.map +1 -0
  170. package/dist/ssr-context.d.ts +49 -0
  171. package/dist/ssr-context.d.ts.map +1 -0
  172. package/dist/ssr-context.js +85 -0
  173. package/dist/ssr-context.js.map +1 -0
  174. package/dist/ssr-globals.d.ts +32 -0
  175. package/dist/ssr-globals.d.ts.map +1 -0
  176. package/dist/ssr-globals.js +1010 -0
  177. package/dist/ssr-globals.js.map +1 -0
  178. package/dist/ssr-template.d.ts +73 -0
  179. package/dist/ssr-template.d.ts.map +1 -0
  180. package/dist/ssr-template.js +507 -0
  181. package/dist/ssr-template.js.map +1 -0
  182. package/dist/stack-mapper.d.ts +25 -0
  183. package/dist/stack-mapper.d.ts.map +1 -0
  184. package/dist/stack-mapper.js +139 -0
  185. package/dist/stack-mapper.js.map +1 -0
  186. package/dist/stream.d.ts +89 -0
  187. package/dist/stream.d.ts.map +1 -0
  188. package/dist/stream.js +299 -0
  189. package/dist/stream.js.map +1 -0
  190. package/dist/upload.d.ts +69 -0
  191. package/dist/upload.d.ts.map +1 -0
  192. package/dist/upload.js +110 -0
  193. package/dist/upload.js.map +1 -0
  194. package/dist/validate.d.ts +58 -0
  195. package/dist/validate.d.ts.map +1 -0
  196. package/dist/validate.js +89 -0
  197. package/dist/validate.js.map +1 -0
  198. package/dist/verify-package.d.ts +3 -0
  199. package/dist/verify-package.d.ts.map +1 -0
  200. package/dist/verify-package.js +128 -0
  201. package/dist/verify-package.js.map +1 -0
  202. package/package.json +79 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * mates-ssr — sanitize.ts
3
+ *
4
+ * Automatic XSS sanitization of parsed JSON request bodies.
5
+ *
6
+ * Runs after JSON.parse on every API route body and serverFn arg list.
7
+ * Walks the object tree and cleans every string value.
8
+ *
9
+ * No external dependencies — pure string operations.
10
+ *
11
+ * Rules:
12
+ * - Only string values are touched
13
+ * - Numbers, booleans, null, undefined pass through unchanged
14
+ * - Objects and arrays are recursed into
15
+ * - Fields in the skip list are never touched
16
+ * - Circular references are safely handled
17
+ */
18
+ // ─── Built-in fields that must never be sanitized ─────────────────────────────
19
+ // Passwords must preserve all characters.
20
+ // Tokens/secrets are cryptographic values.
21
+ // Content/html/markdown fields contain intentional markup.
22
+ const BUILTIN_SKIP = new Set([
23
+ "password",
24
+ "passwordConfirm",
25
+ "confirmPassword",
26
+ "currentPassword",
27
+ "newPassword",
28
+ "oldPassword",
29
+ "token",
30
+ "secret",
31
+ "apiKey",
32
+ "api_key",
33
+ "privateKey",
34
+ "private_key",
35
+ "accessToken",
36
+ "access_token",
37
+ "refreshToken",
38
+ "refresh_token",
39
+ "content",
40
+ "body",
41
+ "html",
42
+ "markdown",
43
+ "rawContent",
44
+ "raw_content",
45
+ "template",
46
+ "source",
47
+ ]);
48
+ // ─── HTML detection ───────────────────────────────────────────────────────────
49
+ // Matches opening and closing HTML tags including self-closing
50
+ // e.g. <script>, </div>, <img src="x" onerror="xss">, <!-- comment -->
51
+ const HTML_TAG_REGEX = /<\/?[a-zA-Z][^>]*>|<!--|-->/g;
52
+ // Strict check — does the string contain any HTML tags at all?
53
+ function containsHtml(value) {
54
+ // Reset lastIndex since we reuse a stateful regex
55
+ HTML_TAG_REGEX.lastIndex = 0;
56
+ return HTML_TAG_REGEX.test(value);
57
+ }
58
+ // ─── Sanitizers ───────────────────────────────────────────────────────────────
59
+ /**
60
+ * Strip all HTML tags from a string.
61
+ * "<script>alert(1)</script>hello" → "hello"
62
+ * "<b>bold</b> and <i>italic</i>" → "bold and italic"
63
+ */
64
+ function stripHtml(value) {
65
+ return value.replace(/<\/?[a-zA-Z][^>]*>|<!--|-->/g, "");
66
+ }
67
+ /**
68
+ * Escape HTML special characters.
69
+ * Only escapes the five characters that are dangerous in HTML context.
70
+ * Does NOT mangle normal text — "O'Brien" stays "O&#39;Brien" when escaped,
71
+ * which round-trips correctly. Use this if you want to preserve the content
72
+ * but neutralize it for HTML output.
73
+ */
74
+ function escapeHtml(value) {
75
+ return value
76
+ .replace(/&/g, "&amp;")
77
+ .replace(/</g, "&lt;")
78
+ .replace(/>/g, "&gt;")
79
+ .replace(/"/g, "&quot;")
80
+ .replace(/'/g, "&#39;");
81
+ }
82
+ // ─── Core sanitizer ───────────────────────────────────────────────────────────
83
+ export class SanitizeError extends Error {
84
+ status = 400;
85
+ code = "XSS_DETECTED";
86
+ field;
87
+ constructor(field) {
88
+ super(`HTML content is not allowed in field: "${field}"`);
89
+ this.name = "SanitizeError";
90
+ this.field = field;
91
+ }
92
+ }
93
+ /**
94
+ * Sanitize a single string value.
95
+ * Returns the cleaned string or throws SanitizeError in "reject" mode.
96
+ */
97
+ export function sanitizeString(value, fieldName, mode) {
98
+ switch (mode) {
99
+ case "strip":
100
+ return stripHtml(value);
101
+ case "escape":
102
+ return escapeHtml(value);
103
+ case "reject":
104
+ if (containsHtml(value))
105
+ throw new SanitizeError(fieldName);
106
+ return value;
107
+ }
108
+ }
109
+ /**
110
+ * Recursively sanitize all string values in an object or array.
111
+ *
112
+ * @param input The parsed JSON value (object, array, primitive)
113
+ * @param config Sanitize configuration
114
+ * @param fieldName Current field path (for error messages)
115
+ * @param seen WeakSet to detect circular references
116
+ * @returns The sanitized value (mutates strings in place for objects)
117
+ */
118
+ export function sanitizeBody(input, config, fieldName = "body", seen = new WeakSet()) {
119
+ if (!config.enabled)
120
+ return input;
121
+ // Primitives other than string — pass through unchanged
122
+ if (input === null || input === undefined)
123
+ return input;
124
+ if (typeof input === "number")
125
+ return input;
126
+ if (typeof input === "boolean")
127
+ return input;
128
+ // String — sanitize it
129
+ if (typeof input === "string") {
130
+ return sanitizeString(input, fieldName, config.mode);
131
+ }
132
+ // Array — recurse into each element
133
+ if (Array.isArray(input)) {
134
+ if (seen.has(input))
135
+ return input;
136
+ seen.add(input);
137
+ return input.map((item, i) => sanitizeBody(item, config, `${fieldName}[${i}]`, seen));
138
+ }
139
+ // Object — recurse into each value, respecting skip list
140
+ if (typeof input === "object") {
141
+ if (seen.has(input))
142
+ return input;
143
+ seen.add(input);
144
+ const skipSet = new Set([...BUILTIN_SKIP, ...config.skip]);
145
+ const result = {};
146
+ for (const [key, value] of Object.entries(input)) {
147
+ // Skip fields in the skip list — return value as-is
148
+ if (skipSet.has(key)) {
149
+ result[key] = value;
150
+ }
151
+ else {
152
+ result[key] = sanitizeBody(value, config, fieldName === "body" ? key : `${fieldName}.${key}`, seen);
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ // Anything else — pass through
158
+ return input;
159
+ }
160
+ /**
161
+ * Sanitize a WebSocket message.
162
+ * Parses JSON if the message is a string, sanitizes all string fields,
163
+ * and returns the cleaned object (or the original string if not JSON).
164
+ *
165
+ * @param msg Raw WebSocket message (string or Buffer)
166
+ * @param config Sanitize config
167
+ * @returns { parsed: any, raw: string } — parsed is the sanitized object,
168
+ * raw is the original string for pass-through if needed
169
+ */
170
+ export function sanitizeWsMessage(msg, config) {
171
+ const raw = typeof msg === "string" ? msg : msg.toString("utf-8");
172
+ if (!config.enabled)
173
+ return { parsed: raw, raw, isJson: false };
174
+ // Try to parse as JSON
175
+ let parsed;
176
+ let isJson = false;
177
+ try {
178
+ parsed = JSON.parse(raw);
179
+ isJson = true;
180
+ }
181
+ catch {
182
+ // Not JSON — treat as plain string and sanitize it directly
183
+ return {
184
+ parsed: sanitizeString(raw, "message", config.mode),
185
+ raw,
186
+ isJson: false,
187
+ };
188
+ }
189
+ // JSON parsed — sanitize all string values
190
+ const sanitized = sanitizeBody(parsed, config, "message");
191
+ return { parsed: sanitized, raw, isJson: true };
192
+ }
193
+ //# sourceMappingURL=sanitize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * mates-fullstack — security-headers.ts
3
+ *
4
+ * Sets all standard security response headers in one call.
5
+ * Every header is on by default and individually overridable or disableable.
6
+ *
7
+ * Covers the full helmet header set plus Permissions-Policy.
8
+ */
9
+ export interface SecurityHeadersOptions {
10
+ /**
11
+ * Strict-Transport-Security.
12
+ * Default in production: "max-age=31536000; includeSubDomains".
13
+ * Disabled in development by default.
14
+ * Set to false to always omit.
15
+ */
16
+ hsts?: string | false;
17
+ /**
18
+ * X-Frame-Options — controls whether the page can be embedded in an iframe.
19
+ * Default: "SAMEORIGIN". Set to false to omit.
20
+ */
21
+ xFrameOptions?: "DENY" | "SAMEORIGIN" | false;
22
+ /**
23
+ * Cross-Origin-Opener-Policy — isolates the browsing context group.
24
+ * Default: "same-origin". Set to false to omit.
25
+ */
26
+ crossOriginOpenerPolicy?: string | false;
27
+ /**
28
+ * Cross-Origin-Embedder-Policy — requires resources to opt in to being loaded.
29
+ * Needed for SharedArrayBuffer / high-res timers.
30
+ * Default: "require-corp". Set to false or "unsafe-none" to disable.
31
+ *
32
+ * Note: "require-corp" will block third-party resources (CDN fonts, images, etc.)
33
+ * that do not send CORP or CORS headers. Set to false if your app loads
34
+ * resources from external origins without CORS headers.
35
+ */
36
+ crossOriginEmbedderPolicy?: string | false;
37
+ /**
38
+ * Cross-Origin-Resource-Policy — prevents other origins from loading your resources.
39
+ * Default: "same-origin". Set to false to omit.
40
+ */
41
+ crossOriginResourcePolicy?: string | false;
42
+ /**
43
+ * X-Content-Type-Options: nosniff — prevents MIME-type sniffing.
44
+ * Default: true.
45
+ */
46
+ xContentTypeOptions?: boolean;
47
+ /**
48
+ * X-XSS-Protection: 0 — explicitly disables the legacy XSS filter.
49
+ * Disabling it is the modern recommendation (the filter can introduce vulnerabilities).
50
+ * Default: true (sends "0").
51
+ */
52
+ xXssProtection?: boolean;
53
+ /**
54
+ * Referrer-Policy.
55
+ * Default: "no-referrer". Set to false to omit.
56
+ */
57
+ referrerPolicy?: string | false;
58
+ /**
59
+ * X-DNS-Prefetch-Control — disables browser DNS prefetching.
60
+ * Default: "off". Set to false to omit.
61
+ */
62
+ xDnsPrefetchControl?: "on" | "off" | false;
63
+ /**
64
+ * X-Permitted-Cross-Domain-Policies — disallows Adobe Flash/Acrobat cross-domain requests.
65
+ * Default: "none". Set to false to omit.
66
+ */
67
+ xPermittedCrossDomainPolicies?: string | false;
68
+ /**
69
+ * X-Download-Options: noopen — prevents IE from executing downloads in site context.
70
+ * Default: true. Set to false to omit.
71
+ */
72
+ xDownloadOptions?: boolean;
73
+ /**
74
+ * Origin-Agent-Cluster: ?1 — hints the browser to isolate this origin in its own agent cluster.
75
+ * Default: true. Set to false to omit.
76
+ */
77
+ originAgentCluster?: boolean;
78
+ /**
79
+ * Content-Security-Policy.
80
+ * Not set by default — CSP is highly application-specific.
81
+ * Set to false to explicitly omit.
82
+ */
83
+ contentSecurityPolicy?: string | false;
84
+ /**
85
+ * Permissions-Policy (formerly Feature-Policy).
86
+ * Not set by default — policy is application-specific.
87
+ * Set to false to explicitly omit.
88
+ */
89
+ permissionsPolicy?: string | false;
90
+ }
91
+ /**
92
+ * Register all standard security headers on every response.
93
+ *
94
+ * Call once at module level in server/main.ts.
95
+ * Every header has a safe default — pass options to override or disable individual headers.
96
+ *
97
+ * @example
98
+ * // All defaults
99
+ * useSecurityHeaders();
100
+ *
101
+ * // Custom CSP + preload HSTS
102
+ * useSecurityHeaders({
103
+ * contentSecurityPolicy: "default-src 'self'",
104
+ * hsts: "max-age=63072000; includeSubDomains; preload",
105
+ * });
106
+ *
107
+ * // Disable COEP for apps that load cross-origin resources without CORS headers
108
+ * useSecurityHeaders({ crossOriginEmbedderPolicy: false });
109
+ *
110
+ * // Disable a header entirely
111
+ * useSecurityHeaders({ xFrameOptions: false });
112
+ */
113
+ export declare function useSecurityHeaders(options?: SecurityHeadersOptions): void;
114
+ //# sourceMappingURL=security-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,sBAAsB;IAGrC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAItB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,KAAK,CAAC;IAE9C;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAEzC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAE3C;;;OAGG;IACH,yBAAyB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAI3C;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAIzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAEhC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;IAI3C;;;OAGG;IACH,6BAA6B,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAE/C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAI7B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAEvC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,sBAA2B,GAAG,IAAI,CA+G7E"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * mates-fullstack — security-headers.ts
3
+ *
4
+ * Sets all standard security response headers in one call.
5
+ * Every header is on by default and individually overridable or disableable.
6
+ *
7
+ * Covers the full helmet header set plus Permissions-Policy.
8
+ */
9
+ import { onRequest } from "./middleware.js";
10
+ /**
11
+ * Register all standard security headers on every response.
12
+ *
13
+ * Call once at module level in server/main.ts.
14
+ * Every header has a safe default — pass options to override or disable individual headers.
15
+ *
16
+ * @example
17
+ * // All defaults
18
+ * useSecurityHeaders();
19
+ *
20
+ * // Custom CSP + preload HSTS
21
+ * useSecurityHeaders({
22
+ * contentSecurityPolicy: "default-src 'self'",
23
+ * hsts: "max-age=63072000; includeSubDomains; preload",
24
+ * });
25
+ *
26
+ * // Disable COEP for apps that load cross-origin resources without CORS headers
27
+ * useSecurityHeaders({ crossOriginEmbedderPolicy: false });
28
+ *
29
+ * // Disable a header entirely
30
+ * useSecurityHeaders({ xFrameOptions: false });
31
+ */
32
+ export function useSecurityHeaders(options = {}) {
33
+ const isProd = process.env.NODE_ENV === "production";
34
+ const resolved = {};
35
+ // X-Content-Type-Options
36
+ if (options.xContentTypeOptions !== false) {
37
+ resolved["x-content-type-options"] = "nosniff";
38
+ }
39
+ // X-Frame-Options
40
+ const xFrame = options.xFrameOptions !== undefined ? options.xFrameOptions : "SAMEORIGIN";
41
+ if (xFrame !== false) {
42
+ resolved["x-frame-options"] = xFrame;
43
+ }
44
+ // X-XSS-Protection: 0 (disable the legacy filter)
45
+ if (options.xXssProtection !== false) {
46
+ resolved["x-xss-protection"] = "0";
47
+ }
48
+ // X-DNS-Prefetch-Control
49
+ const dns = options.xDnsPrefetchControl !== undefined
50
+ ? options.xDnsPrefetchControl
51
+ : "off";
52
+ if (dns !== false) {
53
+ resolved["x-dns-prefetch-control"] = dns;
54
+ }
55
+ // X-Download-Options
56
+ if (options.xDownloadOptions !== false) {
57
+ resolved["x-download-options"] = "noopen";
58
+ }
59
+ // X-Permitted-Cross-Domain-Policies
60
+ const xPdp = options.xPermittedCrossDomainPolicies !== undefined
61
+ ? options.xPermittedCrossDomainPolicies
62
+ : "none";
63
+ if (xPdp !== false) {
64
+ resolved["x-permitted-cross-domain-policies"] = xPdp;
65
+ }
66
+ // Referrer-Policy
67
+ const referrer = options.referrerPolicy !== undefined
68
+ ? options.referrerPolicy
69
+ : "no-referrer";
70
+ if (referrer !== false) {
71
+ resolved["referrer-policy"] = referrer;
72
+ }
73
+ // Strict-Transport-Security — production only by default
74
+ const hsts = options.hsts !== undefined
75
+ ? options.hsts
76
+ : isProd
77
+ ? "max-age=31536000; includeSubDomains"
78
+ : false;
79
+ if (hsts !== false) {
80
+ resolved["strict-transport-security"] = hsts;
81
+ }
82
+ // Origin-Agent-Cluster
83
+ if (options.originAgentCluster !== false) {
84
+ resolved["origin-agent-cluster"] = "?1";
85
+ }
86
+ // Cross-Origin-Opener-Policy
87
+ const coop = options.crossOriginOpenerPolicy !== undefined
88
+ ? options.crossOriginOpenerPolicy
89
+ : "same-origin";
90
+ if (coop !== false) {
91
+ resolved["cross-origin-opener-policy"] = coop;
92
+ }
93
+ // Cross-Origin-Embedder-Policy
94
+ const coep = options.crossOriginEmbedderPolicy !== undefined
95
+ ? options.crossOriginEmbedderPolicy
96
+ : "require-corp";
97
+ if (coep !== false) {
98
+ resolved["cross-origin-embedder-policy"] = coep;
99
+ }
100
+ // Cross-Origin-Resource-Policy
101
+ const corp = options.crossOriginResourcePolicy !== undefined
102
+ ? options.crossOriginResourcePolicy
103
+ : "same-origin";
104
+ if (corp !== false) {
105
+ resolved["cross-origin-resource-policy"] = corp;
106
+ }
107
+ // Content-Security-Policy (opt-in — too app-specific for a default)
108
+ if (options.contentSecurityPolicy) {
109
+ resolved["content-security-policy"] = options.contentSecurityPolicy;
110
+ }
111
+ // Permissions-Policy (opt-in — too app-specific for a default)
112
+ if (options.permissionsPolicy) {
113
+ resolved["permissions-policy"] = options.permissionsPolicy;
114
+ }
115
+ onRequest((c) => {
116
+ for (const [key, value] of Object.entries(resolved)) {
117
+ c.resHeaders[key] = value;
118
+ }
119
+ });
120
+ }
121
+ //# sourceMappingURL=security-headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"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"}