elysia 1.4.22 → 1.4.24

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 (41) hide show
  1. package/dist/adapter/bun/handler-native.js +1 -1
  2. package/dist/adapter/bun/handler-native.mjs +1 -1
  3. package/dist/adapter/bun/handler.js +27 -1
  4. package/dist/adapter/bun/handler.mjs +27 -1
  5. package/dist/adapter/cloudflare-worker/index.d.ts +0 -1
  6. package/dist/adapter/cloudflare-worker/index.js +2 -16
  7. package/dist/adapter/cloudflare-worker/index.mjs +1 -14
  8. package/dist/adapter/utils.d.ts +2 -0
  9. package/dist/adapter/utils.js +33 -39
  10. package/dist/adapter/utils.mjs +31 -39
  11. package/dist/adapter/web-standard/handler.js +24 -0
  12. package/dist/adapter/web-standard/handler.mjs +24 -0
  13. package/dist/adapter/web-standard/index.js +50 -3
  14. package/dist/adapter/web-standard/index.mjs +50 -3
  15. package/dist/bun/index.js +91 -45
  16. package/dist/bun/index.js.map +18 -19
  17. package/dist/compose.js +29 -21
  18. package/dist/compose.mjs +30 -21
  19. package/dist/cookies.d.ts +7 -3
  20. package/dist/cookies.js +12 -10
  21. package/dist/cookies.mjs +12 -10
  22. package/dist/dynamic-handle.js +122 -32
  23. package/dist/dynamic-handle.mjs +122 -31
  24. package/dist/error.d.ts +1 -1
  25. package/dist/error.js +4 -4
  26. package/dist/error.mjs +4 -4
  27. package/dist/index.d.ts +6 -6
  28. package/dist/schema.d.ts +2 -1
  29. package/dist/schema.js +28 -2
  30. package/dist/schema.mjs +27 -2
  31. package/dist/sucrose.d.ts +3 -3
  32. package/dist/sucrose.js +7 -7
  33. package/dist/sucrose.mjs +5 -6
  34. package/dist/types.d.ts +3 -3
  35. package/dist/universal/utils.d.ts +1 -0
  36. package/dist/universal/utils.js +14 -0
  37. package/dist/universal/utils.mjs +13 -0
  38. package/dist/utils.d.ts +10 -1
  39. package/dist/utils.js +11 -9
  40. package/dist/utils.mjs +11 -8
  41. package/package.json +2 -2
