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,564 @@
1
+ /**
2
+ * mates-fullstack — rpc-runner.ts
3
+ *
4
+ * Executes a registered RPC function for an incoming HTTP request.
5
+ *
6
+ * Execution pipeline per request:
7
+ * 1. Read + size-check request body
8
+ * 2. Parse payload (JSON or multipart/form-data)
9
+ * 3. Create Context from request headers
10
+ * 4. Run onRequest hooks (registered in server/main.ts)
11
+ * - throws → error response sent, onResponse SKIPPED
12
+ * - returns Response → that response sent, onResponse RUNS
13
+ * - returns nothing → continue
14
+ * 5. Run entry.fn(payload, ctx)
15
+ * - throws → error response sent, onResponse SKIPPED
16
+ * - returns data → onResponse hooks run, then response sent
17
+ * 6. Detect return type → route to correct response writer:
18
+ * - StreamResponse → SSE
19
+ * - Download → binary attachment
20
+ * - void/null/undefined → {} 200
21
+ * - anything else → JSON 200
22
+ * 7. Run onResponse hooks (with data + ctx)
23
+ * 8. Apply ctx.resHeaders to the response
24
+ *
25
+ * Error handling:
26
+ * - Redirect throw → 302 JSON { __type: "Redirect", url, status }
27
+ * - ServerError throw → 4xx/5xx JSON { __type, message, status, code, ...}
28
+ * - Plain Error throw → 500, message hidden in production
29
+ * - Unknown throw → 500, "Internal Server Error"
30
+ *
31
+ * Body limits:
32
+ * - JSON: 1MB default (MAX_JSON_BYTES)
33
+ * - Multipart: 10MB default (MAX_UPLOAD_BYTES)
34
+ */
35
+ import { createContext, applyResHeaders } from "./ctx.js";
36
+ import { serializeError } from "./errors.js";
37
+ import { isRedirect, serializeRedirect } from "./redirect.js";
38
+ import { isStreamResponse } from "./stream.js";
39
+ import { isDownload, writeDownload } from "./download.js";
40
+ import { runResponseHooks, runBeforeRPCHooks, runAfterRPCHooks, } from "./middleware.js";
41
+ const _config = {
42
+ maxJsonBytes: 1 * 1024 * 1024,
43
+ maxJsonDepth: 50,
44
+ maxArrayLength: 10000,
45
+ maxStringLength: 100000,
46
+ maxUploadBytes: 10 * 1024 * 1024,
47
+ maxMultipartParts: 200,
48
+ };
49
+ /**
50
+ * Configure RPC runner limits. Call once at startup.
51
+ * All values are optional — only provided values override the defaults.
52
+ */
53
+ export function configureRpcRunner(config) {
54
+ if (config.maxJsonBytes !== undefined)
55
+ _config.maxJsonBytes = config.maxJsonBytes;
56
+ if (config.maxJsonDepth !== undefined)
57
+ _config.maxJsonDepth = config.maxJsonDepth;
58
+ if (config.maxArrayLength !== undefined)
59
+ _config.maxArrayLength = config.maxArrayLength;
60
+ if (config.maxStringLength !== undefined)
61
+ _config.maxStringLength = config.maxStringLength;
62
+ if (config.maxUploadBytes !== undefined)
63
+ _config.maxUploadBytes = config.maxUploadBytes;
64
+ if (config.maxMultipartParts !== undefined)
65
+ _config.maxMultipartParts = config.maxMultipartParts;
66
+ }
67
+ /**
68
+ * Recursively validate a parsed JSON payload for safety limits.
69
+ * Checks depth, array size, and string lengths.
70
+ */
71
+ function _validateJsonPayload(value, depth) {
72
+ if (depth > _config.maxJsonDepth) {
73
+ const err = new Error(`JSON payload exceeds maximum depth of ${_config.maxJsonDepth}.`);
74
+ err.status = 400;
75
+ throw err;
76
+ }
77
+ if (typeof value === "string" && value.length > _config.maxStringLength) {
78
+ const err = new Error(`JSON string exceeds maximum length of ${_config.maxStringLength}.`);
79
+ err.status = 413;
80
+ throw err;
81
+ }
82
+ if (Array.isArray(value)) {
83
+ if (value.length > _config.maxArrayLength) {
84
+ const err = new Error(`JSON array exceeds maximum length of ${_config.maxArrayLength}.`);
85
+ err.status = 413;
86
+ throw err;
87
+ }
88
+ for (const item of value) {
89
+ _validateJsonPayload(item, depth + 1);
90
+ }
91
+ }
92
+ else if (typeof value === "object" && value !== null) {
93
+ for (const key of Object.keys(value)) {
94
+ _validateJsonPayload(key, depth + 1);
95
+ _validateJsonPayload(value[key], depth + 1);
96
+ }
97
+ }
98
+ }
99
+ /** Request timeout in milliseconds: 30 seconds */
100
+ export const DEFAULT_TIMEOUT_MS = 30000;
101
+ // ─── Runner ───────────────────────────────────────────────────────────────────
102
+ /**
103
+ * Handle a single RPC request end-to-end.
104
+ * Never throws under any circumstances.
105
+ * All errors — including unexpected framework bugs — produce a JSON error response.
106
+ */
107
+ export async function runRpcRequest(req, res, entry, dev, timeoutMs = DEFAULT_TIMEOUT_MS,
108
+ /** Pre-populated ctx from the outer request handler. When supplied, auth
109
+ * and other middleware state already applied via onRequest are shared. */
110
+ sharedCtx) {
111
+ // Create an AbortController to cancel streams if the client disconnects
112
+ // or if the request times out
113
+ const controller = new AbortController();
114
+ const { signal } = controller;
115
+ // Use the pre-populated Context from the outer request handler if provided
116
+ // (preserves auth, state, and headers set by onRequest middleware),
117
+ // otherwise create a fresh ctx from the raw Node.js request.
118
+ const ctx = sharedCtx ?? createContext(req);
119
+ req.on("close", () => {
120
+ if (!res.writableEnded)
121
+ controller.abort();
122
+ });
123
+ req.on("error", () => controller.abort());
124
+ const timeoutId = setTimeout(() => {
125
+ if (!res.writableEnded) {
126
+ controller.abort();
127
+ const serialized = {
128
+ __type: "AppError",
129
+ message: "Request timeout",
130
+ status: 504,
131
+ code: "TIMEOUT",
132
+ };
133
+ ctx.resStatus = 504;
134
+ void runResponseHooks(ctx);
135
+ _writeErrorResponse(res, serialized, 504);
136
+ }
137
+ }, timeoutMs);
138
+ try {
139
+ await _execute(req, res, entry, dev, signal, ctx);
140
+ }
141
+ catch (err) {
142
+ // Absolute last resort — _execute itself has bugs or threw unexpectedly
143
+ if (!res.headersSent) {
144
+ const serialized = serializeError(err, dev);
145
+ ctx.resStatus = serialized.status;
146
+ await runResponseHooks(ctx);
147
+ _writeErrorResponse(res, serialized, serialized.status);
148
+ }
149
+ }
150
+ finally {
151
+ clearTimeout(timeoutId);
152
+ }
153
+ }
154
+ // ─── Execution ────────────────────────────────────────────────────────────────
155
+ async function _execute(req, res, entry, dev, signal, ctx) {
156
+ // ── 1. Parse payload ───────────────────────────────────────────────────────
157
+ let payload;
158
+ try {
159
+ payload = await _parseBody(req);
160
+ }
161
+ catch (err) {
162
+ if (res.headersSent)
163
+ return;
164
+ const status = err.status ?? 400;
165
+ const serialized = {
166
+ __type: "AppError",
167
+ message: err.message ?? "Bad request",
168
+ status,
169
+ code: "BAD_REQUEST",
170
+ };
171
+ ctx.resStatus = status;
172
+ await runResponseHooks(ctx);
173
+ _writeErrorResponse(res, serialized, status);
174
+ return;
175
+ }
176
+ // ── 2. Run the server function ─────────────────────────────────────────────
177
+ // RPC functions receive the request payload as the first argument and
178
+ // the framework Context (with auth, cookies, etc.) as the second argument.
179
+ try {
180
+ const mergedPayload = payload && typeof payload === "object" && !Array.isArray(payload)
181
+ ? payload
182
+ : {};
183
+ // Run onBeforeRPC hooks as a data pipeline — each hook can mutate the
184
+ // payload before it reaches the RPC function.
185
+ const moduleId = entry.url.replace(/^\/api\//, "").replace(/\/[^/]+$/, "");
186
+ const rpcPayload = await runBeforeRPCHooks(mergedPayload, ctx);
187
+ const startTime = performance.now();
188
+ const raw = await entry.fn(rpcPayload, ctx);
189
+ const duration = performance.now() - startTime;
190
+ // Run onAfterRPC hooks as a result pipeline — each hook can mutate the
191
+ // return value before it is sent to the client.
192
+ const result = await runAfterRPCHooks(raw, ctx, {
193
+ moduleId,
194
+ fnName: entry.fnName,
195
+ duration,
196
+ });
197
+ if (res.headersSent)
198
+ return;
199
+ // Detect special response types — before the generic JSON path
200
+ if (isRedirect(result)) {
201
+ ctx.resStatus = result.status;
202
+ await runResponseHooks(ctx);
203
+ applyResHeaders(ctx.resHeaders, res);
204
+ _writeJsonResponse(res, serializeRedirect(result), result.status, ctx.resHeaders);
205
+ return;
206
+ }
207
+ if (isStreamResponse(result)) {
208
+ ctx.resStatus = 200;
209
+ await runResponseHooks(ctx);
210
+ applyResHeaders(ctx.resHeaders, res);
211
+ const { writeStream } = await import("./stream.js");
212
+ writeStream(result, res, signal);
213
+ return;
214
+ }
215
+ if (isDownload(result)) {
216
+ ctx.resStatus = 200;
217
+ await runResponseHooks(ctx);
218
+ applyResHeaders(ctx.resHeaders, res);
219
+ writeDownload(result, res);
220
+ return;
221
+ }
222
+ // Default: JSON response
223
+ const body = result === undefined || result === null ? {} : result;
224
+ ctx.resStatus = 200;
225
+ await runResponseHooks(ctx);
226
+ applyResHeaders(ctx.resHeaders, res);
227
+ _writeJsonResponse(res, body, 200, ctx.resHeaders);
228
+ }
229
+ catch (err) {
230
+ if (res.headersSent)
231
+ return;
232
+ // Check for Redirect thrown via redirect() helper
233
+ if (isRedirect(err)) {
234
+ ctx.resStatus = err.status;
235
+ await runResponseHooks(ctx);
236
+ applyResHeaders(ctx.resHeaders, res);
237
+ _writeJsonResponse(res, serializeRedirect(err), err.status, ctx.resHeaders);
238
+ return;
239
+ }
240
+ const serialized = serializeError(err, dev);
241
+ _applyRateLimitHeader(serialized, ctx);
242
+ ctx.resStatus = serialized.status;
243
+ await runResponseHooks(ctx);
244
+ applyResHeaders(ctx.resHeaders, res);
245
+ _writeErrorResponse(res, serialized, serialized.status);
246
+ }
247
+ }
248
+ // ─── Internal helpers ──────────────────────────────────────────────────────────────────────
249
+ /** Set Retry-After header for rate-limit errors. */
250
+ function _applyRateLimitHeader(serialized, ctx) {
251
+ if (serialized.code === "RATE_LIMIT" && serialized.retryAfter !== undefined) {
252
+ ctx.resHeaders["retry-after"] = String(serialized.retryAfter);
253
+ }
254
+ }
255
+ // ─── Body parsing ────────────────────────────────────────────────────────────────────
256
+ /**
257
+ * Read and parse the request body.
258
+ *
259
+ * Handles:
260
+ * - application/json → JSON.parse
261
+ * - multipart/form-data → FormData-like object with File entries
262
+ * - no content-type → attempt JSON parse, fallback to {}
263
+ * - empty body → {}
264
+ *
265
+ * Throws with .status set for:
266
+ * - Body too large (413)
267
+ * - Malformed JSON (400)
268
+ */
269
+ export async function parseRpcBody(req) {
270
+ return _parseBody(req);
271
+ }
272
+ async function _parseBody(req) {
273
+ const contentType = (req.headers["content-type"] ?? "").toLowerCase();
274
+ const contentLength = parseInt(req.headers["content-length"] ?? "0", 10);
275
+ // ── Multipart/form-data ────────────────────────────────────────────────
276
+ if (contentType.includes("multipart/form-data")) {
277
+ if (contentLength > _config.maxUploadBytes) {
278
+ const err = new Error(`Upload too large. Maximum size is ${_config.maxUploadBytes / 1024 / 1024}MB.`);
279
+ err.status = 413;
280
+ throw err;
281
+ }
282
+ return _parseMultipart(req, contentType);
283
+ }
284
+ // ── JSON (default) ─────────────────────────────────────────────────────
285
+ if (contentLength > _config.maxJsonBytes) {
286
+ const err = new Error(`Request body too large. Maximum size is ${_config.maxJsonBytes / 1024}KB.`);
287
+ err.status = 413;
288
+ throw err;
289
+ }
290
+ const raw = await _readBody(req, _config.maxJsonBytes);
291
+ // Empty body → {}
292
+ if (!raw || raw.length === 0)
293
+ return {};
294
+ try {
295
+ // Parse JSON first, then validate depth and array sizes recursively.
296
+ // This prevents stack exhaustion from deeply nested objects
297
+ // and CPU/memory exhaustion from massive arrays.
298
+ const parsed = JSON.parse(raw);
299
+ _validateJsonPayload(parsed, 0);
300
+ // Must be an object at the top level
301
+ if (typeof parsed !== "object" ||
302
+ parsed === null ||
303
+ Array.isArray(parsed)) {
304
+ // Allow it but wrap so payload is always an object shape
305
+ // The actual function signature handles this
306
+ return parsed;
307
+ }
308
+ return parsed;
309
+ }
310
+ catch {
311
+ const err = new Error("Invalid JSON in request body.");
312
+ err.status = 400;
313
+ throw err;
314
+ }
315
+ }
316
+ /**
317
+ * Read the raw request body as a string.
318
+ * Enforces a maximum byte limit to prevent memory exhaustion.
319
+ */
320
+ async function _readBody(req, maxBytes) {
321
+ return new Promise((resolve, reject) => {
322
+ const chunks = [];
323
+ let totalBytes = 0;
324
+ req.on("data", (chunk) => {
325
+ totalBytes += chunk.length;
326
+ if (totalBytes > maxBytes) {
327
+ req.destroy(); // stop reading
328
+ const err = new Error(`Request body too large. Maximum size is ${maxBytes / 1024}KB.`);
329
+ err.status = 413;
330
+ reject(err);
331
+ return;
332
+ }
333
+ chunks.push(chunk);
334
+ });
335
+ req.on("end", () => {
336
+ resolve(Buffer.concat(chunks).toString("utf-8"));
337
+ });
338
+ req.on("error", (err) => {
339
+ reject(err);
340
+ });
341
+ });
342
+ }
343
+ /**
344
+ * Parse a multipart/form-data body.
345
+ *
346
+ * Returns a plain object where:
347
+ * - Text fields → string values
348
+ * - File fields → { name, type, size, buffer } objects
349
+ *
350
+ * This is a minimal parser that covers the common cases.
351
+ * For production use, a more robust parser (e.g. busboy) is recommended
352
+ * but we avoid adding dependencies.
353
+ */
354
+ async function _parseMultipart(req, contentType) {
355
+ // Extract boundary from Content-Type header
356
+ // e.g. multipart/form-data; boundary=----WebKitFormBoundary...
357
+ const boundaryMatch = contentType.match(/boundary=([^\s;]+)/i);
358
+ if (!boundaryMatch) {
359
+ const err = new Error("Missing boundary in multipart/form-data Content-Type.");
360
+ err.status = 400;
361
+ throw err;
362
+ }
363
+ const boundary = boundaryMatch[1].replace(/^"(.*)"$/, "$1"); // strip quotes
364
+ const rawBody = await _readBodyBuffer(req, _config.maxUploadBytes);
365
+ return _parseMultipartBuffer(rawBody, boundary);
366
+ }
367
+ async function _readBodyBuffer(req, maxBytes) {
368
+ return new Promise((resolve, reject) => {
369
+ const chunks = [];
370
+ let totalBytes = 0;
371
+ req.on("data", (chunk) => {
372
+ totalBytes += chunk.length;
373
+ if (totalBytes > maxBytes) {
374
+ req.destroy();
375
+ const err = new Error(`Upload too large. Maximum size is ${maxBytes / 1024 / 1024}MB.`);
376
+ err.status = 413;
377
+ reject(err);
378
+ return;
379
+ }
380
+ chunks.push(chunk);
381
+ });
382
+ req.on("end", () => resolve(Buffer.concat(chunks)));
383
+ req.on("error", reject);
384
+ });
385
+ }
386
+ /**
387
+ * Sanitize a filename from Content-Disposition to prevent path traversal.
388
+ * Strips directory separators, null bytes, and other dangerous characters.
389
+ */
390
+ function _sanitizeFilename(filename) {
391
+ // Strip null bytes
392
+ let clean = filename.replace(/\0/g, "");
393
+ // Strip directory traversal patterns
394
+ clean = clean.replace(/\.\./g, "");
395
+ // Strip path separators (forward and backslash)
396
+ clean = clean.replace(/[/\\]/g, "");
397
+ // Strip any remaining dangerous characters
398
+ clean = clean.replace(/[<>:"|?*]/g, "_");
399
+ // Trim whitespace
400
+ clean = clean.trim();
401
+ // Default name for empty results
402
+ return clean || "unnamed";
403
+ }
404
+ function _parseMultipartBuffer(body, boundary) {
405
+ const result = {};
406
+ const delimiter = Buffer.from(`--${boundary}`);
407
+ const parts = _splitBuffer(body, delimiter);
408
+ // Enforce maximum part count to prevent CPU/memory exhaustion
409
+ if (parts.length > _config.maxMultipartParts) {
410
+ const err = new Error(`Too many multipart parts. Maximum is ${_config.maxMultipartParts}.`);
411
+ err.status = 413;
412
+ throw err;
413
+ }
414
+ for (const part of parts) {
415
+ // Skip preamble, epilogue, and empty parts
416
+ if (part.length < 4)
417
+ continue;
418
+ // Find the blank line separating headers from body (\r\n\r\n)
419
+ const headerEnd = _indexOfBuffer(part, Buffer.from("\r\n\r\n"));
420
+ if (headerEnd === -1)
421
+ continue;
422
+ const headerSection = part.slice(0, headerEnd).toString("utf-8");
423
+ const bodySection = part.slice(headerEnd + 4);
424
+ // Remove trailing \r\n from body
425
+ const partBody = bodySection.length >= 2 &&
426
+ bodySection[bodySection.length - 2] === 13 &&
427
+ bodySection[bodySection.length - 1] === 10
428
+ ? bodySection.slice(0, -2)
429
+ : bodySection;
430
+ // Parse headers
431
+ const headers = {};
432
+ for (const line of headerSection.split("\r\n")) {
433
+ const colonIdx = line.indexOf(":");
434
+ if (colonIdx === -1)
435
+ continue;
436
+ headers[line.slice(0, colonIdx).trim().toLowerCase()] = line
437
+ .slice(colonIdx + 1)
438
+ .trim();
439
+ }
440
+ // Extract name and filename from Content-Disposition
441
+ const disposition = headers["content-disposition"] ?? "";
442
+ const nameMatch = disposition.match(/name="([^"]+)"/);
443
+ const filenameMatch = disposition.match(/filename="([^"]*)"/);
444
+ if (!nameMatch)
445
+ continue;
446
+ const fieldName = nameMatch[1];
447
+ if (filenameMatch) {
448
+ // File field
449
+ const rawFilename = filenameMatch[1];
450
+ const filename = _sanitizeFilename(rawFilename);
451
+ const mimeType = headers["content-type"] ?? "application/octet-stream";
452
+ // Store as a plain object with buffer — avoids File/Blob browser APIs
453
+ const fileEntry = {
454
+ name: filename,
455
+ type: mimeType,
456
+ size: partBody.length,
457
+ buffer: partBody,
458
+ // Helper to get as Buffer (server-side usage)
459
+ arrayBuffer: () => Promise.resolve(partBody.buffer.slice(partBody.byteOffset, partBody.byteOffset + partBody.byteLength)),
460
+ };
461
+ // Multiple files with same name → convert to array
462
+ if (fieldName in result) {
463
+ const existing = result[fieldName];
464
+ result[fieldName] = Array.isArray(existing)
465
+ ? [...existing, fileEntry]
466
+ : [existing, fileEntry];
467
+ }
468
+ else {
469
+ result[fieldName] = fileEntry;
470
+ }
471
+ }
472
+ else {
473
+ // Text field
474
+ const value = partBody.toString("utf-8");
475
+ if (fieldName in result) {
476
+ const existing = result[fieldName];
477
+ result[fieldName] = Array.isArray(existing)
478
+ ? [...existing, value]
479
+ : [existing, value];
480
+ }
481
+ else {
482
+ result[fieldName] = value;
483
+ }
484
+ }
485
+ }
486
+ return result;
487
+ }
488
+ /** Split a Buffer by a delimiter Buffer, returning the parts between delimiters. */
489
+ function _splitBuffer(buf, delimiter) {
490
+ const parts = [];
491
+ let start = 0;
492
+ while (true) {
493
+ const idx = _indexOfBuffer(buf, delimiter, start);
494
+ if (idx === -1) {
495
+ parts.push(buf.slice(start));
496
+ break;
497
+ }
498
+ parts.push(buf.slice(start, idx));
499
+ start = idx + delimiter.length;
500
+ // Skip \r\n after delimiter
501
+ if (buf[start] === 13 && buf[start + 1] === 10)
502
+ start += 2;
503
+ // Final boundary ends with --
504
+ if (buf[start] === 45 && buf[start + 1] === 45)
505
+ break;
506
+ }
507
+ return parts;
508
+ }
509
+ /** Find the index of `needle` in `haystack` starting at `offset`. */
510
+ function _indexOfBuffer(haystack, needle, offset = 0) {
511
+ outer: for (let i = offset; i <= haystack.length - needle.length; i++) {
512
+ for (let j = 0; j < needle.length; j++) {
513
+ if (haystack[i + j] !== needle[j])
514
+ continue outer;
515
+ }
516
+ return i;
517
+ }
518
+ return -1;
519
+ }
520
+ // ─── Response writers ─────────────────────────────────────────────────────────
521
+ /**
522
+ * Write a JSON response with the given status code.
523
+ * Applies ctx.resHeaders before writing.
524
+ */
525
+ function _writeJsonResponse(res, body, status, resHeaders = {}) {
526
+ if (res.headersSent)
527
+ return;
528
+ let json;
529
+ let finalStatus = status;
530
+ try {
531
+ json = JSON.stringify(body);
532
+ }
533
+ catch {
534
+ finalStatus = 500;
535
+ json = JSON.stringify({
536
+ __type: "AppError",
537
+ message: "RPC response is not JSON-serializable",
538
+ status: 500,
539
+ code: "SERIALIZATION_ERROR",
540
+ });
541
+ }
542
+ const headers = {
543
+ "Content-Type": "application/json; charset=utf-8",
544
+ "Content-Length": Buffer.byteLength(json).toString(),
545
+ ...resHeaders,
546
+ };
547
+ try {
548
+ res.writeHead(finalStatus, headers);
549
+ res.end(json);
550
+ }
551
+ catch {
552
+ // Connection was closed before we could write — ignore
553
+ }
554
+ }
555
+ /**
556
+ * Write a JSON error response.
557
+ * Does NOT apply ctx.resHeaders (caller should do that separately if needed).
558
+ */
559
+ function _writeErrorResponse(res, error, status) {
560
+ if (res.headersSent)
561
+ return;
562
+ _writeJsonResponse(res, error, status);
563
+ }
564
+ //# sourceMappingURL=rpc-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-runner.js","sourceRoot":"","sources":["../src/rpc-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAiCzB,MAAM,OAAO,GAA8B;IACzC,YAAY,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IAC7B,YAAY,EAAE,EAAE;IAChB,cAAc,EAAE,KAAM;IACtB,eAAe,EAAE,MAAO;IACxB,cAAc,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IAChC,iBAAiB,EAAE,GAAG;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAuB;IACxD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;QACnC,OAAO,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IAC7C,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;QACnC,OAAO,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IAC7C,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS;QACrC,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IACjD,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS;QACtC,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;IACnD,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS;QACrC,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IACjD,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS;QACxC,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,KAAc,EAAE,KAAa;IACzD,IAAI,KAAK,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACjC,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,yCAAyC,OAAO,CAAC,YAAY,GAAG,CACjE,CAAC;QACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;QACxE,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,yCAAyC,OAAO,CAAC,eAAe,GAAG,CACpE,CAAC;QACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,wCAAwC,OAAO,CAAC,cAAc,GAAG,CAClE,CAAC;YACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,oBAAoB,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,oBAAoB,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACrC,oBAAoB,CAAE,KAAiC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;AACH,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAEzC,iFAAiF;AAEjF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAoB,EACpB,GAAmB,EACnB,KAAe,EACf,GAAY,EACZ,SAAS,GAAG,kBAAkB;AAC9B;0EAC0E;AAC1E,SAAsC;IAEtC,wEAAwE;IACxE,8BAA8B;IAC9B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAE9B,2EAA2E;IAC3E,oEAAoE;IACpE,6DAA6D;IAC7D,MAAM,GAAG,GAAG,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IAE5C,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACnB,IAAI,CAAC,GAAG,CAAC,aAAa;YAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YACvB,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,UAAU,GAAG;gBACjB,MAAM,EAAE,UAAU;gBAClB,OAAO,EAAE,iBAAiB;gBAC1B,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,SAAS;aACP,CAAC;YACX,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;YACpB,KAAK,gBAAgB,CAAC,GAAU,CAAC,CAAC;YAClC,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,EAAE,SAAS,CAAC,CAAC;IAEd,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC5C,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC;YAClC,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;YACnC,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,KAAK,UAAU,QAAQ,CACrB,GAAoB,EACpB,GAAmB,EACnB,KAAe,EACf,GAAY,EACZ,MAAmB,EACnB,GAA+B;IAE/B,8EAA8E;IAC9E,IAAI,OAAgB,CAAC;IAErB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,CAAC,WAAW;YAAE,OAAO;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;QACjC,MAAM,UAAU,GAAG;YACjB,MAAM,EAAE,UAAmB;YAC3B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,aAAa;YACrC,MAAM;YACN,IAAI,EAAE,aAAsB;SAC7B,CAAC;QACF,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;QACvB,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;QACnC,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,sEAAsE;IACtE,2EAA2E;IAC3E,IAAI,CAAC;QACH,MAAM,aAAa,GACjB,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;YAC/D,CAAC,CAAE,OAAmC;YACtC,CAAC,CAAC,EAAE,CAAC;QAET,sEAAsE;QACtE,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE/D,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAE/C,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE;YAC9C,QAAQ;YACR,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,QAAQ;SACT,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,WAAW;YAAE,OAAO;QAE5B,+DAA+D;QAC/D,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;YAC9B,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;YACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACrC,kBAAkB,CAChB,GAAG,EACH,iBAAiB,CAAC,MAAM,CAAC,EACzB,MAAM,CAAC,MAAM,EACb,GAAG,CAAC,UAAU,CACf,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;YACpB,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;YACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACrC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YACpD,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;YACpB,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;YACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACrC,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC3B,OAAO;QACT,CAAC;QAED,yBAAyB;QACzB,MAAM,IAAI,GAAG,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAEnE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QACpB,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;QACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACrC,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,CAAC,WAAW;YAAE,OAAO;QAE5B,kDAAkD;QAClD,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC;YAC3B,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;YACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACrC,kBAAkB,CAChB,GAAG,EACH,iBAAiB,CAAC,GAAG,CAAC,EACtB,GAAG,CAAC,MAAM,EACV,GAAG,CAAC,UAAU,CACf,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5C,qBAAqB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvC,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC;QAClC,MAAM,gBAAgB,CAAC,GAAU,CAAC,CAAC;QACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACrC,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,8FAA8F;AAE9F,oDAAoD;AACpD,SAAS,qBAAqB,CAC5B,UAA6C,EAC7C,GAA+B;IAE/B,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC5E,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,wFAAwF;AAExF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB;IACrD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,GAAoB;IAC5C,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACtE,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAEzE,0EAA0E;IAC1E,IAAI,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAChD,IAAI,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,qCAAqC,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,IAAI,KAAK,CAC/E,CAAC;YACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,eAAe,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,0EAA0E;IAC1E,IAAI,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACzC,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,2CAA2C,OAAO,CAAC,YAAY,GAAG,IAAI,KAAK,CAC5E,CAAC;QACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAEvD,kBAAkB;IAClB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,IAAI,CAAC;QACH,qEAAqE;QACrE,4DAA4D;QAC5D,iDAAiD;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAEhC,qCAAqC;QACrC,IACE,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EACrB,CAAC;YACD,yDAAyD;YACzD,6CAA6C;YAC7C,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAQ,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC5D,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,SAAS,CACtB,GAAoB,EACpB,QAAgB;IAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;YAE3B,IAAI,UAAU,GAAG,QAAQ,EAAE,CAAC;gBAC1B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,eAAe;gBAC9B,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,2CAA2C,QAAQ,GAAG,IAAI,KAAK,CAChE,CAAC;gBACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;gBACjB,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACtB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,eAAe,CAC5B,GAAoB,EACpB,WAAmB;IAEnB,4CAA4C;IAC5C,+DAA+D;IAC/D,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC/D,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,uDAAuD,CACxD,CAAC;QACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe;IAC5E,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEnE,OAAO,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,GAAoB,EACpB,QAAgB;IAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;YAC3B,IAAI,UAAU,GAAG,QAAQ,EAAE,CAAC;gBAC1B,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,qCAAqC,QAAQ,GAAG,IAAI,GAAG,IAAI,KAAK,CACjE,CAAC;gBACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;gBACjB,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,mBAAmB;IACnB,IAAI,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxC,qCAAqC;IACrC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnC,gDAAgD;IAChD,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpC,2CAA2C;IAC3C,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACzC,kBAAkB;IAClB,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,KAAK,IAAI,SAAS,CAAC;AAC5B,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAY,EACZ,QAAgB;IAEhB,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAE5C,8DAA8D;IAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAQ,IAAI,KAAK,CACxB,wCAAwC,OAAO,CAAC,iBAAiB,GAAG,CACrE,CAAC;QACF,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,2CAA2C;QAC3C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAE9B,8DAA8D;QAC9D,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChE,IAAI,SAAS,KAAK,CAAC,CAAC;YAAE,SAAS;QAE/B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QAE9C,iCAAiC;QACjC,MAAM,QAAQ,GACZ,WAAW,CAAC,MAAM,IAAI,CAAC;YACvB,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;YAC1C,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;YACxC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,CAAC,CAAC,WAAW,CAAC;QAElB,gBAAgB;QAChB,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,QAAQ,KAAK,CAAC,CAAC;gBAAE,SAAS;YAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI;iBACzD,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;iBACnB,IAAI,EAAE,CAAC;QACZ,CAAC;QAED,qDAAqD;QACrD,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC;QACzD,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACtD,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE9D,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAE/B,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa;YACb,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,0BAA0B,CAAC;YAEvE,sEAAsE;YACtE,MAAM,SAAS,GAAG;gBAChB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ,CAAC,MAAM;gBACrB,MAAM,EAAE,QAAQ;gBAChB,8CAA8C;gBAC9C,WAAW,EAAE,GAAG,EAAE,CAChB,OAAO,CAAC,OAAO,CACb,QAAQ,CAAC,MAAM,CAAC,KAAK,CACnB,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAC1C,CACF;aACJ,CAAC;YAEF,mDAAmD;YACnD,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnC,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;oBACzC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC;oBAC1B,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;YAChC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,aAAa;YACb,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnC,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;oBACzC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC;oBACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oFAAoF;AACpF,SAAS,YAAY,CAAC,GAAW,EAAE,SAAiB;IAClD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAClD,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7B,MAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QAClC,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC;QAC/B,4BAA4B;QAC5B,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE;YAAE,KAAK,IAAI,CAAC,CAAC;QAC3D,8BAA8B;QAC9B,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE;YAAE,MAAM;IACxD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,qEAAqE;AACrE,SAAS,cAAc,CAAC,QAAgB,EAAE,MAAc,EAAE,MAAM,GAAG,CAAC;IAClE,KAAK,EAAE,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,IAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;gBAAE,SAAS,KAAK,CAAC;QACpD,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,SAAS,kBAAkB,CACzB,GAAmB,EACnB,IAAa,EACb,MAAc,EACd,aAAgD,EAAE;IAElD,IAAI,GAAG,CAAC,WAAW;QAAE,OAAO;IAE5B,IAAI,IAAY,CAAC;IACjB,IAAI,WAAW,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,GAAG,CAAC;QAClB,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YACpB,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,uCAAuC;YAChD,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,qBAAqB;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAsC;QACjD,cAAc,EAAE,iCAAiC;QACjD,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;QACpD,GAAG,UAAU;KACd,CAAC;IAEF,IAAI,CAAC;QACH,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACpC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,uDAAuD;IACzD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,GAAmB,EACnB,KAAa,EACb,MAAc;IAEd,IAAI,GAAG,CAAC,WAAW;QAAE,OAAO;IAC5B,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,61 @@
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
+ /// <reference types="node" />
19
+ export type SanitizeMode = "strip" | "escape" | "reject";
20
+ export interface SanitizeConfig {
21
+ enabled: boolean;
22
+ mode: SanitizeMode;
23
+ skip: string[];
24
+ }
25
+ export declare class SanitizeError extends Error {
26
+ readonly status = 400;
27
+ readonly code = "XSS_DETECTED";
28
+ readonly field: string;
29
+ constructor(field: string);
30
+ }
31
+ /**
32
+ * Sanitize a single string value.
33
+ * Returns the cleaned string or throws SanitizeError in "reject" mode.
34
+ */
35
+ export declare function sanitizeString(value: string, fieldName: string, mode: SanitizeMode): string;
36
+ /**
37
+ * Recursively sanitize all string values in an object or array.
38
+ *
39
+ * @param input The parsed JSON value (object, array, primitive)
40
+ * @param config Sanitize configuration
41
+ * @param fieldName Current field path (for error messages)
42
+ * @param seen WeakSet to detect circular references
43
+ * @returns The sanitized value (mutates strings in place for objects)
44
+ */
45
+ export declare function sanitizeBody(input: unknown, config: SanitizeConfig, fieldName?: string, seen?: WeakSet<object>): unknown;
46
+ /**
47
+ * Sanitize a WebSocket message.
48
+ * Parses JSON if the message is a string, sanitizes all string fields,
49
+ * and returns the cleaned object (or the original string if not JSON).
50
+ *
51
+ * @param msg Raw WebSocket message (string or Buffer)
52
+ * @param config Sanitize config
53
+ * @returns { parsed: any, raw: string } — parsed is the sanitized object,
54
+ * raw is the original string for pass-through if needed
55
+ */
56
+ export declare function sanitizeWsMessage(msg: string | Buffer, config: SanitizeConfig): {
57
+ parsed: unknown;
58
+ raw: string;
59
+ isJson: boolean;
60
+ };
61
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;;AAkCH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AA4CD,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,OAAO;IACtB,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM;CAK1B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,YAAY,GACjB,MAAM,CAUR;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,cAAc,EACtB,SAAS,SAAS,EAClB,IAAI,kBAAwB,GAC3B,OAAO,CAmDT;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,GAAG,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAuBnD"}