elysia 1.4.30 → 1.4.31

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.
@@ -19,7 +19,11 @@ __export(compose_exports, {
19
19
  });
20
20
  module.exports = __toCommonJS(compose_exports);
21
21
  var import_handler = require('./handler.js'), import_sucrose = require('../../sucrose.js'), import_compose = require('../../compose.js'), import_utils = require('../../utils.js'), import_error = require('../../error.js'), import_trace = require('../../trace.js');
22
- const allocateIf = (value, condition) => condition ? value : "", createContext = (app, route, inference, isInline = !1) => {
22
+ const allocateIf = (value, condition) => condition ? value : "", preserveEncodedSlashes = (params) => {
23
+ for (const key of Object.keys(params))
24
+ params[key].includes("/") && (params[key] = params[key].replaceAll("/", "%2F"));
25
+ return params;
26
+ }, createContext = (app, route, inference, isInline = !1) => {
23
27
  let fnLiteral = "";
24
28
  const defaultHeaders = app.setHeaders, hasTrace = !!app.event.trace?.length;
25
29
  hasTrace && (fnLiteral += `const id=randomId()
@@ -31,8 +35,8 @@ const allocateIf = (value, condition) => condition ? value : "", createContext =
31
35
  needsQuery && (fnLiteral += getQi);
32
36
  const getPath = inference.path ? isDynamic ? "get path(){" + (needsQuery ? "" : getQi) + `if(qi===-1)return u.substring(s)
33
37
  return u.substring(s,qi)
34
- },` : `path:'${route.path}',` : "";
35
- fnLiteral += allocateIf("const c=", !isInline) + "{request,store," + allocateIf("qi,", needsQuery) + allocateIf("params:request.params,", isDynamic) + getPath + allocateIf(
38
+ },` : "path:route," : "";
39
+ fnLiteral += allocateIf("const c=", !isInline) + "{request,store," + allocateIf("qi,", needsQuery) + allocateIf("params:preserveEncodedSlashes(request.params),", isDynamic) + getPath + allocateIf(
36
40
  "url:request.url,",
37
41
  hasTrace || inference.url || needsQuery
38
42
  ) + "redirect,status,set:{headers:" + ((0, import_utils.isNotEmpty)(defaultHeaders) ? "Object.assign({},app.setHeaders)" : "Object.create(null)") + ",status:200}", inference.server && (fnLiteral += ",get server(){return app.getServer()}"), hasTrace && (fnLiteral += ",[ELYSIA_REQUEST_ID]:id");
@@ -57,7 +61,7 @@ return u.substring(s,qi)
57
61
  },
58
62
  inference
59
63
  );
60
- let fnLiteral = "const handler=data.handler,app=data.app,store=data.store,decorator=data.decorator,redirect=data.redirect,route=data.route,mapEarlyResponse=data.mapEarlyResponse," + allocateIf("randomId=data.randomId,", hasTrace) + allocateIf("ELYSIA_REQUEST_ID=data.ELYSIA_REQUEST_ID,", hasTrace) + allocateIf("ELYSIA_TRACE=data.ELYSIA_TRACE,", hasTrace) + allocateIf("trace=data.trace,", hasTrace) + allocateIf("hoc=data.hoc,", hasHoc) + `status=data.status
64
+ let fnLiteral = "const handler=data.handler,app=data.app,store=data.store,decorator=data.decorator,preserveEncodedSlashes=data.preserveEncodedSlashes,redirect=data.redirect,route=data.route,mapEarlyResponse=data.mapEarlyResponse," + allocateIf("randomId=data.randomId,", hasTrace) + allocateIf("ELYSIA_REQUEST_ID=data.ELYSIA_REQUEST_ID,", hasTrace) + allocateIf("ELYSIA_TRACE=data.ELYSIA_TRACE,", hasTrace) + allocateIf("trace=data.trace,", hasTrace) + allocateIf("hoc=data.hoc,", hasHoc) + `status=data.status
61
65
  `;
62
66
  app.event.request?.length && (fnLiteral += `const onRequest=app.event.request.map(x=>x.fn)