@@ -23,7 +23,7 @@ const createNativeStaticHandler = (handle, hooks, set) => {
23
23
  if (typeof handle == "function" || handle instanceof Blob) return;
24
24
  if ((0, import_index.isHTMLBundle)(handle)) return () => handle;
25
25
  const response = (0, import_handler.mapResponse)(
26
- handle,
26
+ handle instanceof Response ? handle.clone() : handle instanceof Promise ? handle.then((x) => x instanceof Response ? x.clone() : x) : handle,
27
27
  set ?? {
28
28
  headers: {}
29
29
  }
@@ -4,7 +4,7 @@ const createNativeStaticHandler = (handle, hooks, set) => {
4
4
  if (typeof handle == "function" || handle instanceof Blob) return;
5
5
  if (isHTMLBundle(handle)) return () => handle;
6
6
  const response = mapResponse(
7
- handle,
7
+ handle instanceof Response ? handle.clone() : handle instanceof Promise ? handle.then((x) => x instanceof Response ? x.clone() : x) : handle,
8
8
  set ?? {
9
9
  headers: {}
10
10
  }
@@ -84,7 +84,15 @@ const mapResponse = (response, set, request) => {
84
84
  )
85
85
  return handleStream(response, set, request);
86
86
  if (typeof response?.then == "function")
87
- return response.then((x) => mapResponse(x, set));
87
+ return response.then(
88
+ (x) => mapResponse(x, set)
89
+ );
90
+ if (Array.isArray(response))
91
+ return new Response(JSON.stringify(response), {
92
+ headers: {
93
+ "Content-Type": "application/json"
94
+ }
95
+ });
88
96
  if (typeof response?.toResponse == "function")
89
97
  return mapResponse(response.toResponse(), set);
90
98
  if ("charCodeAt" in response) {
@@ -168,6 +176,12 @@ const mapResponse = (response, set, request) => {
168
176
  );
169
177
  if (typeof response?.toResponse == "function")
170
178
  return mapEarlyResponse(response.toResponse(), set);
179
+ if (Array.isArray(response))
180
+ return new Response(JSON.stringify(response), {
181
+ headers: {
182
+ "Content-Type": "application/json"
183
+ }
184
+ });
171
185
  if ("charCodeAt" in response) {
172
186
  const code = response.charCodeAt(0);
173
187
  if (code === 123 || code === 91)
@@ -244,6 +258,12 @@ const mapResponse = (response, set, request) => {
244
258
  );
245
259
  if (typeof response?.toResponse == "function")
246
260
  return mapEarlyResponse(response.toResponse(), set);
261
+ if (Array.isArray(response))
262
+ return new Response(JSON.stringify(response), {
263
+ headers: {
264
+ "Content-Type": "application/json"
265
+ }
266
+ });
247
267
  if ("charCodeAt" in response) {
248
268
  const code = response.charCodeAt(0);
249
269
  if (code === 123 || code === 91)
@@ -328,6 +348,12 @@ const mapResponse = (response, set, request) => {
328
348
  );
329
349
  if (typeof response?.toResponse == "function")
330
350
  return mapCompactResponse(response.toResponse());
351
+ if (Array.isArray(response))
352
+ return new Response(JSON.stringify(response), {
353
+ headers: {
354
+ "Content-Type": "application/json"
355
+ }
356
+ });
331
357
  if ("charCodeAt" in response) {
332
358
  const code = response.charCodeAt(0);
333
359
  if (code === 123 || code === 91)
@@ -68,7 +68,15 @@ const mapResponse = (response, set, request) => {
68
68
  )
69
69
  return handleStream(response, set, request);
70
70
  if (typeof response?.then == "function")
71
- return response.then((x) => mapResponse(x, set));
71
+ return response.then(
72
+ (x) => mapResponse(x, set)
73
+ );
74
+ if (Array.isArray(response))
75
+ return new Response(JSON.stringify(response), {
76
+ headers: {
77
+ "Content-Type": "application/json"
78
+ }
79
+ });
72
80
  if (typeof response?.toResponse == "function")
73
81
  return mapResponse(response.toResponse(), set);
74
82
  if ("charCodeAt" in response) {
@@ -152,6 +160,12 @@ const mapResponse = (response, set, request) => {
152
160
  );
153
161
  if (typeof response?.toResponse == "function")
154
162
  return mapEarlyResponse(response.toResponse(), set);
163
+ if (Array.isArray(response))
164
+ return new Response(JSON.stringify(response), {
165
+ headers: {
166
+ "Content-Type": "application/json"
167
+ }
168
+ });
155
169
  if ("charCodeAt" in response) {
156
170
  const code = response.charCodeAt(0);
157
171
  if (code === 123 || code === 91)
@@ -228,6 +242,12 @@ const mapResponse = (response, set, request) => {
228
242
  );
229
243
  if (typeof response?.toResponse == "function")
230
244
  return mapEarlyResponse(response.toResponse(), set);
245
+ if (Array.isArray(response))
246
+ return new Response(JSON.stringify(response), {
247
+ headers: {
248
+ "Content-Type": "application/json"
249
+ }
250
+ });
231
251
  if ("charCodeAt" in response) {
232
252
  const code = response.charCodeAt(0);
233
253
  if (code === 123 || code === 91)
@@ -312,6 +332,12 @@ const mapResponse = (response, set, request) => {
312
332
  );
313
333
  if (typeof response?.toResponse == "function")
314
334
  return mapCompactResponse(response.toResponse());
335
+ if (Array.isArray(response))
336
+ return new Response(JSON.stringify(response), {
337
+ headers: {
338
+ "Content-Type": "application/json"
339
+ }
340
+ });
315
341
  if ("charCodeAt" in response) {
316
342
  const code = response.charCodeAt(0);
317
343
  if (code === 123 || code === 91)
@@ -1,5 +1,4 @@
1
1
  import { ElysiaAdapter } from '../..';
2
- export declare function isCloudflareWorker(): boolean;
3
2
  /**
4
3
  * Cloudflare Adapter (Experimental)
5
4
  * @see https://elysiajs.com/integrations/cloudflare-worker
@@ -15,23 +15,10 @@ var __export = (target, all) => {
15
15
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
16
16
  var cloudflare_worker_exports = {};
17
17
  __export(cloudflare_worker_exports, {
18
- CloudflareAdapter: () => CloudflareAdapter,
19
- isCloudflareWorker: () => isCloudflareWorker
18
+ CloudflareAdapter: () => CloudflareAdapter
20
19
  });
21
20
  module.exports = __toCommonJS(cloudflare_worker_exports);
22
21
  var import_web_standard = require('../web-standard/index.js'), import_compose = require('../../compose.js');
23
- function isCloudflareWorker() {
24
- try {
25
- if (
26
- // @ts-ignore
27
- typeof caches < "u" && // @ts-ignore
28
- typeof caches.default < "u" || typeof WebSocketPair < "u"
29
- ) return !0;
30
- } catch {
31
- return !1;
32
- }
33
- return !1;
34
- }
35
22
  const CloudflareAdapter = {
36
23
  ...import_web_standard.WebStandardAdapter,
37
24
  name: "cloudflare-worker",
@@ -68,6 +55,5 @@ const error404={clone:()=>new Response(error404Message,{status:404})}
68
55
  };
69
56
  // Annotate the CommonJS export names for ESM import in node:
70
57
  0 && (module.exports = {
71
- CloudflareAdapter,
72
- isCloudflareWorker
58
+ CloudflareAdapter
73
59
  });
@@ -1,17 +1,5 @@
1
1
  import { WebStandardAdapter } from "../web-standard/index.mjs";
2
2
  import { composeErrorHandler } from "../../compose.mjs";
3
- function isCloudflareWorker() {
4
- try {
5
- if (
6
- // @ts-ignore
7
- typeof caches < "u" && // @ts-ignore
8
- typeof caches.default < "u" || typeof WebSocketPair < "u"
9
- ) return !0;
10
- } catch {
11
- return !1;
12
- }
13
- return !1;
14
- }
15
3
  const CloudflareAdapter = {
16
4
  ...WebStandardAdapter,
17
5
  name: "cloudflare-worker",
@@ -47,6 +35,5 @@ const error404={clone:()=>new Response(error404Message,{status:404})}
47
35
  }
48
36
  };
49
37
  export {
50
- CloudflareAdapter,
51
- isCloudflareWorker
38
+ CloudflareAdapter
52
39
  };
@@ -15,6 +15,8 @@ interface CreateHandlerParameter {
15
15
  export declare const createStreamHandler: ({ mapResponse, mapCompactResponse }: CreateHandlerParameter) => (generator: Generator | AsyncGenerator | ReadableStream, set?: Context["set"], request?: Request, skipFormat?: boolean) => Promise<Response>;
16
16
  export declare function streamResponse(response: Response): AsyncGenerator<string, void, unknown>;
17
17
  export declare const handleSet: (set: Context["set"]) => void;
18
+ export declare function mergeHeaders(responseHeaders: Headers, setHeaders: Context['set']['headers']): Headers;
19
+ export declare function mergeStatus(responseStatus: number, setStatus: Context['set']['status']): number | undefined;
18
20
  export declare const createResponseHandler: (handler: CreateHandlerParameter) => (response: Response, set: Context["set"], request?: Request) => any;
19
21
  export declare function tee<T>(source: AsyncIterable<T>, branches?: number): Promise<AsyncIterableIterator<T>[]>;
20
22
  export {};
@@ -19,13 +19,15 @@ __export(utils_exports, {
19
19
  createStreamHandler: () => createStreamHandler,
20
20
  handleFile: () => handleFile,
21
21
  handleSet: () => handleSet,
22
+ mergeHeaders: () => mergeHeaders,
23
+ mergeStatus: () => mergeStatus,
22
24
  parseSetCookies: () => parseSetCookies,
23
25
  responseToSetHeaders: () => responseToSetHeaders,
24
26
  streamResponse: () => streamResponse,
25
27
  tee: () => tee
26
28
  });
27
29
  module.exports = __toCommonJS(utils_exports);
28
- var import_cookies = require('../cookies.js'), import_utils = require('../utils.js'), import_utils2 = require('../universal/utils.js'), import_universal = require('../universal/index.js');
30
+ var import_cookies = require('../cookies.js'), import_utils = require('../utils.js'), import_universal = require('../universal/index.js'), import_utils2 = require('../universal/utils.js');
29
31
  const handleFile = (response, set) => {
30
32
  if (!import_utils2.isBun && response instanceof Promise)
31
33
  return response.then((res) => handleFile(res, set));
@@ -195,48 +197,38 @@ const handleSet = (set) => {
195
197
  new Headers(set.headers),
196
198
  set.headers["set-cookie"]
197
199
  ));
198
- }, createResponseHandler = (handler) => {
200
+ };
201
+ function mergeHeaders(responseHeaders, setHeaders) {
202
+ const headers = new Headers(responseHeaders);
203
+ if (setHeaders instanceof Headers)
204
+ for (const key of setHeaders.keys())
205
+ if (key === "set-cookie") {
206
+ if (headers.has("set-cookie")) continue;
207
+ for (const cookie of setHeaders.getSetCookie())
208
+ headers.append("set-cookie", cookie);
209
+ } else responseHeaders.has(key) || headers.set(key, setHeaders?.get(key) ?? "");
210
+ else
211
+ for (const key in setHeaders)
212
+ key === "set-cookie" ? headers.append(key, setHeaders[key]) : responseHeaders.has(key) || headers.set(key, setHeaders[key]);
213
+ return headers;
214
+ }
215
+ function mergeStatus(responseStatus, setStatus) {
216
+ return typeof setStatus == "string" && (setStatus = import_utils.StatusMap[setStatus]), responseStatus === 200 ? setStatus : responseStatus;
217
+ }
218
+ const createResponseHandler = (handler) => {
199
219
  const handleStream = createStreamHandler(handler);
200
220
  return (response, set, request) => {
201
- let isCookieSet = !1;
202
- if (set.headers instanceof Headers)
203
- for (const key of set.headers.keys())
204
- if (key === "set-cookie") {
205
- if (isCookieSet) continue;
206
- isCookieSet = !0;
207
- for (const cookie of set.headers.getSetCookie())
208
- response.headers.append("set-cookie", cookie);
209
- } else response.headers.has(key) || response.headers.set(key, set.headers?.get(key) ?? "");
210
- else
211
- for (const key in set.headers)
212
- key === "set-cookie" ? response.headers.append(
213
- key,
214
- set.headers[key]
215
- ) : response.headers.has(key) || response.headers.set(
216
- key,
217
- set.headers[key]
218
- );
219
- const status = set.status ?? 200;
220
- if (response.status !== status && status !== 200 && (response.status <= 300 || response.status > 400)) {
221
- const newResponse = new Response(response.body, {
222
- headers: response.headers,
223
- status: set.status
224
- });
225
- return !newResponse.headers.has("content-length") && newResponse.headers.get("transfer-encoding") === "chunked" ? handleStream(
226
- streamResponse(newResponse),
227
- responseToSetHeaders(newResponse, set),
228
- request,
229
- !0
230
- // skipFormat: don't auto-format SSE for pre-formatted Response
231
- ) : newResponse;
232
- }
233
- return !response.headers.has("content-length") && response.headers.get("transfer-encoding") === "chunked" ? handleStream(
234
- streamResponse(response),
235
- responseToSetHeaders(response, set),
221
+ const newResponse = new Response(response.body, {
222
+ headers: mergeHeaders(response.headers, set.headers),
223
+ status: mergeStatus(response.status, set.status)
224
+ });
225
+ return !newResponse.headers.has("content-length") && newResponse.headers.get("transfer-encoding") === "chunked" ? handleStream(
226
+ streamResponse(newResponse),
227
+ responseToSetHeaders(newResponse, set),
236
228
  request,
237
229
  !0
238
- // skipFormat: don't auto-format SSE for pre-formatted Response
239
- ) : response;
230
+ // don't auto-format SSE for pre-formatted Response
231
+ ) : newResponse;
240
232
  };
241
233
  };
242
234
  async function tee(source, branches = 2) {
@@ -266,6 +258,8 @@ async function tee(source, branches = 2) {
266
258
  createStreamHandler,
267
259
  handleFile,
268
260
  handleSet,
261
+ mergeHeaders,
262
+ mergeStatus,
269
263
  parseSetCookies,
270
264
  responseToSetHeaders,
271
265
  streamResponse,
@@ -1,7 +1,7 @@
1
1
  import { serializeCookie } from "../cookies.mjs";
2
2
  import { hasHeaderShorthand, isNotEmpty, StatusMap } from "../utils.mjs";
3
- import { isBun } from "../universal/utils.mjs";
4
3
  import { env } from "../universal/index.mjs";
4
+ import { isBun } from "../universal/utils.mjs";
5
5
  const handleFile = (response, set) => {
6
6
  if (!isBun && response instanceof Promise)
7
7
  return response.then((res) => handleFile(res, set));
@@ -171,48 +171,38 @@ const handleSet = (set) => {
171
171
  new Headers(set.headers),
172
172
  set.headers["set-cookie"]
173
173
  ));
174
- }, createResponseHandler = (handler) => {
174
+ };
175
+ function mergeHeaders(responseHeaders, setHeaders) {
176
+ const headers = new Headers(responseHeaders);
177
+ if (setHeaders instanceof Headers)
178
+ for (const key of setHeaders.keys())
179
+ if (key === "set-cookie") {
180
+ if (headers.has("set-cookie")) continue;
181
+ for (const cookie of setHeaders.getSetCookie())
182
+ headers.append("set-cookie", cookie);
183
+ } else responseHeaders.has(key) || headers.set(key, setHeaders?.get(key) ?? "");
184
+ else
185
+ for (const key in setHeaders)
186
+ key === "set-cookie" ? headers.append(key, setHeaders[key]) : responseHeaders.has(key) || headers.set(key, setHeaders[key]);
187
+ return headers;
188
+ }
189
+ function mergeStatus(responseStatus, setStatus) {
190
+ return typeof setStatus == "string" && (setStatus = StatusMap[setStatus]), responseStatus === 200 ? setStatus : responseStatus;
191
+ }
192
+ const createResponseHandler = (handler) => {
175
193
  const handleStream = createStreamHandler(handler);
176
194
  return (response, set, request) => {
177
- let isCookieSet = !1;
178
- if (set.headers instanceof Headers)
179
- for (const key of set.headers.keys())
180
- if (key === "set-cookie") {
181
- if (isCookieSet) continue;
182
- isCookieSet = !0;
183
- for (const cookie of set.headers.getSetCookie())
184
- response.headers.append("set-cookie", cookie);
185
- } else response.headers.has(key) || response.headers.set(key, set.headers?.get(key) ?? "");
186
- else
187
- for (const key in set.headers)
188
- key === "set-cookie" ? response.headers.append(
189
- key,
190
- set.headers[key]
191
- ) : response.headers.has(key) || response.headers.set(
192
- key,
193
- set.headers[key]
194
- );
195
- const status = set.status ?? 200;
196
- if (response.status !== status && status !== 200 && (response.status <= 300 || response.status > 400)) {
197
- const newResponse = new Response(response.body, {
198
- headers: response.headers,
199
- status: set.status
200
- });
201
- return !newResponse.headers.has("content-length") && newResponse.headers.get("transfer-encoding") === "chunked" ? handleStream(
202
- streamResponse(newResponse),
203
- responseToSetHeaders(newResponse, set),
204
- request,
205
- !0
206
- // skipFormat: don't auto-format SSE for pre-formatted Response
207
- ) : newResponse;
208
- }
209
- return !response.headers.has("content-length") && response.headers.get("transfer-encoding") === "chunked" ? handleStream(
210
- streamResponse(response),
211
- responseToSetHeaders(response, set),
195
+ const newResponse = new Response(response.body, {
196
+ headers: mergeHeaders(response.headers, set.headers),
197
+ status: mergeStatus(response.status, set.status)
198
+ });
199
+ return !newResponse.headers.has("content-length") && newResponse.headers.get("transfer-encoding") === "chunked" ? handleStream(
200
+ streamResponse(newResponse),
201
+ responseToSetHeaders(newResponse, set),
212
202
  request,
213
203
  !0
214
- // skipFormat: don't auto-format SSE for pre-formatted Response
215
- ) : response;
204
+ // don't auto-format SSE for pre-formatted Response
205
+ ) : newResponse;
216
206
  };
217
207
  };
218
208
  async function tee(source, branches = 2) {
@@ -241,6 +231,8 @@ export {
241
231
  createStreamHandler,
242
232
  handleFile,
243
233
  handleSet,
234
+ mergeHeaders,
235
+ mergeStatus,
244
236
  parseSetCookies,
245
237
  responseToSetHeaders,
246
238
  streamResponse,
@@ -95,6 +95,12 @@ const handleElysiaFile = (file, set = {
95
95
  return response.then(
96
96
  (x) => mapResponse(x, set)
97
97
  );
98
+ if (Array.isArray(response))
99
+ return new Response(JSON.stringify(response), {
100
+ headers: {
101
+ "Content-Type": "application/json"
102
+ }
103
+ });
98
104
  if (typeof response?.toResponse == "function")
99
105
  return mapResponse(response.toResponse(), set);
100
106
  if ("charCodeAt" in response) {
@@ -178,6 +184,12 @@ const handleElysiaFile = (file, set = {
178
184
  );
179
185
  if (typeof response?.toResponse == "function")
180
186
  return mapEarlyResponse(response.toResponse(), set);
187
+ if (Array.isArray(response))
188
+ return new Response(JSON.stringify(response), {
189
+ headers: {
190
+ "Content-Type": "application/json"
191
+ }
192
+ });
181
193
  if ("charCodeAt" in response) {
182
194
  const code = response.charCodeAt(0);
183
195
  if (code === 123 || code === 91)
@@ -254,6 +266,12 @@ const handleElysiaFile = (file, set = {
254
266
  );
255
267
  if (typeof response?.toResponse == "function")
256
268
  return mapEarlyResponse(response.toResponse(), set);
269
+ if (Array.isArray(response))
270
+ return new Response(JSON.stringify(response), {
271
+ headers: {
272
+ "Content-Type": "application/json"
273
+ }
274
+ });
257
275
  if ("charCodeAt" in response) {
258
276
  const code = response.charCodeAt(0);
259
277
  if (code === 123 || code === 91)
@@ -342,6 +360,12 @@ const handleElysiaFile = (file, set = {
342
360
  );
343
361
  if (typeof response?.toResponse == "function")
344
362
  return mapCompactResponse(response.toResponse());
363
+ if (Array.isArray(response))
364
+ return new Response(JSON.stringify(response), {
365
+ headers: {
366
+ "Content-Type": "application/json"
367
+ }
368
+ });
345
369
  if ("charCodeAt" in response) {
346
370
  const code = response.charCodeAt(0);
347
371
  if (code === 123 || code === 91)
@@ -80,6 +80,12 @@ const handleElysiaFile = (file, set = {
80
80
  return response.then(
81
81
  (x) => mapResponse(x, set)
82
82
  );
83
+ if (Array.isArray(response))
84
+ return new Response(JSON.stringify(response), {
85
+ headers: {
86
+ "Content-Type": "application/json"
87
+ }
88
+ });
83
89
  if (typeof response?.toResponse == "function")
84
90
  return mapResponse(response.toResponse(), set);
85
91
  if ("charCodeAt" in response) {
@@ -163,6 +169,12 @@ const handleElysiaFile = (file, set = {
163
169
  );
164
170
  if (typeof response?.toResponse == "function")
165
171
  return mapEarlyResponse(response.toResponse(), set);
172
+ if (Array.isArray(response))
173
+ return new Response(JSON.stringify(response), {
174
+ headers: {
175
+ "Content-Type": "application/json"
176
+ }
177
+ });
166
178
  if ("charCodeAt" in response) {
167
179
  const code = response.charCodeAt(0);
168
180
  if (code === 123 || code === 91)
@@ -239,6 +251,12 @@ const handleElysiaFile = (file, set = {
239
251
  );
240
252
  if (typeof response?.toResponse == "function")
241
253
  return mapEarlyResponse(response.toResponse(), set);
254
+ if (Array.isArray(response))
255
+ return new Response(JSON.stringify(response), {
256
+ headers: {
257
+ "Content-Type": "application/json"
258
+ }
259
+ });
242
260
  if ("charCodeAt" in response) {
243
261
  const code = response.charCodeAt(0);
244
262
  if (code === 123 || code === 91)
@@ -327,6 +345,12 @@ const handleElysiaFile = (file, set = {
327
345
  );
328
346
  if (typeof response?.toResponse == "function")
329
347
  return mapCompactResponse(response.toResponse());
348
+ if (Array.isArray(response))
349
+ return new Response(JSON.stringify(response), {
350
+ headers: {
351
+ "Content-Type": "application/json"
352
+ }
353
+ });
330
354
  if ("charCodeAt" in response) {
331
355
  const code = response.charCodeAt(0);
332
356
  if (code === 123 || code === 91)
@@ -58,10 +58,57 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
58
58
  c.body={}
59
59
  `;
60
60
  return isOptional ? fnLiteral += "let form;try{form=await c.request.formData()}catch{}" : fnLiteral += `const form=await c.request.formData()
61
- `, fnLiteral + `for(const key of form.keys()){if(c.body[key]) continue
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
+ for(const key of form.keys()){if(c.body[key])continue
62
65
  const value=form.getAll(key)
63
- if(value.length===1)c.body[key]=value[0]
64
- else c.body[key]=value}`;
66
+ let finalValue
67
+ if(value.length===1){
68
+ const sv=value[0]
69
+ if(typeof sv==='string'&&(sv.charCodeAt(0)===123||sv.charCodeAt(0)===91)){
70
+ try{
71
+ const p=JSON.parse(sv)
72
+ if(p&&typeof p==='object')finalValue=p
73
+ }catch{}
74
+ }
75
+ if(finalValue===undefined)finalValue=sv
76
+ }else finalValue=value
77
+ if(Array.isArray(finalValue)){
78
+ const stringValue=finalValue.find((entry)=>typeof entry==='string')
79
+ const files=typeof File==='undefined'?[]:finalValue.filter((entry)=>entry instanceof File)
80
+ if(stringValue&&files.length&&stringValue.charCodeAt(0)===123){
81
+ try{
82
+ const parsed=JSON.parse(stringValue)
83
+ if(parsed&&typeof parsed==='object'&&!Array.isArray(parsed)){
84
+ if(!('file' in parsed)&&files.length===1)parsed.file=files[0]
85
+ else if(!('files' in parsed)&&files.length>1)parsed.files=files
86
+ finalValue=parsed
87
+ }
88
+ }catch{}
89
+ }
90
+ }
91
+ if(key.includes('.')||key.includes('[')){const keys=key.split('.')
92
+ const lastKey=keys.pop()
93
+ if(isDangerousKey(lastKey)||keys.some(isDangerousKey))continue
94
+ let current=c.body
95
+ for(const k of keys){const arrayInfo=parseArrayKey(k)
96
+ if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
97
+ const existing=current[arrayInfo.name][arrayInfo.index]
98
+ const isFile=typeof File!=='undefined'&&existing instanceof File
99
+ if(!existing||typeof existing!=='object'||Array.isArray(existing)||isFile){
100
+ let parsed
101
+ if(typeof existing==='string'&&existing.charCodeAt(0)===123){
102
+ try{parsed=JSON.parse(existing)
103
+ if(!parsed||typeof parsed!=='object'||Array.isArray(parsed))parsed=undefined}catch{}
104
+ }
105
+ current[arrayInfo.name][arrayInfo.index]=parsed||{}
106
+ }
107
+ current=current[arrayInfo.name][arrayInfo.index]}else{if(!current[k]||typeof current[k]!=='object')current[k]={}
108
+ current=current[k]}}
109
+ const arrayInfo=parseArrayKey(lastKey)
110
+ if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
111
+ current[arrayInfo.name][arrayInfo.index]=finalValue}else{current[lastKey]=finalValue}}else c.body[key]=finalValue}`;
65
112
  }
66
113
  }
67
114
  },
@@ -43,10 +43,57 @@ for(const [k,v] of c.request.headers.entries())c.headers[k]=v
43
43
  c.body={}
44
44
  `;
45
45
  return isOptional ? fnLiteral += "let form;try{form=await c.request.formData()}catch{}" : fnLiteral += `const form=await c.request.formData()
46
- `, fnLiteral + `for(const key of form.keys()){if(c.body[key]) continue
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
+ for(const key of form.keys()){if(c.body[key])continue
47
50
  const value=form.getAll(key)
48
- if(value.length===1)c.body[key]=value[0]
49
- else c.body[key]=value}`;
51
+ let finalValue
52
+ if(value.length===1){
53
+ const sv=value[0]
54
+ if(typeof sv==='string'&&(sv.charCodeAt(0)===123||sv.charCodeAt(0)===91)){
55
+ try{
56
+ const p=JSON.parse(sv)
57
+ if(p&&typeof p==='object')finalValue=p
58
+ }catch{}
59
+ }
60
+ if(finalValue===undefined)finalValue=sv
61
+ }else finalValue=value
62
+ if(Array.isArray(finalValue)){
63
+ const stringValue=finalValue.find((entry)=>typeof entry==='string')
64
+ const files=typeof File==='undefined'?[]:finalValue.filter((entry)=>entry instanceof File)
65
+ if(stringValue&&files.length&&stringValue.charCodeAt(0)===123){
66
+ try{
67
+ const parsed=JSON.parse(stringValue)
68
+ if(parsed&&typeof parsed==='object'&&!Array.isArray(parsed)){
69
+ if(!('file' in parsed)&&files.length===1)parsed.file=files[0]
70
+ else if(!('files' in parsed)&&files.length>1)parsed.files=files
71
+ finalValue=parsed
72
+ }
73
+ }catch{}
74
+ }
75
+ }
76
+ if(key.includes('.')||key.includes('[')){const keys=key.split('.')
77
+ const lastKey=keys.pop()
78
+ if(isDangerousKey(lastKey)||keys.some(isDangerousKey))continue
79
+ let current=c.body
80
+ for(const k of keys){const arrayInfo=parseArrayKey(k)
81
+ if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
82
+ const existing=current[arrayInfo.name][arrayInfo.index]
83
+ const isFile=typeof File!=='undefined'&&existing instanceof File
84
+ if(!existing||typeof existing!=='object'||Array.isArray(existing)||isFile){
85
+ let parsed
86
+ if(typeof existing==='string'&&existing.charCodeAt(0)===123){
87
+ try{parsed=JSON.parse(existing)
88
+ if(!parsed||typeof parsed!=='object'||Array.isArray(parsed))parsed=undefined}catch{}
89
+ }
90
+ current[arrayInfo.name][arrayInfo.index]=parsed||{}
91
+ }
92
+ current=current[arrayInfo.name][arrayInfo.index]}else{if(!current[k]||typeof current[k]!=='object')current[k]={}
93
+ current=current[k]}}
94
+ const arrayInfo=parseArrayKey(lastKey)
95
+ if(arrayInfo){if(!Array.isArray(current[arrayInfo.name]))current[arrayInfo.name]=[]
96
+ current[arrayInfo.name][arrayInfo.index]=finalValue}else{current[lastKey]=finalValue}}else c.body[key]=finalValue}`;
50
97
  }
51
98
  }
52
99
  },