elysia 2.0.0-exp.60 → 2.0.0-exp.62

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 (79) hide show
  1. package/dist/adapter/utils.d.ts +1 -1
  2. package/dist/adapter/web-standard/handler.js +13 -9
  3. package/dist/adapter/web-standard/handler.mjs +14 -10
  4. package/dist/base.d.ts +24 -9
  5. package/dist/base.js +33 -17
  6. package/dist/base.mjs +34 -18
  7. package/dist/compile/aot-capture.js +1 -1
  8. package/dist/compile/aot-capture.mjs +2 -2
  9. package/dist/compile/handler/descriptor.d.ts +1 -1
  10. package/dist/compile/handler/descriptor.js +5 -4
  11. package/dist/compile/handler/descriptor.mjs +5 -4
  12. package/dist/compile/handler/frozen-validator.d.ts +3 -2
  13. package/dist/compile/handler/frozen-validator.js +35 -5
  14. package/dist/compile/handler/frozen-validator.mjs +34 -5
  15. package/dist/compile/handler/index.d.ts +1 -1
  16. package/dist/compile/handler/jit.js +8 -9
  17. package/dist/compile/handler/jit.mjs +9 -10
  18. package/dist/compile/handler/params.js +3 -3
  19. package/dist/compile/handler/params.mjs +4 -4
  20. package/dist/compile/handler/utils.d.ts +1 -1
  21. package/dist/compile/handler/utils.js +6 -2
  22. package/dist/compile/handler/utils.mjs +6 -2
  23. package/dist/compile/lexer.d.ts +1 -1
  24. package/dist/context.d.ts +6 -2
  25. package/dist/context.js +11 -0
  26. package/dist/context.mjs +11 -0
  27. package/dist/cookie/cookie.js +1 -0
  28. package/dist/cookie/cookie.mjs +1 -0
  29. package/dist/error.d.ts +138 -5
  30. package/dist/error.js +73 -0
  31. package/dist/error.mjs +73 -1
  32. package/dist/handler/error.d.ts +20 -1
  33. package/dist/handler/error.js +120 -8
  34. package/dist/handler/error.mjs +119 -9
  35. package/dist/handler/fetch.js +18 -8
  36. package/dist/handler/fetch.mjs +18 -8
  37. package/dist/handler/utils.js +2 -1
  38. package/dist/handler/utils.mjs +3 -2
  39. package/dist/index.d.ts +4 -4
  40. package/dist/index.js +1 -0
  41. package/dist/index.mjs +2 -2
  42. package/dist/package.js +1 -1
  43. package/dist/package.mjs +1 -1
  44. package/dist/plugin/aot/core.d.ts +4 -3
  45. package/dist/plugin/aot/core.js +4 -4
  46. package/dist/plugin/aot/core.mjs +5 -5
  47. package/dist/route-table.d.ts +1 -1
  48. package/dist/sucrose.d.ts +2 -8
  49. package/dist/sucrose.js +124 -19
  50. package/dist/sucrose.mjs +124 -19
  51. package/dist/type/bridge.d.ts +6 -6
  52. package/dist/type/coerce.js +9 -4
  53. package/dist/type/coerce.mjs +9 -4
  54. package/dist/type/constants.d.ts +1 -1
  55. package/dist/type/elysia/array-string.js +29 -2
  56. package/dist/type/elysia/array-string.mjs +30 -3
  57. package/dist/type/elysia/file-type.js +11 -1
  58. package/dist/type/elysia/file-type.mjs +11 -1
  59. package/dist/type/elysia/form.js +2 -1
  60. package/dist/type/elysia/form.mjs +2 -1
  61. package/dist/type/elysia/object-string.js +26 -2
  62. package/dist/type/elysia/object-string.mjs +27 -3
  63. package/dist/type/validator/index.js +11 -13
  64. package/dist/type/validator/index.mjs +12 -14
  65. package/dist/types.d.ts +106 -20
  66. package/dist/universal/constants.d.ts +2 -1
  67. package/dist/universal/constants.js +3 -1
  68. package/dist/universal/constants.mjs +2 -1
  69. package/dist/universal/file.js +1 -0
  70. package/dist/universal/file.mjs +1 -0
  71. package/dist/universal/index.d.ts +1 -1
  72. package/dist/utils.d.ts +4 -6
  73. package/dist/utils.js +10 -12
  74. package/dist/utils.mjs +8 -12
  75. package/dist/validator/route.js +9 -9
  76. package/dist/validator/route.mjs +9 -9
  77. package/dist/ws/route.js +1 -1
  78. package/dist/ws/route.mjs +1 -1
  79. package/package.json +2 -8
@@ -1,6 +1,6 @@
1
1
  import { BaseCookie } from "../cookie/types.js";
2
- import { StatusMap } from "../constants.js";
3
2
  import { ElysiaFile } from "../universal/file.js";
3
+ import { StatusMap } from "../constants.js";
4
4
  import { HTTPHeaders } from "../types.js";
5
5
  import { Context } from "../context.js";
6
6
  //#region src/adapter/utils.d.ts
@@ -21,20 +21,24 @@ function handleElysiaFile(file, set = { headers: require_utils.nullObject() }, r
21
21
  });
22
22
  return require_adapter_utils.handleFile(file.value, set, request);
23
23
  }