63
67
  `), fnLiteral += `${app.event.request?.find(import_compose.isAsync) ? "async" : ""} function map(request){`;
@@ -76,6 +80,7 @@ return u.substring(s,qi)
76
80
  hoc: app.extender.higherOrderFunctions.map((x) => x.fn),
77
81
  store: app.store,
78
82
  decorator: app.decorator,
83
+ preserveEncodedSlashes,
79
84
  route: route.path,
80
85
  randomId: hasTrace ? import_utils.randomId : void 0,
81
86
  ELYSIA_TRACE: hasTrace ? import_trace.ELYSIA_TRACE : void 0,
@@ -4,7 +4,11 @@ import { createHoc, createOnRequestHandler, isAsync } from "../../compose.mjs";
4
4
  import { randomId, ELYSIA_REQUEST_ID, redirect, isNotEmpty } from "../../utils.mjs";
5
5
  import { status } from "../../error.mjs";
6
6
  import { ELYSIA_TRACE } from "../../trace.mjs";
7
- const allocateIf = (value, condition) => condition ? value : "", createContext = (app, route, inference, isInline = !1) => {
7
+ const allocateIf = (value, condition) => condition ? value : "", preserveEncodedSlashes = (params) => {
8
+ for (const key of Object.keys(params))
9
+ params[key].includes("/") && (params[key] = params[key].replaceAll("/", "%2F"));
10
+ return params;
11
+ }, createContext = (app, route, inference, isInline = !1) => {
8
12
  let fnLiteral = "";
9
13
  const defaultHeaders = app.setHeaders, hasTrace = !!app.event.trace?.length;
10
14
  hasTrace && (fnLiteral += `const id=randomId()
@@ -16,8 +20,8 @@ const allocateIf = (value, condition) => condition ? value : "", createContext =
16
20
  needsQuery && (fnLiteral += getQi);
17
21
  const getPath = inference.path ? isDynamic ? "get path(){" + (needsQuery ? "" : getQi) + `if(qi===-1)return u.substring(s)
18
22
  return u.substring(s,qi)
19
- },` : `path:'${route.path}',` : "";
20
- fnLiteral += allocateIf("const c=", !isInline) + "{request,store," + allocateIf("qi,", needsQuery) + allocateIf("params:request.params,", isDynamic) + getPath + allocateIf(
23
+ },` : "path:route," : "";
24
+ fnLiteral += allocateIf("const c=", !isInline) + "{request,store," + allocateIf("qi,", needsQuery) + allocateIf("params:preserveEncodedSlashes(request.params),", isDynamic) + getPath + allocateIf(
21
25
  "url:request.url,",
22
26
  hasTrace || inference.url || needsQuery
23
27
  ) + "redirect,status,set:{headers:" + (isNotEmpty(defaultHeaders) ? "Object.assign({},app.setHeaders)" : "Object.create(null)") + ",status:200}", inference.server && (fnLiteral += ",get server(){return app.getServer()}"), hasTrace && (fnLiteral += ",[ELYSIA_REQUEST_ID]:id");
@@ -42,7 +46,7 @@ return u.substring(s,qi)
42
46
  },
43
47
  inference
44
48
  );
45
- let fnLiteral = "const handler=data.handler,app=data.app,store=data.store,decorator=data.decorator,redirect=data.redirect,route=data.route,mapEarlyResponse=data.mapEarlyResponse," + allocateIf("randomId=data.randomId,", hasTrace) + allocateIf("ELYSIA_REQUEST_ID=data.ELYSIA_REQUEST_ID,", hasTrace) + allocateIf("ELYSIA_TRACE=data.ELYSIA_TRACE,", hasTrace) + allocateIf("trace=data.trace,", hasTrace) + allocateIf("hoc=data.hoc,", hasHoc) + `status=data.status
49
+ let fnLiteral = "const handler=data.handler,app=data.app,store=data.store,decorator=data.decorator,preserveEncodedSlashes=data.preserveEncodedSlashes,redirect=data.redirect,route=data.route,mapEarlyResponse=data.mapEarlyResponse," + allocateIf("randomId=data.randomId,", hasTrace) + allocateIf("ELYSIA_REQUEST_ID=data.ELYSIA_REQUEST_ID,", hasTrace) + allocateIf("ELYSIA_TRACE=data.ELYSIA_TRACE,", hasTrace) + allocateIf("trace=data.trace,", hasTrace) + allocateIf("hoc=data.hoc,", hasHoc) + `status=data.status
46
50
  `;
47
51
  app.event.request?.length && (fnLiteral += `const onRequest=app.event.request.map(x=>x.fn)
48
52
  `), fnLiteral += `${app.event.request?.find(isAsync) ? "async" : ""} function map(request){`;
@@ -61,6 +65,7 @@ return u.substring(s,qi)
61
65
  hoc: app.extender.higherOrderFunctions.map((x) => x.fn),
62
66
  store: app.store,
63
67
  decorator: app.decorator,
68
+ preserveEncodedSlashes,
64
69
  route: route.path,
65
70
  randomId: hasTrace ? randomId : void 0,
66
71
  ELYSIA_TRACE: hasTrace ? ELYSIA_TRACE : void 0,
@@ -238,7 +238,10 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
238
238
  // @ts-expect-error private property
239
239
  models: app.definitions.type,
240
240
  normalize: app.config.normalize
241
- }), validateMessage = messageValidator ? messageValidator.provider === "standard" ? (data) => messageValidator.schema["~standard"].validate(data).issues : (data) => messageValidator.Check(data) === !1 : void 0, responseValidator = (0, import_schema.getSchemaValidator)(response, {
241
+ }), validateMessage = messageValidator ? messageValidator.provider === "standard" ? (data) => messageValidator.schema["~standard"].validate(data) : (data) => ({
242
+ issues: messageValidator.Check(data) === !1 || void 0,
243
+ value: data
244
+ }) : void 0, responseValidator = (0, import_schema.getSchemaValidator)(response, {
242
245
  // @ts-expect-error private property
243
246
  modules: app.definitions.typebox,
244
247
  // @ts-expect-error private property
@@ -313,19 +316,22 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
313
316
  }
314
317
  },