24
+ function responseTag(response) {
25
+ if (response == null) return;
26
+ return Object.getPrototypeOf(response)?.constructor?.name;
27
+ }
24
28
  function mapResponseWithSet(response, set, request, owned) {
25
29
  require_adapter_utils.handleSet(set);
26
30
  const headers = set.headers;
27
- switch (response?.constructor?.name) {
31
+ switch (responseTag(response)) {
28
32
  case "String":
29
33
  if (!require_universal_constants.isBun && !headers["content-type"]) require_adapter_utils.materializeSetHeaders(set)["content-type"] = "text/plain";
30
34
  return new Response(response, set);
31
35
  case "Array": return Response.json(response, set);
36
+ case "ElysiaForm": return new Response(require_utils.formToFormData(response), set);
32
37
  case "Object":
33
- if (response["~ely-form"]) return new Response(require_utils.formToFormData(response), set);
34
38
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
35
39
  return Response.json(response, set);
36
40
  case "Number":
37
- case "Boolean": return new Response(response.toString(), set);
41
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString(), set);
38
42
  case "ElysiaFile": return handleElysiaFile(response, set, request);
39
43
  case "File":
40
44
  case "Blob": return require_adapter_utils.handleFile(response, set, request);
@@ -66,14 +70,13 @@ function mapResponse(response, set, request, owned) {
66
70
  }
67
71
  const textHeaders = require_universal_constants.isBun ? void 0 : textPlainInit;
68
72
  function mapCompactResponse(response, request, owned) {
69
- switch (response?.constructor?.name) {
73
+ switch (responseTag(response)) {
70
74
  case "String": return new Response(response, textHeaders);
71
75
  case "Array": return Response.json(response);
72
- case "Object":
73
- if (response["~ely-form"]) return new Response(require_utils.formToFormData(response));
74
- return Response.json(response);
76
+ case "ElysiaForm": return new Response(require_utils.formToFormData(response));
77
+ case "Object": return Response.json(response);
75
78
  case "Number":
76
- case "Boolean": return new Response(response.toString());
79
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
77
80
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
78
81
  case "File":
79
82
  case "Blob": return require_adapter_utils.handleFile(response, void 0, request);
@@ -126,11 +129,12 @@ function mapFallback(response, set, request, owned = false) {
126
129
  headers: response.headers ? { ...response.headers } : {}
127
130
  }, request, owned);
128
131
  if (response instanceof require_universal_file.ElysiaFile) return handleElysiaFile(response, void 0, request);
132
+ if (require_utils.isElysiaForm(response)) return new Response(require_utils.formToFormData(response), set);
129
133
  if (typeof response?.next === "function" || response instanceof ReadableStream) return handleStream(response, set, request, void 0, owned);
130
134
  if (typeof response?.then === "function") return response.then((x) => set ? mapResponse(x, set, request, owned) : mapCompactResponse(x, request, owned));
131
135
  if (Array.isArray(response)) return Response.json(response);
132
136
  if (typeof response?.toResponse === "function") return set ? mapResponse(response.toResponse(), set, request, owned) : mapCompactResponse(response.toResponse(), request, owned);
133
- if (response?.constructor?.name === "Cookie" && response.jar) return new Response(response.value, set);
137
+ if (responseTag(response) === "Cookie") return set ? mapResponse(response.value, set, request, owned) : mapCompactResponse(response.value, request, owned);
134
138
  return new Response(response, set);
135
139
  }
136
140
  const handleResponse = require_adapter_utils.createResponseHandler({
@@ -1,6 +1,6 @@
1
1
  import { isBun } from "../../universal/constants.mjs";
2
2
  import { ElysiaFile, mime } from "../../universal/file.mjs";
3
- import { formToFormData, isNotEmpty, nullObject } from "../../utils.mjs";
3
+ import { formToFormData, isElysiaForm, isNotEmpty, nullObject } from "../../utils.mjs";
4
4
  import { ElysiaStatus, PROBLEM_JSON, internalServerErrorBody } from "../../error.mjs";
5
5
  import { defaultHeaders } from "../default-headers.mjs";
6
6
  import { createResponseHandler, createStreamHandler, handleFile, handleSet, materializeSetHeaders } from "../utils.mjs";
@@ -20,20 +20,24 @@ function handleElysiaFile(file, set = { headers: nullObject() }, request) {
20
20
  });
21
21
  return handleFile(file.value, set, request);
22
22
  }
23
+ function responseTag(response) {
24
+ if (response == null) return;
25
+ return Object.getPrototypeOf(response)?.constructor?.name;
26
+ }
23
27
  function mapResponseWithSet(response, set, request, owned) {
24
28
  handleSet(set);
25
29
  const headers = set.headers;
26
- switch (response?.constructor?.name) {
30
+ switch (responseTag(response)) {
27
31
  case "String":
28
32
  if (!isBun && !headers["content-type"]) materializeSetHeaders(set)["content-type"] = "text/plain";
29
33
  return new Response(response, set);
30
34
  case "Array": return Response.json(response, set);
35
+ case "ElysiaForm": return new Response(formToFormData(response), set);
31
36
  case "Object":
32
- if (response["~ely-form"]) return new Response(formToFormData(response), set);
33
37
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
34
38
  return Response.json(response, set);
35
39
  case "Number":
36
- case "Boolean": return new Response(response.toString(), set);
40
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString(), set);
37
41
  case "ElysiaFile": return handleElysiaFile(response, set, request);
38
42
  case "File":
39
43
  case "Blob": return handleFile(response, set, request);
@@ -65,14 +69,13 @@ function mapResponse(response, set, request, owned) {
65
69
  }
66
70
  const textHeaders = isBun ? void 0 : textPlainInit;
67
71
  function mapCompactResponse(response, request, owned) {
68
- switch (response?.constructor?.name) {
72
+ switch (responseTag(response)) {
69
73
  case "String": return new Response(response, textHeaders);
70
74
  case "Array": return Response.json(response);
71
- case "Object":
72
- if (response["~ely-form"]) return new Response(formToFormData(response));
73
- return Response.json(response);
75
+ case "ElysiaForm": return new Response(formToFormData(response));
76
+ case "Object": return Response.json(response);
74
77
  case "Number":
75
- case "Boolean": return new Response(response.toString());
78
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
76
79
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
77
80
  case "File":
78
81
  case "Blob": return handleFile(response, void 0, request);
@@ -125,11 +128,12 @@ function mapFallback(response, set, request, owned = false) {
125
128
  headers: response.headers ? { ...response.headers } : {}
126
129
  }, request, owned);
127
130
  if (response instanceof ElysiaFile) return handleElysiaFile(response, void 0, request);
131
+ if (isElysiaForm(response)) return new Response(formToFormData(response), set);
128
132
  if (typeof response?.next === "function" || response instanceof ReadableStream) return handleStream(response, set, request, void 0, owned);
129
133
  if (typeof response?.then === "function") return response.then((x) => set ? mapResponse(x, set, request, owned) : mapCompactResponse(x, request, owned));
130
134
  if (Array.isArray(response)) return Response.json(response);
131
135
  if (typeof response?.toResponse === "function") return set ? mapResponse(response.toResponse(), set, request, owned) : mapCompactResponse(response.toResponse(), request, owned);
132
- if (response?.constructor?.name === "Cookie" && response.jar) return new Response(response.value, set);
136
+ if (responseTag(response) === "Cookie") return set ? mapResponse(response.value, set, request, owned) : mapCompactResponse(response.value, request, owned);
133
137
  return new Response(response, set);
134
138
  }
135
139
  const handleResponse = createResponseHandler({
package/dist/base.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ElysiaStatus } from "./error.js";
2
1
  import { TraceCapability, TraceHandler } from "./trace.js";
3
2
  import { ListenCallback, Serve, Server } from "./universal/server.js";
4
- import { AddRoute, AddWSRoute, AfterHandler, AfterResponseHandler, AnyErrorConstructor, AnyLocalHook, BodyHandler, CompiledHandler, CreateEden, DefaultEphemeral, DefaultMetadata, DefaultSingleton, DefinitionBase, DocumentDecoration, ElysiaConfig, ElysiaHandlerToResponseSchemaAmbiguous, EphemeralType, ErrorDefinitionEntry, ErrorHandler, EventScope, ExcludeElysiaResponse, ExtractErrorFromHandle, GlobalHookReturn, GracefulHandler, GuardHookSingleton, GuardLocalHook, HTTPMethod, HistoryEntry, HookContextSchema, HookContextSingleton, InlineHandler, InlineHandlerNonMacro, InputSchema, InputSchemaKey, InternalRoute, IntersectIfObjectSchema, JoinPath, LocalHook, LocalHookReturn, Macro, MacroSchemaChannel, MacroToContext, MacroToProperty, MapResponse, MaybeArray, MaybePromise, MergeElysiaInstances, MergeSchema, MergeScopedSchemas, MetadataBase, NonResolvableMacroKey, ObjectMacroDefs, OptionalHandler, PluginHookReturn, PreHandler, Prettify, PublicRoute, ResolveRouteErrors, RouteBase, ScopedHookReturn, ScopedMapDeriveReturn, SingletonBase, StaticMapAliases, TransformHandler, UnionResponseStatus, UnwrapRoute, WrapFn } from "./types.js";
5
3
  import { ChainNode } from "./utils.js";
4
+ import { AddRoute, AddWSRoute, AfterHandler, AfterResponseHandler, AnyErrorConstructor, AnyLocalHook, BodyHandler, CompiledHandler, CreateEden, DefaultEphemeral, DefaultMetadata, DefaultSingleton, DefinitionBase, DocumentDecoration, ElysiaConfig, ElysiaHandlerToResponseSchemaAmbiguous, EphemeralType, ErrorDefinitionEntry, ErrorHandler, EventScope, ExcludeElysiaResponse, ExtractErrorFromHandle, GlobalHookReturn, GracefulHandler, GuardHookSingleton, GuardLocalHook, HTTPMethod, HistoryEntry, HookContextSchema, HookContextSingleton, InlineHandler, InlineHandlerNonMacro, InputSchema, InputSchemaKey, InternalRoute, IntersectIfObjectSchema, JoinPath, LocalHook, LocalHookReturn, Macro, MacroSchemaChannel, MacroToContext, MacroToProperty, MapResponse, MaybeArray, MaybePromise, MergeElysiaInstances, MergeSchema, MergeScopedSchemas, MetadataBase, NonResolvableMacroKey, ObjectMacroDefs, OptionalHandler, PluginHookReturn, PreHandler, Prettify, PublicRoute, ResolveRouteErrors, RouteBase, ScopedHookReturn, ScopedMapDeriveReturn, SingletonBase, StaticMapAliases, TransformHandler, UnionResponseStatus, UnwrapRoute, WrapFn } from "./types.js";
5
+ import { ElysiaStatus } from "./error.js";
6
6
  import { Context, ErrorContext, LifecycleContext } from "./context.js";
7
7
  import { AnySchema } from "./type/types.js";
8
8
  import { AotFingerprint, CompilerSession, ProgramId } from "./compile/aot.js";
@@ -391,7 +391,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
391
391
  * them with `.use()` instead.
392
392
  */
393
393
  guard<const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], BasePath>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>>(hook: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
394
- schema: 'standalone';
394
+ schema: 'merge';
395
395
  }): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes, Ephemeral, {
396
396
  derive: Volatile['derive'] & MacroContext['resolve'];
397
397
  schema: Volatile['schema'];
@@ -407,7 +407,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
407
407
  error: Volatile['error'];
408
408
  }>;
409
409
  guard<const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], BasePath>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const NewElysia extends AnyElysia>(hook: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
410
- schema: 'standalone';
410
+ schema: 'merge';
411
411
  }, run: (group: Elysia<BasePath, Scope, {
412
412
  decorator: Singleton['decorator'];
413
413
  store: Singleton['store'];
@@ -433,7 +433,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
433
433
  response: Metadata['response'] & MacroContext['response'] & ElysiaHandlerToResponseSchemaAmbiguous<BeforeHandle> & ElysiaHandlerToResponseSchemaAmbiguous<AfterHandle> & ElysiaHandlerToResponseSchemaAmbiguous<ErrorHandle>;
434
434
  }, {}, Ephemeral, Volatile>) => NewElysia): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes & NewElysia['~Routes'], Ephemeral, Volatile>;
435
435
  guard<const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], BasePath>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>>(scope: 'local', hook: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
436
- schema: 'standalone';
436
+ schema: 'merge';
437
437
  }): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes, Ephemeral, {
438
438
  derive: Volatile['derive'] & MacroContext['resolve'];
439
439
  schema: Volatile['schema'];
@@ -449,7 +449,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
449
449
  error: Volatile['error'];
450
450
  }>;
451
451
  guard<const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], BasePath>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>>(scope: 'plugin', hook: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
452
- schema: 'standalone';
452
+ schema: 'merge';
453
453
  }): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes, {
454
454
  derive: Ephemeral['derive'] & MacroContext['resolve'];
455
455
  schema: Ephemeral['schema'];
@@ -465,7 +465,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
465
465
  error: Ephemeral['error'];
466
466
  }, Volatile>;
467
467
  guard<const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], BasePath>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>>(scope: 'global', hook: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
468
- schema: 'standalone';
468
+ schema: 'merge';
469
469
  }): Elysia<BasePath, Scope, {
470
470
  decorator: Singleton['decorator'];
471
471
  store: Singleton['store'];
@@ -499,7 +499,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
499
499
  response: Metadata['response'];
500
500
  }, {}, Ephemeral, Volatile>) => NewElysia): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes & NewElysia['~Routes'], Ephemeral, Volatile>;
501
501
  group<const Prefix extends string, const Input extends Metadata['macro'] & InputSchema<keyof Definitions['typebox'] & string>, const Schema extends MergeSchema<UnwrapRoute<Input, Definitions['typebox'], JoinPath<BasePath, Prefix>>, MergeSchema<Volatile['schema'], MergeSchema<Ephemeral['schema'], Metadata['schema']>>> & Metadata['schemas'] & Ephemeral['schemas'] & Volatile['schemas'], const MacroContext extends ({} extends Metadata['macroFn'] ? {} : MacroToContext<Metadata['macroFn'], Omit<Input, NonResolvableMacroKey>, Definitions['typebox']>), const BeforeHandle extends MaybeArray<OptionalHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const AfterHandle extends MaybeArray<AfterHandler<Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const ErrorHandle extends MaybeArray<ErrorHandler<Definitions['error'], Schema, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>>>, const NewElysia extends AnyElysia>(prefix: Prefix, schema: GuardLocalHook<Input, Schema & MacroContext, GuardHookSingleton<Singleton, Ephemeral, Volatile, MacroContext>, keyof Metadata['parser'], BeforeHandle, AfterHandle, ErrorHandle> & {
502
- schema: 'standalone';
502
+ schema: 'merge';
503
503
  }, run: (group: Elysia<JoinPath<BasePath, Prefix>, Scope, {
504
504
  decorator: Singleton['decorator'];
505
505
  store: Singleton['store'];
@@ -559,7 +559,7 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
559
559
  parser: Metadata['parser'];
560
560
  response: Metadata['response'];
561
561
  }, Routes, Ephemeral, Volatile>;
562
- '~applyMacro'(input: Partial<AnyLocalHook>, toApply?: Partial<AnyLocalHook>, iteration?: number, seen?: Set<string | Partial<any>>): Partial<AnyLocalHook>;
562
+ '~applyMacro'(input: Partial<AnyLocalHook>, toApply?: Partial<AnyLocalHook>, iteration?: number, seen?: Set<string | Partial<any>>, insertions?: Map<string, number>): Partial<AnyLocalHook>;
563
563
  /**
564
564
  * Merge a plugin instance
565
565
  */
@@ -869,6 +869,21 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
869
869
  get fetch(): (request: Request, ...rest: any[]) => MaybePromise<Response>;
870
870
  get handle(): (url: string | Request, options?: RequestInit) => Promise<Response>;
871
871
  listen(options: string | number | Partial<Serve>, callback?: ListenCallback): this;
872
+ /**
873
+ * Add a higher order function over Elysia.fetch
874
+ *
875
+ * @example
876
+ * ```ts
877
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
878
+ *
879
+ * new Elysia()
880
+ * .wrap(
881
+ * (fetch) => (request) =>
882
+ * ctx.run({ counter: 0 }, () => fetch(request))
883
+ * )
884
+ * .get('/', () => ctx.getStore())
885
+ * ```
886
+ */
872
887
  wrap<T extends (...params: any) => MaybePromise<Response> = (request: Request, ...rest: any[]) => MaybePromise<Response>>(callback: WrapFn<T>): this;
873
888
  /**
874
889
  * ### cleanup | Life cycle event
package/dist/base.js CHANGED
@@ -502,7 +502,7 @@ var Elysia = class Elysia {
502
502
  require_utils.invalidateMacroEpoch();
503
503
  return this;
504
504
  }
505
- "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set()) {
505
+ "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set(), insertions = /* @__PURE__ */ new Map()) {
506
506
  if (iteration >= 16) return input;
507
507
  const macro = this["~ext"]?.macro;
508
508
  if (!macro) return input;
@@ -547,14 +547,14 @@ var Elysia = class Elysia {
547
547
  continue;
548
548
  }
549
549
  if (k in macro) {
550
- this["~applyMacro"](input, { [k]: v }, iteration + 1, seen);
550
+ this["~applyMacro"](input, { [k]: v }, iteration + 1, seen, insertions);
551
551
  delete input[key];
552
552
  continue;
553
553
  }
554
554
  if (k === "schema") {
555
555
  const incoming = Array.isArray(v) ? v : [v];
556
556
  if (!input.schemas) input.schemas = [];
557
- require_utils.coalesceStandaloneSchemas(input.schemas, incoming);
557
+ require_utils.coalesceSchemas(input.schemas, incoming);
558
558
  delete input[key];
559
559
  continue;
560
560
  }
@@ -564,23 +564,24 @@ var Elysia = class Elysia {
564
564
  continue;
565
565
  }
566
566
  input.schemas ??= [];
567
- require_utils.coalesceStandaloneSchemas(input.schemas, [{ [k]: v }]);
567
+ require_utils.coalesceSchemas(input.schemas, [{ [k]: v }]);
568
568
  delete input[key];
569
569
  continue;
570
570
  }
571
- if (k in input) {
572
- if (require_utils.eventProperties.has(k) || k === "derive") {
573
- const macroFns = Array.isArray(v) ? v : [v];
574
- const existing = Array.isArray(input[k]) ? input[k] : [input[k]];
575
- const merged = [];
576
- const seen = /* @__PURE__ */ new Set();
577
- for (const fn of macroFns) if (!existing.includes(fn) && !seen.has(fn)) {
578
- seen.add(fn);
579
- merged.push(fn);
580
- }
581
- for (const fn of existing) if (!seen.has(fn)) merged.push(fn);
582
- input[k] = merged;
583
- } else if (Array.isArray(input[k])) {
571
+ if (require_utils.eventProperties.has(k) || k === "derive") {
572
+ const incoming = Array.isArray(v) ? v : [v];
573
+ const existing = k in input ? Array.isArray(input[k]) ? input[k] : [input[k]] : [];
574
+ const added = [];
575
+ for (const fn of incoming) if (!existing.includes(fn) && !added.includes(fn)) added.push(fn);
576
+ const at = insertions.get(k) ?? 0;
577
+ input[k] = [
578
+ ...existing.slice(0, at),
579
+ ...added,
580
+ ...existing.slice(at)
581
+ ];
582
+ insertions.set(k, at + added.length);
583
+ } else if (k in input) {
584
+ if (Array.isArray(input[k])) {
584
585
  if (Array.isArray(v)) {
585
586
  for (const item of v) if (!input[k].some((e) => e === item)) input[k].unshift(item);
586
587
  } else if (!input[k].some((item) => item === v)) input[k].unshift(v);
@@ -1511,6 +1512,21 @@ var Elysia = class Elysia {
1511
1512
  if (!require_compile_aot.Capture.isAotBuildEnv()) listen(this, options, callback);
1512
1513
  return this;
1513
1514
  }
1515
+ /**
1516
+ * Add a higher order function over Elysia.fetch
1517
+ *
1518
+ * @example
1519
+ * ```ts
1520
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
1521
+ *
1522
+ * new Elysia()
1523
+ * .wrap(
1524
+ * (fetch) => (request) =>
1525
+ * ctx.run({ counter: 0 }, () => fetch(request))
1526
+ * )
1527
+ * .get('/', () => ctx.getStore())
1528
+ * ```
1529
+ */
1514
1530
  wrap(callback) {
1515
1531
  this.#assertMutable("wrap");
1516
1532
  if (this.#fetchFn && !this.#pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
package/dist/base.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isBun } from "./universal/constants.mjs";
2
- import { clonePlainDecorators, clonePlainDeep, coalesceStandaloneSchemas, createErrorEventHandler, eventProperties, fnOrigin, fnv1a, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isEmpty, isNotEmpty, isRecordNumber, joinPath, macroOrigin, mapDeriveEntry, mergeDeep, mergeResponse, nullObject, pushField, schemaProperties, serializeMacroSeed } from "./utils.mjs";
2
+ import { clonePlainDecorators, clonePlainDeep, coalesceSchemas, createErrorEventHandler, eventProperties, fnOrigin, fnv1a, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isEmpty, isNotEmpty, isRecordNumber, joinPath, macroOrigin, mapDeriveEntry, mergeDeep, mergeResponse, nullObject, pushField, schemaProperties, serializeMacroSeed } from "./utils.mjs";
3
3
  import { Ref } from "./type/bridge.mjs";
4
4
  import { isProduction } from "./universal/is-production.mjs";
5
5
  import { Capture, Compiled, beginCompilerSession, createAotFingerprint, createProgramId, endCompilerSession } from "./compile/aot.mjs";
@@ -499,7 +499,7 @@ var Elysia = class Elysia {
499
499
  invalidateMacroEpoch();
500
500
  return this;
501
501
  }
502
- "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set()) {
502
+ "~applyMacro"(input, toApply = input, iteration = 0, seen = /* @__PURE__ */ new Set(), insertions = /* @__PURE__ */ new Map()) {
503
503
  if (iteration >= 16) return input;
504
504
  const macro = this["~ext"]?.macro;
505
505
  if (!macro) return input;
@@ -544,14 +544,14 @@ var Elysia = class Elysia {
544
544
  continue;
545
545
  }
546
546
  if (k in macro) {
547
- this["~applyMacro"](input, { [k]: v }, iteration + 1, seen);
547
+ this["~applyMacro"](input, { [k]: v }, iteration + 1, seen, insertions);
548
548
  delete input[key];
549
549
  continue;
550
550
  }
551
551
  if (k === "schema") {
552
552
  const incoming = Array.isArray(v) ? v : [v];
553
553
  if (!input.schemas) input.schemas = [];
554
- coalesceStandaloneSchemas(input.schemas, incoming);
554
+ coalesceSchemas(input.schemas, incoming);
555
555
  delete input[key];
556
556
  continue;
557
557
  }
@@ -561,23 +561,24 @@ var Elysia = class Elysia {
561
561
  continue;
562
562
  }
563
563
  input.schemas ??= [];
564
- coalesceStandaloneSchemas(input.schemas, [{ [k]: v }]);
564
+ coalesceSchemas(input.schemas, [{ [k]: v }]);
565
565
  delete input[key];
566
566
  continue;
567
567
  }
568
- if (k in input) {
569
- if (eventProperties.has(k) || k === "derive") {
570
- const macroFns = Array.isArray(v) ? v : [v];
571
- const existing = Array.isArray(input[k]) ? input[k] : [input[k]];
572
- const merged = [];
573
- const seen = /* @__PURE__ */ new Set();
574
- for (const fn of macroFns) if (!existing.includes(fn) && !seen.has(fn)) {
575
- seen.add(fn);
576
- merged.push(fn);
577
- }
578
- for (const fn of existing) if (!seen.has(fn)) merged.push(fn);
579
- input[k] = merged;
580
- } else if (Array.isArray(input[k])) {
568
+ if (eventProperties.has(k) || k === "derive") {
569
+ const incoming = Array.isArray(v) ? v : [v];
570
+ const existing = k in input ? Array.isArray(input[k]) ? input[k] : [input[k]] : [];
571
+ const added = [];
572
+ for (const fn of incoming) if (!existing.includes(fn) && !added.includes(fn)) added.push(fn);
573
+ const at = insertions.get(k) ?? 0;
574
+ input[k] = [
575
+ ...existing.slice(0, at),
576
+ ...added,
577
+ ...existing.slice(at)
578
+ ];
579
+ insertions.set(k, at + added.length);
580
+ } else if (k in input) {
581
+ if (Array.isArray(input[k])) {
581
582
  if (Array.isArray(v)) {
582
583
  for (const item of v) if (!input[k].some((e) => e === item)) input[k].unshift(item);
583
584
  } else if (!input[k].some((item) => item === v)) input[k].unshift(v);
@@ -1508,6 +1509,21 @@ var Elysia = class Elysia {
1508
1509
  if (!Capture.isAotBuildEnv()) listen(this, options, callback);
1509
1510
  return this;
1510
1511
  }
1512
+ /**
1513
+ * Add a higher order function over Elysia.fetch
1514
+ *
1515
+ * @example
1516
+ * ```ts
1517
+ * const ctx = new AsyncLocalStorage<{ counter: number }>()
1518
+ *
1519
+ * new Elysia()
1520
+ * .wrap(
1521
+ * (fetch) => (request) =>
1522
+ * ctx.run({ counter: 0 }, () => fetch(request))
1523
+ * )
1524
+ * .get('/', () => ctx.getStore())
1525
+ * ```
1526
+ */
1511
1527
  wrap(callback) {
1512
1528
  this.#assertMutable("wrap");
1513
1529
  if (this.#fetchFn && !this.#pending) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
@@ -282,7 +282,7 @@ function captureBridgeFree(aot, slot, rawSchema) {
282
282
  path: aot.path,
283
283
  slot
284
284
  }, { bridgeFree });
285
- if (bridgeFree && !require_compile_handler_frozen_validator.isCompactDiagnosable(coerced)) warnCompactErrorLoss(aot, slot);
285
+ if (bridgeFree && !require_compile_handler_frozen_validator.isCompactWalkable(coerced)) warnCompactErrorLoss(aot, slot);
286
286
  }
287
287
  }
288
288
  function beginValidatorCapture() {
@@ -2,7 +2,7 @@ import { nullObject } from "../utils.mjs";
2
2
  import { env } from "../universal/env.mjs";
3
3
  import { Capture, CompilerState, aotActivationError, captureImpl, setCaptureImpl } from "./aot.mjs";
4
4
  import { isAsyncPredicate } from "../type/elysia/file-type.mjs";
5
- import { isCapturedBridgeFree, isCompactDiagnosable } from "./handler/frozen-validator.mjs";
5
+ import { isCapturedBridgeFree, isCompactWalkable } from "./handler/frozen-validator.mjs";
6
6
  import { buildCoercedFromPlan, captureCoercePlan } from "../type/coerce.mjs";
7
7
  import { applyPrecomputed, buildDefaultClonerSource, buildObjectDefaultMergeSource, canonical, createMergerFromSource, setDefaultProbeImpl, verifyPreallocatableDefault } from "../type/validator/default-precompute.mjs";
8
8
  import { collectExternals } from "./aot-reconstruct.mjs";
@@ -280,7 +280,7 @@ function captureBridgeFree(aot, slot, rawSchema) {
280
280
  path: aot.path,
281
281
  slot
282
282
  }, { bridgeFree });
283
- if (bridgeFree && !isCompactDiagnosable(coerced)) warnCompactErrorLoss(aot, slot);
283
+ if (bridgeFree && !isCompactWalkable(coerced)) warnCompactErrorLoss(aot, slot);
284
284
  }
285
285
  }
286
286
  function beginValidatorCapture() {
@@ -1,6 +1,6 @@
1
1
  import { TraceEvent } from "../../trace.js";
2
- import { AnyLocalHook, MaybeArray } from "../../types.js";
3
2
  import { CompactBeforeHandlePrefix } from "../../utils.js";
3
+ import { AnyLocalHook, MaybeArray } from "../../types.js";
4
4
  import { CompiledCookieConfig } from "../../cookie/config.js";
5
5
  import { AnyElysia } from "../../base.js";
6
6
  import { ElysiaAdapter } from "../../adapter/index.js";
@@ -97,9 +97,9 @@ function describeRoute(input) {
97
97
  if (hook && typeof hook.parse === "function") hook.parse = [hook.parse];
98
98
  const parseLength = Array.isArray(hook?.parse) ? hook.parse.length : 0;
99
99
  const parseFirst = Array.isArray(hook?.parse) ? hook.parse[0] : hook?.parse;
100
- const hasStandaloneBody = !!hook?.schemas?.some((s) => s?.body);
100
+ const hasMergeBody = !!hook?.schemas?.some((s) => s?.body);
101
101
  const bodylessMethod = method === "GET" || method === "HEAD";
102
- const hasBody = !!hook?.body || hasStandaloneBody || !bodylessMethod && (parseLength > 0 || inference.body) && parseFirst !== "none";
102
+ const hasBody = !!hook?.body || hasMergeBody || !bodylessMethod && (parseLength > 0 || inference.body) && parseFirst !== "none";
103
103
  const bodyValiIsAsync = hasBody && (isAsyncValidator(vali?.body) || mayReturnPromiseValidator(vali?.body));
104
104
  const headersValiIsAsync = vali?.headers && (isAsyncValidator(vali?.headers) || mayReturnPromiseValidator(vali?.headers));
105
105
  const paramsValiIsAsync = vali?.params && (isAsyncValidator(vali?.params) || mayReturnPromiseValidator(vali?.params));
@@ -113,7 +113,8 @@ function describeRoute(input) {
113
113
  const asyncCookieSign = hasCookieSign && !syncCookieSign;
114
114
  const lazyCookieVerify = syncCookieSign && cookieConfig?.verify === "lazy" && !vali?.cookie;
115
115
  const hasErrorHook = !!hook?.error?.length;
116
- const hasAfterResponse = !!hook?.afterResponse?.length;
116
+ const hasStaticAfterResponse = !!hook?.afterResponse?.length;
117
+ const hasAfterResponse = hasStaticAfterResponse || !!inference.afterResponse;
117
118
  const hasBeforeHandle = !!beforeHandlePrefix?.length || !!hook?.beforeHandle?.length;
118
119
  const hasAfterHandle = !!hook?.afterHandle?.length;
119
120
  const hasMapResponse = !!hook?.mapResponse?.length;
@@ -137,7 +138,7 @@ function describeRoute(input) {
137
138
  }
138
139
  const handlerIsAsync = isHandleFunction && require_compile_utils.isAsyncFunction(handler);
139
140
  const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || require_compile_utils.isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error, false));
140
- const afterResponseForcesAsync = hasAfterResponse && (require_compile_utils.isAsyncLifecycle(hook?.afterResponse) || hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
141
+ const afterResponseForcesAsync = hasStaticAfterResponse && require_compile_utils.isAsyncLifecycle(hook?.afterResponse) || hasAfterResponse && (hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
141
142
  const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && (require_compile_utils.mayReturnPromise(handler) || mayReturnIdentifier(handler));
142
143
  const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && (require_compile_utils.mayReturnPromise(handler) || mayReturnIdentifier(handler));
143
144
  const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle, true) || lifecycleMayReturnPromise(hook.transform, false) || lifecycleMayReturnPromise(hook.afterHandle, true) || lifecycleMayReturnPromise(hook.mapResponse, true));
@@ -96,9 +96,9 @@ function describeRoute(input) {
96
96
  if (hook && typeof hook.parse === "function") hook.parse = [hook.parse];
97
97
  const parseLength = Array.isArray(hook?.parse) ? hook.parse.length : 0;
98
98
  const parseFirst = Array.isArray(hook?.parse) ? hook.parse[0] : hook?.parse;
99
- const hasStandaloneBody = !!hook?.schemas?.some((s) => s?.body);
99
+ const hasMergeBody = !!hook?.schemas?.some((s) => s?.body);
100
100
  const bodylessMethod = method === "GET" || method === "HEAD";
101
- const hasBody = !!hook?.body || hasStandaloneBody || !bodylessMethod && (parseLength > 0 || inference.body) && parseFirst !== "none";
101
+ const hasBody = !!hook?.body || hasMergeBody || !bodylessMethod && (parseLength > 0 || inference.body) && parseFirst !== "none";
102
102
  const bodyValiIsAsync = hasBody && (isAsyncValidator(vali?.body) || mayReturnPromiseValidator(vali?.body));
103
103
  const headersValiIsAsync = vali?.headers && (isAsyncValidator(vali?.headers) || mayReturnPromiseValidator(vali?.headers));
104
104
  const paramsValiIsAsync = vali?.params && (isAsyncValidator(vali?.params) || mayReturnPromiseValidator(vali?.params));
@@ -112,7 +112,8 @@ function describeRoute(input) {
112
112
  const asyncCookieSign = hasCookieSign && !syncCookieSign;
113
113
  const lazyCookieVerify = syncCookieSign && cookieConfig?.verify === "lazy" && !vali?.cookie;
114
114
  const hasErrorHook = !!hook?.error?.length;
115
- const hasAfterResponse = !!hook?.afterResponse?.length;
115
+ const hasStaticAfterResponse = !!hook?.afterResponse?.length;
116
+ const hasAfterResponse = hasStaticAfterResponse || !!inference.afterResponse;
116
117
  const hasBeforeHandle = !!beforeHandlePrefix?.length || !!hook?.beforeHandle?.length;
117
118
  const hasAfterHandle = !!hook?.afterHandle?.length;
118
119
  const hasMapResponse = !!hook?.mapResponse?.length;
@@ -136,7 +137,7 @@ function describeRoute(input) {
136
137
  }
137
138
  const handlerIsAsync = isHandleFunction && isAsyncFunction(handler);
138
139
  const errorHookForcesAsync = hasErrorHook && (hasAfterHandle || hasMapResponse || hasResponseValidator || isAsyncLifecycle(hook?.error) || lifecycleMayReturnPromise(hook?.error, false));
139
- const afterResponseForcesAsync = hasAfterResponse && (isAsyncLifecycle(hook?.afterResponse) || hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
140
+ const afterResponseForcesAsync = hasStaticAfterResponse && isAsyncLifecycle(hook?.afterResponse) || hasAfterResponse && (hasAfterHandle || hasMapResponse || hasResponseValidator || hasErrorHook);
140
141
  const traceForcesAsync = (traceHandleOn || phaseOn("error") || phaseOn("afterResponse")) && isHandleFunction && !handlerIsAsync && (mayReturnPromise(handler) || mayReturnIdentifier(handler));
141
142
  const handlerResultObserved = isHandleFunction && !handlerIsAsync && (hasResponseValidator || hasAfterHandle || hasMapResponse) && (mayReturnPromise(handler) || mayReturnIdentifier(handler));
142
143
  const lifecycleForcesAsync = !!hook && ((beforeHandlePrefix ? compactPrefixForcesAsync(beforeHandlePrefix) : false) || lifecycleMayReturnPromise(hook.beforeHandle, true) || lifecycleMayReturnPromise(hook.transform, false) || lifecycleMayReturnPromise(hook.afterHandle, true) || lifecycleMayReturnPromise(hook.mapResponse, true));
@@ -11,6 +11,7 @@ interface SlotCheckClean {
11
11
  decode?: (value: unknown) => unknown;
12
12
  }
13
13
  declare function isCompactDiagnosable(schema: any): boolean;
14
+ declare function isCompactWalkable(schema: any): boolean;
14
15
  declare class FrozenSlotValidator {
15
16
  #private;
16
17
  isAsync: boolean;
@@ -32,8 +33,8 @@ interface FrozenRouteValidatorShape {
32
33
  response?: Record<number, FrozenSlotValidator>;
33
34
  }
34
35
  declare const isStandardSchema: (schema: unknown) => schema is object & Record<"~standard", unknown>;
35
- declare function standaloneAllStandard(schemas: Array<Record<string, unknown>> | undefined): boolean;
36
+ declare function mergeSchemasAllStandard(schemas: Array<Record<string, unknown>> | undefined): boolean;
36
37
  declare function buildFrozenRouteValidator(hook: AnyLocalHook, root: AnyElysia, method: HTTPMethod, path: string): FrozenRouteValidatorShape | undefined;
37
38
  declare function isCapturedBridgeFree(c: CapturedValidator, schema: unknown, coerced?: unknown): boolean;
38
39
  //#endregion
39
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, standaloneAllStandard };
40
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isCompactWalkable, isStandardSchema, mergeSchemasAllStandard };
@@ -55,17 +55,30 @@ const typeError = (schema, instancePath, schemaPath) => ({
55
55
  **/
56
56
  function walkCompactError(schema, value, instancePath, schemaPath) {
57
57
  if (!schema || typeof schema !== "object") return;
58
+ const elyTyp = schema["~elyTyp"];
59
+ if (schema.anyOf && (elyTyp === require_type_constants.ELYSIA_TYPES.ObjectString || elyTyp === require_type_constants.ELYSIA_TYPES.ArrayString)) {
60
+ let decoded = value;
61
+ if (typeof value === "string") try {
62
+ decoded = JSON.parse(value);
63
+ } catch {
64
+ return;
65
+ }
66
+ else if (value === void 0) return;
67
+ return walkCompactError(schema.anyOf[0], decoded, instancePath, `${schemaPath}/anyOf/0`);
68
+ }
58
69
  const type = schema.type;
59
70
  if (type === "object") {
60
71
  if (typeof value !== "object" || value === null || Array.isArray(value)) return typeError(schema, instancePath, schemaPath);
61
72
  const required = schema.required;
62
73
  if (Array.isArray(required)) {
63
- for (const key of required) if (!(key in value)) return {
74
+ let missing;
75
+ for (const key of required) if (!(key in value)) (missing ??= []).push(key);
76
+ if (missing) return {
64
77
  keyword: "required",
65
78
  schemaPath,
66
79
  instancePath,
67
- params: { requiredProperties: [key] },
68
- message: `must have required properties ${key}`
80
+ params: { requiredProperties: missing },
81
+ message: `must have required properties ${missing.join(", ")}`
69
82
  };
70
83
  }
71
84
  const properties = schema.properties;
@@ -121,6 +134,22 @@ function isCompactDiagnosable(schema) {
121
134
  if (type === "array") return isCompactDiagnosable(schema.items);
122
135
  return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
123
136
  }
137
+ function isCompactWalkable(schema) {
138
+ if (!schema || typeof schema !== "object") return false;
139
+ const elyTyp = schema["~elyTyp"];
140
+ if (schema.anyOf && (elyTyp === require_type_constants.ELYSIA_TYPES.ObjectString || elyTyp === require_type_constants.ELYSIA_TYPES.ArrayString)) return isCompactWalkable(schema.anyOf[0]);
141
+ if (schema.anyOf || schema.oneOf || schema.allOf) return false;
142
+ const type = schema.type;
143
+ if (type === "object") {
144
+ const properties = schema.properties;
145
+ if (properties) {
146
+ for (const key in properties) if (!isCompactWalkable(properties[key])) return false;
147
+ }
148
+ return true;
149
+ }
150
+ if (type === "array") return isCompactWalkable(schema.items);
151
+ return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
152
+ }
124
153
  var FrozenSlotValidator = class {
125
154
  #check;
126
155
  #clean;
@@ -224,7 +253,7 @@ const REQUEST_SLOTS = [
224
253
  "cookie"
225
254
  ];
226
255
  const isStandardSchema = (schema) => schema != null && typeof schema === "object" && "~standard" in schema;
227
- function standaloneAllStandard(schemas) {
256
+ function mergeSchemasAllStandard(schemas) {
228
257
  if (!schemas || schemas.length === 0) return true;
229
258
  for (const entry of schemas) for (const key in entry) {
230
259
  const value = entry[key];
@@ -315,5 +344,6 @@ exports.buildFrozenRouteValidator = buildFrozenRouteValidator;
315
344
  exports.isBridgeNotInitialized = isBridgeNotInitialized;
316
345
  exports.isCapturedBridgeFree = isCapturedBridgeFree;
317
346
  exports.isCompactDiagnosable = isCompactDiagnosable;
347
+ exports.isCompactWalkable = isCompactWalkable;
318
348
  exports.isStandardSchema = isStandardSchema;
319
- exports.standaloneAllStandard = standaloneAllStandard;
349
+ exports.mergeSchemasAllStandard = mergeSchemasAllStandard;