315
318
  message: async (ws, _message) => {
316
- const message = await parseMessage(ws, _message);
317
- if (validateMessage && validateMessage(message)) {
318
- const validationError = new import_error.ValidationError(
319
- "message",
320
- messageValidator,
321
- message
322
- );
323
- return hasCustomErrorHandlers ? handleErrors(ws, validationError) : void ws.send(
324
- validationError.message
325
- );
326
- }
327
319
  try {
328
- await handleResponse(
320
+ let message = await parseMessage(ws, _message);
321
+ const validation = validateMessage ? await validateMessage(message) : void 0;
322
+ if (validation?.issues) {
323
+ const validationError = new import_error.ValidationError(
324
+ "message",
325
+ messageValidator,
326
+ message,
327
+ !1,
328
+ messageValidator?.provider === "standard" ? validation.issues : void 0
329
+ );
330
+ return hasCustomErrorHandlers ? handleErrors(ws, validationError) : void ws.send(
331
+ validationError.message
332
+ );
333
+ }
334
+ validation && (message = validation.value), await handleResponse(
329
335
  ws,
330
336
  options.message?.(
331
337
  new import_ws.ElysiaWS(
@@ -241,7 +241,10 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
241
241
  // @ts-expect-error private property
242
242
  models: app.definitions.type,
243
243
  normalize: app.config.normalize
244
- }), validateMessage = messageValidator ? messageValidator.provider === "standard" ? (data) => messageValidator.schema["~standard"].validate(data).issues : (data) => messageValidator.Check(data) === !1 : void 0, responseValidator = getSchemaValidator(response, {
244
+ }), validateMessage = messageValidator ? messageValidator.provider === "standard" ? (data) => messageValidator.schema["~standard"].validate(data) : (data) => ({
245
+ issues: messageValidator.Check(data) === !1 || void 0,
246
+ value: data
247
+ }) : void 0, responseValidator = getSchemaValidator(response, {
245
248
  // @ts-expect-error private property
246
249
  modules: app.definitions.typebox,
247
250
  // @ts-expect-error private property
@@ -316,19 +319,22 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
316
319
  }
317
320
  },
318
321
  message: async (ws, _message) => {
319
- const message = await parseMessage(ws, _message);
320
- if (validateMessage && validateMessage(message)) {
321
- const validationError = new ValidationError(
322
- "message",
323
- messageValidator,
324
- message
325
- );
326
- return hasCustomErrorHandlers ? handleErrors(ws, validationError) : void ws.send(
327
- validationError.message
328
- );
329
- }
330
322
  try {
331
- await handleResponse(
323
+ let message = await parseMessage(ws, _message);
324
+ const validation = validateMessage ? await validateMessage(message) : void 0;
325
+ if (validation?.issues) {
326
+ const validationError = new ValidationError(
327
+ "message",
328
+ messageValidator,
329
+ message,
330
+ !1,
331
+ messageValidator?.provider === "standard" ? validation.issues : void 0
332
+ );
333
+ return hasCustomErrorHandlers ? handleErrors(ws, validationError) : void ws.send(
334
+ validationError.message
335
+ );
336
+ }
337
+ validation && (message = validation.value), await handleResponse(
332
338
  ws,
333
339
  options.message?.(
334
340
  new ElysiaWS(
@@ -285,25 +285,70 @@ const createResponseHandler = (handler) => {
285
285
  };
286
286
  };
287
287
  async function tee(source, branches = 2) {
288
- const buffer = [];
289
- let done = !1, waiting = [];
290
- (async () => {
291
- for await (const value of source)
292
- buffer.push(value), waiting.forEach((w) => w.resolve()), waiting = [];
293
- done = !0, waiting.forEach((w) => w.resolve());
294
- })();
295
- async function* makeIterator() {
296
- let i = 0;
297
- for (; ; )
298
- if (i < buffer.length)
299
- yield buffer[i++];
300
- else {
301
- if (done)
302
- return;
303
- await new Promise((resolve) => waiting.push({ resolve }));
288
+ const state = Array.from({ length: branches }, () => ({
289
+ active: !0,
290
+ consumed: !0
291
+ }));
292
+ if (!state.length) return [];
293
+ const iterator = source[Symbol.asyncIterator]?.() ?? source[Symbol.iterator]();
294
+ let active = state.length, current, hasValue = !1, remaining = 0, done = !1, failed = !1, sourceError, pulling, waiting = [];
295
+ const wake = () => {
296
+ const pending = waiting;
297
+ waiting = [];
298
+ for (const resolve of pending) resolve();
299
+ }, wait = () => new Promise((resolve) => waiting.push(resolve)), pull = () => {
300
+ pulling ??= Promise.resolve().then(() => iterator.next()).then((result) => {
301
+ if (result.done || !active || done) {
302
+ done = !0;
303
+ return;
304
304
  }
305
- }
306
- return Array.from({ length: branches }, makeIterator);
305
+ current = result.value, hasValue = !0, remaining = active;
306
+ for (const branch of state)
307
+ branch.active && (branch.consumed = !1);
308
+ }).catch((error) => {
309
+ !active || done || (failed = done = !0, sourceError = error);
310
+ }).finally(() => {
311
+ pulling = void 0, wake();
312
+ });
313
+ }, stop = () => {
314
+ if (!done) {
315
+ done = !0, wake();
316
+ try {
317
+ Promise.resolve(iterator.return?.()).catch(() => {
318
+ });
319
+ } catch {
320
+ }
321
+ }
322
+ }, close = (index) => {
323
+ const branch = state[index];
324
+ return branch.active ? (branch.active = !1, active--, hasValue && !branch.consumed && --remaining === 0 && (hasValue = !1, wake()), !0) : !1;
325
+ }, next = async (index) => {
326
+ const branch = state[index];
327
+ for (; branch.active; ) {
328
+ if (failed)
329
+ throw close(index), sourceError;
330
+ if (hasValue && !branch.consumed) {
331
+ branch.consumed = !0;
332
+ const result = { done: !1, value: current };
333
+ return --remaining === 0 && (hasValue = !1, wake()), result;
334
+ }
335
+ if (done) {
336
+ close(index);
337
+ break;
338
+ }
339
+ hasValue || pull(), await wait();
340
+ }
341
+ return { done: !0, value: void 0 };
342
+ };
343
+ return state.map((_, index) => ({
344
+ next: () => next(index),
345
+ async return(finalValue) {
346
+ return close(index) && (index === 0 || !active) && stop(), { done: !0, value: finalValue };
347
+ },
348
+ [Symbol.asyncIterator]() {
349
+ return this;
350
+ }
351
+ }));
307
352
  }
308
353
  // Annotate the CommonJS export names for ESM import in node:
309
354
  0 && (module.exports = {
@@ -258,25 +258,70 @@ const createResponseHandler = (handler) => {
258
258
  };
259
259
  };
260
260
  async function tee(source, branches = 2) {
261
- const buffer = [];
262
- let done = !1, waiting = [];
263
- (async () => {
264
- for await (const value of source)
265
- buffer.push(value), waiting.forEach((w) => w.resolve()), waiting = [];
266
- done = !0, waiting.forEach((w) => w.resolve());
267
- })();
268
- async function* makeIterator() {
269
- let i = 0;
270
- for (; ; )
271
- if (i < buffer.length)
272
- yield buffer[i++];
273
- else {
274
- if (done)
275
- return;
276
- await new Promise((resolve) => waiting.push({ resolve }));
261
+ const state = Array.from({ length: branches }, () => ({
262
+ active: !0,
263
+ consumed: !0
264
+ }));
265
+ if (!state.length) return [];
266
+ const iterator = source[Symbol.asyncIterator]?.() ?? source[Symbol.iterator]();
267
+ let active = state.length, current, hasValue = !1, remaining = 0, done = !1, failed = !1, sourceError, pulling, waiting = [];
268
+ const wake = () => {
269
+ const pending = waiting;
270
+ waiting = [];
271
+ for (const resolve of pending) resolve();
272
+ }, wait = () => new Promise((resolve) => waiting.push(resolve)), pull = () => {
273
+ pulling ??= Promise.resolve().then(() => iterator.next()).then((result) => {
274
+ if (result.done || !active || done) {
275
+ done = !0;
276
+ return;
277
277
  }
278
- }
279
- return Array.from({ length: branches }, makeIterator);
278
+ current = result.value, hasValue = !0, remaining = active;
279
+ for (const branch of state)
280
+ branch.active && (branch.consumed = !1);
281
+ }).catch((error) => {
282
+ !active || done || (failed = done = !0, sourceError = error);
283
+ }).finally(() => {
284
+ pulling = void 0, wake();
285
+ });
286
+ }, stop = () => {
287
+ if (!done) {
288
+ done = !0, wake();
289
+ try {
290
+ Promise.resolve(iterator.return?.()).catch(() => {
291
+ });
292
+ } catch {
293
+ }
294
+ }
295
+ }, close = (index) => {
296
+ const branch = state[index];
297
+ return branch.active ? (branch.active = !1, active--, hasValue && !branch.consumed && --remaining === 0 && (hasValue = !1, wake()), !0) : !1;
298
+ }, next = async (index) => {
299
+ const branch = state[index];
300
+ for (; branch.active; ) {
301
+ if (failed)
302
+ throw close(index), sourceError;
303
+ if (hasValue && !branch.consumed) {
304
+ branch.consumed = !0;
305
+ const result = { done: !1, value: current };
306
+ return --remaining === 0 && (hasValue = !1, wake()), result;
307
+ }
308
+ if (done) {
309
+ close(index);
310
+ break;
311
+ }
312
+ hasValue || pull(), await wait();
313
+ }
314
+ return { done: !0, value: void 0 };
315
+ };
316
+ return state.map((_, index) => ({
317
+ next: () => next(index),
318
+ async return(finalValue) {
319
+ return close(index) && (index === 0 || !active) && stop(), { done: !0, value: finalValue };
320
+ },
321
+ [Symbol.asyncIterator]() {
322
+ return this;
323
+ }
324
+ }));
280
325
  }
281
326
  export {
282
327
  createResponseHandler,
@@ -54,62 +54,10 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
54
54
  `;
55
55
  },
56
56
  formData(isOptional) {
57
- let fnLiteral = `
58
- c.body={}
59
- `;
57
+ let fnLiteral = "";
60
58
  return isOptional ? fnLiteral += "let form;try{form=await c.request.formData()}catch{}" : fnLiteral += `const form=await c.request.formData()
61
- `, fnLiteral + `const dangerousKeys=new Set(['__proto__','constructor','prototype'])
62
- const isDangerousKey=(k)=>{if(dangerousKeys.has(k))return true;const m=k.match(/^(.+)\\[(\\d+)\\]$/);return m?dangerousKeys.has(m[1]):false}
63
- const parseArrayKey=(k)=>{const m=k.match(/^(.+)\\[(\\d+)\\]$/);return m?{name:m[1],index:parseInt(m[2],10)}:null}
64
- const grouped=new Map()
65
- form.forEach((v,k)=>{const l=grouped.get(k);if(l)l.push(v);else grouped.set(k,[v])})
66
- for(const [key,value] of grouped){if(c.body[key])continue
67
- let finalValue
68
- if(value.length===1){
69
- const sv=value[0]
70
- if(typeof sv==='string'&&(sv.charCodeAt(0)===123||sv.charCodeAt(0)===91)){
71
- try{
72
- const p=JSON.parse(sv)
73
- if(p&&typeof p==='object')finalValue=p
74
- }catch{}
75
- }
76
- if(finalValue===undefined)finalValue=sv
77
- }else finalValue=value
78
- if(Array.isArray(finalValue)){
79
- const stringValue=finalValue.find((entry)=>typeof entry==='string')
80
- const files=typeof File==='undefined'?[]:finalValue.filter((entry)=>entry instanceof File)
81
- if(stringValue&&files.length&&stringValue.charCodeAt(0)===123){
82
- try{
83
- const parsed=JSON.parse(stringValue)
84
- if(parsed&&typeof parsed==='object'&&!Array.isArray(parsed)){
85
- if(!('file' in parsed)&&files.length===1)parsed.file=files[0]
86
- else if(!('files' in parsed)&&files.length>1)parsed.files=files
87
- finalValue=parsed
88
- }
89
- }catch{}
90
- }
91
- }
92
- if(key.includes('.')||key.includes('[')){const keys=key.split('.')
93
- const lastKey=keys.pop()
94
- if(isDangerousKey(lastKey)||keys.some(isDangerousKey))continue
95
- let current=c.body
96
- for(const k of keys){const arrayInfo=parseArrayKey(k)
97
- if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
98
- const existing=current[arrayInfo.name][arrayInfo.index]
99
- const isFile=typeof File!=='undefined'&&existing instanceof File
100
- if(!existing||typeof existing!=='object'||Array.isArray(existing)||isFile){
101
- let parsed
102
- if(typeof existing==='string'&&existing.charCodeAt(0)===123){
103
- try{parsed=JSON.parse(existing)
104
- if(!parsed||typeof parsed!=='object'||Array.isArray(parsed))parsed=undefined}catch{}
105
- }
106
- current[arrayInfo.name][arrayInfo.index]=parsed||{}
107
- }
108
- current=current[arrayInfo.name][arrayInfo.index]}else{if(!current[k]||typeof current[k]!=='object')current[k]={}
109
- current=current[k]}}
110
- const arrayInfo=parseArrayKey(lastKey)
111
- if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
112
- current[arrayInfo.name][arrayInfo.index]=finalValue}else{current[lastKey]=finalValue}}else c.body[key]=finalValue}`;
59
+ `, fnLiteral + `c.body=parseFormData(form)
60
+ `;
113
61
  }
114
62
  }
115
63
  },
@@ -39,62 +39,10 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
39
39
  `;
40
40
  },
41
41
  formData(isOptional) {
42
- let fnLiteral = `
43
- c.body={}
44
- `;
42
+ let fnLiteral = "";
45
43
  return isOptional ? fnLiteral += "let form;try{form=await c.request.formData()}catch{}" : fnLiteral += `const form=await c.request.formData()
46
- `, fnLiteral + `const dangerousKeys=new Set(['__proto__','constructor','prototype'])
47
- const isDangerousKey=(k)=>{if(dangerousKeys.has(k))return true;const m=k.match(/^(.+)\\[(\\d+)\\]$/);return m?dangerousKeys.has(m[1]):false}
48
- const parseArrayKey=(k)=>{const m=k.match(/^(.+)\\[(\\d+)\\]$/);return m?{name:m[1],index:parseInt(m[2],10)}:null}
49
- const grouped=new Map()
50
- form.forEach((v,k)=>{const l=grouped.get(k);if(l)l.push(v);else grouped.set(k,[v])})
51
- for(const [key,value] of grouped){if(c.body[key])continue
52
- let finalValue
53
- if(value.length===1){
54
- const sv=value[0]
55
- if(typeof sv==='string'&&(sv.charCodeAt(0)===123||sv.charCodeAt(0)===91)){
56
- try{
57
- const p=JSON.parse(sv)
58
- if(p&&typeof p==='object')finalValue=p
59
- }catch{}
60
- }
61
- if(finalValue===undefined)finalValue=sv
62
- }else finalValue=value
63
- if(Array.isArray(finalValue)){
64
- const stringValue=finalValue.find((entry)=>typeof entry==='string')
65
- const files=typeof File==='undefined'?[]:finalValue.filter((entry)=>entry instanceof File)
66
- if(stringValue&&files.length&&stringValue.charCodeAt(0)===123){
67
- try{
68
- const parsed=JSON.parse(stringValue)
69
- if(parsed&&typeof parsed==='object'&&!Array.isArray(parsed)){
70
- if(!('file' in parsed)&&files.length===1)parsed.file=files[0]
71
- else if(!('files' in parsed)&&files.length>1)parsed.files=files
72
- finalValue=parsed
73
- }
74
- }catch{}
75
- }
76
- }
77
- if(key.includes('.')||key.includes('[')){const keys=key.split('.')
78
- const lastKey=keys.pop()
79
- if(isDangerousKey(lastKey)||keys.some(isDangerousKey))continue
80
- let current=c.body
81
- for(const k of keys){const arrayInfo=parseArrayKey(k)
82
- if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
83
- const existing=current[arrayInfo.name][arrayInfo.index]
84
- const isFile=typeof File!=='undefined'&&existing instanceof File
85
- if(!existing||typeof existing!=='object'||Array.isArray(existing)||isFile){
86
- let parsed
87
- if(typeof existing==='string'&&existing.charCodeAt(0)===123){
88
- try{parsed=JSON.parse(existing)
89
- if(!parsed||typeof parsed!=='object'||Array.isArray(parsed))parsed=undefined}catch{}
90
- }
91
- current[arrayInfo.name][arrayInfo.index]=parsed||{}
92
- }
93
- current=current[arrayInfo.name][arrayInfo.index]}else{if(!current[k]||typeof current[k]!=='object')current[k]={}
94
- current=current[k]}}
95
- const arrayInfo=parseArrayKey(lastKey)
96
- if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
97
- current[arrayInfo.name][arrayInfo.index]=finalValue}else{current[lastKey]=finalValue}}else c.body[key]=finalValue}`;
44
+ `, fnLiteral + `c.body=parseFormData(form)
45
+ `;
98
46
  }
99
47
  }
100
48
  },