elysia 2.0.0-exp.61 → 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 (69) hide show
  1. package/dist/adapter/utils.d.ts +1 -1
  2. package/dist/adapter/web-standard/handler.js +11 -7
  3. package/dist/adapter/web-standard/handler.mjs +12 -8
  4. package/dist/base.d.ts +18 -3
  5. package/dist/base.js +31 -15
  6. package/dist/base.mjs +31 -15
  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/frozen-validator.d.ts +2 -1
  11. package/dist/compile/handler/frozen-validator.js +33 -3
  12. package/dist/compile/handler/frozen-validator.mjs +33 -4
  13. package/dist/compile/handler/index.d.ts +1 -1
  14. package/dist/compile/handler/jit.js +5 -8
  15. package/dist/compile/handler/jit.mjs +6 -9
  16. package/dist/compile/handler/params.js +3 -3
  17. package/dist/compile/handler/params.mjs +4 -4
  18. package/dist/compile/handler/utils.d.ts +1 -1
  19. package/dist/compile/handler/utils.js +5 -2
  20. package/dist/compile/handler/utils.mjs +5 -2
  21. package/dist/compile/lexer.d.ts +1 -1
  22. package/dist/context.d.ts +2 -2
  23. package/dist/cookie/cookie.js +1 -0
  24. package/dist/cookie/cookie.mjs +1 -0
  25. package/dist/error.d.ts +138 -5
  26. package/dist/error.js +73 -0
  27. package/dist/error.mjs +73 -1
  28. package/dist/handler/error.d.ts +20 -1
  29. package/dist/handler/error.js +120 -8
  30. package/dist/handler/error.mjs +119 -9
  31. package/dist/handler/fetch.js +9 -5
  32. package/dist/handler/fetch.mjs +9 -5
  33. package/dist/handler/utils.js +2 -1
  34. package/dist/handler/utils.mjs +3 -2
  35. package/dist/index.d.ts +4 -4
  36. package/dist/index.js +1 -0
  37. package/dist/index.mjs +2 -2
  38. package/dist/plugin/aot/core.d.ts +4 -3
  39. package/dist/plugin/aot/core.js +1 -1
  40. package/dist/plugin/aot/core.mjs +1 -1
  41. package/dist/route-table.d.ts +1 -1
  42. package/dist/sucrose.js +118 -16
  43. package/dist/sucrose.mjs +118 -16
  44. package/dist/type/bridge.d.ts +6 -6
  45. package/dist/type/coerce.js +9 -4
  46. package/dist/type/coerce.mjs +9 -4
  47. package/dist/type/elysia/array-string.js +29 -2
  48. package/dist/type/elysia/array-string.mjs +30 -3
  49. package/dist/type/elysia/file-type.js +11 -1
  50. package/dist/type/elysia/file-type.mjs +11 -1
  51. package/dist/type/elysia/form.js +2 -1
  52. package/dist/type/elysia/form.mjs +2 -1
  53. package/dist/type/elysia/object-string.js +26 -2
  54. package/dist/type/elysia/object-string.mjs +27 -3
  55. package/dist/type/validator/index.js +11 -13
  56. package/dist/type/validator/index.mjs +12 -14
  57. package/dist/types.d.ts +104 -18
  58. package/dist/universal/constants.d.ts +2 -1
  59. package/dist/universal/constants.js +3 -1
  60. package/dist/universal/constants.mjs +2 -1
  61. package/dist/universal/file.js +1 -0
  62. package/dist/universal/file.mjs +1 -0
  63. package/dist/universal/index.d.ts +1 -1
  64. package/dist/utils.d.ts +3 -5
  65. package/dist/utils.js +7 -9
  66. package/dist/utils.mjs +6 -10
  67. package/dist/ws/route.js +1 -1
  68. package/dist/ws/route.mjs +1 -1
  69. 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,16 +21,20 @@ 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":
@@ -66,12 +70,11 @@ 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
79
  case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
77
80
  case "ElysiaFile": return handleElysiaFile(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,16 +20,20 @@ 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":
@@ -65,12 +69,11 @@ 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
78
  case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
76
79
  case "ElysiaFile": return handleElysiaFile(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";
@@ -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,7 +547,7 @@ 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
  }
@@ -568,19 +568,20 @@ var Elysia = class Elysia {
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
@@ -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,7 +544,7 @@ 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
  }
@@ -565,19 +565,20 @@ var Elysia = class Elysia {
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";
@@ -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;
@@ -36,4 +37,4 @@ declare function mergeSchemasAllStandard(schemas: Array<Record<string, unknown>>
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, mergeSchemasAllStandard };
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;
@@ -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
349
  exports.mergeSchemasAllStandard = mergeSchemasAllStandard;
@@ -54,17 +54,30 @@ const typeError = (schema, instancePath, schemaPath) => ({
54
54
  **/
55
55
  function walkCompactError(schema, value, instancePath, schemaPath) {
56
56
  if (!schema || typeof schema !== "object") return;
57
+ const elyTyp = schema["~elyTyp"];
58
+ if (schema.anyOf && (elyTyp === ELYSIA_TYPES.ObjectString || elyTyp === ELYSIA_TYPES.ArrayString)) {
59
+ let decoded = value;
60
+ if (typeof value === "string") try {
61
+ decoded = JSON.parse(value);
62
+ } catch {
63
+ return;
64
+ }
65
+ else if (value === void 0) return;
66
+ return walkCompactError(schema.anyOf[0], decoded, instancePath, `${schemaPath}/anyOf/0`);
67
+ }
57
68
  const type = schema.type;
58
69
  if (type === "object") {
59
70
  if (typeof value !== "object" || value === null || Array.isArray(value)) return typeError(schema, instancePath, schemaPath);
60
71
  const required = schema.required;
61
72
  if (Array.isArray(required)) {
62
- for (const key of required) if (!(key in value)) return {
73
+ let missing;
74
+ for (const key of required) if (!(key in value)) (missing ??= []).push(key);
75
+ if (missing) return {
63
76
  keyword: "required",
64
77
  schemaPath,
65
78
  instancePath,
66
- params: { requiredProperties: [key] },
67
- message: `must have required properties ${key}`
79
+ params: { requiredProperties: missing },
80
+ message: `must have required properties ${missing.join(", ")}`
68
81
  };
69
82
  }
70
83
  const properties = schema.properties;
@@ -120,6 +133,22 @@ function isCompactDiagnosable(schema) {
120
133
  if (type === "array") return isCompactDiagnosable(schema.items);
121
134
  return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
122
135
  }
136
+ function isCompactWalkable(schema) {
137
+ if (!schema || typeof schema !== "object") return false;
138
+ const elyTyp = schema["~elyTyp"];
139
+ if (schema.anyOf && (elyTyp === ELYSIA_TYPES.ObjectString || elyTyp === ELYSIA_TYPES.ArrayString)) return isCompactWalkable(schema.anyOf[0]);
140
+ if (schema.anyOf || schema.oneOf || schema.allOf) return false;
141
+ const type = schema.type;
142
+ if (type === "object") {
143
+ const properties = schema.properties;
144
+ if (properties) {
145
+ for (const key in properties) if (!isCompactWalkable(properties[key])) return false;
146
+ }
147
+ return true;
148
+ }
149
+ if (type === "array") return isCompactWalkable(schema.items);
150
+ return type === "string" || type === "number" || type === "integer" || type === "boolean" || type === "null";
151
+ }
123
152
  var FrozenSlotValidator = class {
124
153
  #check;
125
154
  #clean;
@@ -310,4 +339,4 @@ function isCapturedBridgeFree(c, schema, coerced = schema) {
310
339
  }
311
340
 
312
341
  //#endregion
313
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, mergeSchemasAllStandard };
342
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isCompactWalkable, isStandardSchema, mergeSchemasAllStandard };
@@ -1,5 +1,5 @@
1
- import { AnyLocalHook, CompiledHandler, InternalRoute } from "../../types.js";
2
1
  import { ChainNode } from "../../utils.js";
2
+ import { AnyLocalHook, CompiledHandler, InternalRoute } from "../../types.js";
3
3
  import { AnyElysia } from "../../base.js";
4
4
  import { setCaptureHeaderShorthand } from "./jit.js";
5
5
 
@@ -12,6 +12,7 @@ const require_generation = require('../../generation.js');
12
12
  const require_cookie_utils = require('../../cookie/utils.js');
13
13
  const require_compile_utils = require('../utils.js');
14
14
  const require_handler_utils = require('../../handler/utils.js');
15
+ const require_handler_error = require('../../handler/error.js');
15
16
  const require_compile_handler_utils = require('./utils.js');
16
17
  const require_compile_jit_probe = require('../jit-probe.js');
17
18
 
@@ -360,7 +361,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
360
361
  return s;
361
362
  })() : "";
362
363
  const traceNeedsSchedule = traceHandleOn || phaseOn("afterResponse");
363
- const scheduleAfterResponse = hasAfterResponse || traceNeedsSchedule ? "c._arf=true\nqueueMicrotask(async()=>{if(_stl){try{for await(const v of _stl){}}catch{}}\n" + drainTraceStream + resolveHandlePostDrain + beginTrace("afterResponse", hook?.afterResponse?.length ?? 0) + (hasStaticAfterResponse ? require_compile_handler_utils.mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + (hasDynamicAfterResponse ? `if(c['~afterResponse'])for(let i=0;i<c['~afterResponse'].length;i++){try{await c['~afterResponse'][i](c)}catch{}}\n` : "") + endTrace("afterResponse") + `})\n` : "";
364
+ const scheduleAfterResponse = hasAfterResponse || traceNeedsSchedule ? "c._arf=true\nqueueMicrotask(async()=>{if(_stl){try{for await(const v of _stl){}}catch{}}\n" + drainTraceStream + resolveHandlePostDrain + beginTrace("afterResponse", hook?.afterResponse?.length ?? 0) + (hasStaticAfterResponse ? require_compile_handler_utils.mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + (hasDynamicAfterResponse ? "let _q=c['~afterResponse']\nif(_q){let _l=_q.length\nfor(let _i=0;_i<_l;_i++){try{await _q[_i](c)}catch{}}\n" + (!require_universal_is_production.isProduction() ? `if(_q.length!==_l)console.warn('[elysia] defer() called from inside the afterResponse drain is ignored')\n` : "") + `}\n` : "") + endTrace("afterResponse") + `})\n` : "";
364
365
  const dedupSchedule = !!scheduleAfterResponse && (hasErrorHook || hasTrace) && !syncAfterResponse && !syncErrorHook;
365
366
  const scheduleDecl = dedupSchedule ? `function _sc(){\n${scheduleAfterResponse}}\n` : "";
366
367
  const schedule = dedupSchedule ? `_sc()\n` : scheduleAfterResponse;
@@ -482,12 +483,10 @@ if(_vr)_r.response=${awaitStr}${responseValiAsync ? `(_vr.mayReturnPromise?_vr.F
482
483
  }
483
484
  if (hasErrorHook) {
484
485
  link(hook.error, "er");
485
- link(require_error.ElysiaStatus, "es");
486
- link(require_error.internalServerErrorResponse, "ise");
487
- link(require_universal_is_production.isProduction, "isprod");
486
+ link(require_handler_error.fallbackResponse, "fbr");
488
487
  const allowUnsafeDetail = !!root["~config"]?.allowUnsafeValidationDetails;
489
488
  if (allowUnsafeDetail) link(require_error.ValidationError, "verr");
490
- factoryHelpers += `function _em(c,_r){return typeof _r?.then==='function'?Promise.resolve(_r).catch((_e)=>fre(rt,c,_e)):_r}\n${asyncCookieSign ? "async " : ""}function _efb(e,c){\n` + (asyncCookieSign ? `let _sg\n` : ``) + `if(e instanceof es){${signPrefix}return _em(c,${map}(e,c.set,c.request,true))}\nif(e?.status){${signPrefix}return _em(c,${map}(e?.response!==undefined?e.response:(isprod()&&e.status>=500?'Internal Server Error':(e?.message??'')),c.set,c.request,true))}\nc.set.status=500\n` + signPrefix + `return _em(c,${map}(ise(e),c.set,c.request,true))\n}\n`;
489
+ factoryHelpers += `function _em(c,_r){return typeof _r?.then==='function'?Promise.resolve(_r).catch((_e)=>fre(rt,c,_e)):_r}\nfunction _fbm(_r,_s,_c){return ${map}(_r,_s,_c.request,true)}\n${asyncCookieSign ? "async " : ""}function _efb(e,c){\n` + (asyncCookieSign ? `let _sg\n` : ``) + signPrefix + "return _em(c,fbr(c,e,_fbm))\n}\n";
491
490
  body += `c.error=e\n` + (allowUnsafeDetail ? `if(e instanceof verr)e.allowUnsafeValidationDetails=true\n` : ``) + `if(e?.status)c.set.status=e.status
492
491
  else if(c.set.status===undefined||c.set.status===200)c.set.status=500
493
492
  let _r${hasMapResponse ? ",tmp" : ""}\n` + require_compile_handler_utils.mapError(hook.error, [
@@ -497,9 +496,7 @@ let _r${hasMapResponse ? ",tmp" : ""}\n` + require_compile_handler_utils.mapErro
497
496
  (hasMapResponse ? `c.responseValue=_r\n` + require_compile_handler_utils.mapMapResponse(hook.mapResponse, isAsync, void 0, abortOn ? abortArm : void 0) : "") + endTrace("error") + abortCatch + schedule,
498
497
  signPrefix,
499
498
  isAsync
500
- ], abortOn ? abortArm : void 0) + endTrace("error") + abortCatch + schedule + `if(typeof e?.toResponse==='function')try{
501
- const _er=e.toResponse()
502
- if(typeof _er?.then==='function')return Promise.resolve(_er).then(${asyncCookieSign ? "async " : ""}(_v)=>{if(_v instanceof Response){${signPrefix}return _em(c,${map}(_v,c.set,c.request,true))}return _efb(e,c)},()=>_efb(e,c)).catch((_e)=>fre(rt,c,_e))\nif(_er instanceof Response){${signPrefix}return _em(c,${map}(_er,c.set,c.request,true))}\n}catch{}\nreturn _efb(e,c)\n`;
499
+ ], abortOn ? abortArm : void 0) + endTrace("error") + abortCatch + schedule + `return _efb(e,c)\n`;
503
500
  } else {
504
501
  body += endTrace("error") + schedule;
505
502
  body += `return fre(rt,c,e)\n`;
@@ -3,7 +3,7 @@ import { isDynamicRegex, traceEventIndex } from "../../constants.mjs";
3
3
  import { requestId } from "../../utils.mjs";
4
4
  import { isProduction } from "../../universal/is-production.mjs";
5
5
  import { ELYSIA_TYPES } from "../../type/constants.mjs";
6
- import { ElysiaStatus, ParseError, ValidationError, internalServerErrorResponse } from "../../error.mjs";
6
+ import { ElysiaStatus, ParseError, ValidationError } from "../../error.mjs";
7
7
  import { materializeSetHeaders, normalizeContentType, tee } from "../../adapter/utils.mjs";
8
8
  import { parseQueryFromURL } from "../../parse-query.mjs";
9
9
  import { Capture } from "../aot.mjs";
@@ -11,6 +11,7 @@ import { resolvedTraceOf, traceCapabilityRequired } from "../../generation.mjs";
11
11
  import { buildCookieJar, parseCookieRaw, parseCookieRawDeferred, parseCookieRawLazy, parseCookieRawSigned, parseCookieRawSync, signCookieValues } from "../../cookie/utils.mjs";
12
12
  import { isAsyncFunction } from "../utils.mjs";
13
13
  import { emptyResponse, finalizeRouteError, forwardError } from "../../handler/utils.mjs";
14
+ import { fallbackResponse } from "../../handler/error.mjs";
14
15
  import { armEntryAbort, cloneResponse, getQueryParseChannels, hasRequestBody, mapAfterHandle, mapAfterResponse, mapBeforeHandle, mapError, mapMapResponse, mapTransform, runBeforeHandlePrefix, runBeforeHandlePrefixAsync } from "./utils.mjs";
15
16
  import { JITProbe } from "../jit-probe.mjs";
16
17
 
@@ -359,7 +360,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
359
360
  return s;
360
361
  })() : "";
361
362
  const traceNeedsSchedule = traceHandleOn || phaseOn("afterResponse");
362
- const scheduleAfterResponse = hasAfterResponse || traceNeedsSchedule ? "c._arf=true\nqueueMicrotask(async()=>{if(_stl){try{for await(const v of _stl){}}catch{}}\n" + drainTraceStream + resolveHandlePostDrain + beginTrace("afterResponse", hook?.afterResponse?.length ?? 0) + (hasStaticAfterResponse ? mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + (hasDynamicAfterResponse ? `if(c['~afterResponse'])for(let i=0;i<c['~afterResponse'].length;i++){try{await c['~afterResponse'][i](c)}catch{}}\n` : "") + endTrace("afterResponse") + `})\n` : "";
363
+ const scheduleAfterResponse = hasAfterResponse || traceNeedsSchedule ? "c._arf=true\nqueueMicrotask(async()=>{if(_stl){try{for await(const v of _stl){}}catch{}}\n" + drainTraceStream + resolveHandlePostDrain + beginTrace("afterResponse", hook?.afterResponse?.length ?? 0) + (hasStaticAfterResponse ? mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + (hasDynamicAfterResponse ? "let _q=c['~afterResponse']\nif(_q){let _l=_q.length\nfor(let _i=0;_i<_l;_i++){try{await _q[_i](c)}catch{}}\n" + (!isProduction() ? `if(_q.length!==_l)console.warn('[elysia] defer() called from inside the afterResponse drain is ignored')\n` : "") + `}\n` : "") + endTrace("afterResponse") + `})\n` : "";
363
364
  const dedupSchedule = !!scheduleAfterResponse && (hasErrorHook || hasTrace) && !syncAfterResponse && !syncErrorHook;
364
365
  const scheduleDecl = dedupSchedule ? `function _sc(){\n${scheduleAfterResponse}}\n` : "";
365
366
  const schedule = dedupSchedule ? `_sc()\n` : scheduleAfterResponse;
@@ -481,12 +482,10 @@ if(_vr)_r.response=${awaitStr}${responseValiAsync ? `(_vr.mayReturnPromise?_vr.F
481
482
  }
482
483
  if (hasErrorHook) {
483
484
  link(hook.error, "er");
484
- link(ElysiaStatus, "es");
485
- link(internalServerErrorResponse, "ise");
486
- link(isProduction, "isprod");
485
+ link(fallbackResponse, "fbr");
487
486
  const allowUnsafeDetail = !!root["~config"]?.allowUnsafeValidationDetails;
488
487
  if (allowUnsafeDetail) link(ValidationError, "verr");
489
- factoryHelpers += `function _em(c,_r){return typeof _r?.then==='function'?Promise.resolve(_r).catch((_e)=>fre(rt,c,_e)):_r}\n${asyncCookieSign ? "async " : ""}function _efb(e,c){\n` + (asyncCookieSign ? `let _sg\n` : ``) + `if(e instanceof es){${signPrefix}return _em(c,${map}(e,c.set,c.request,true))}\nif(e?.status){${signPrefix}return _em(c,${map}(e?.response!==undefined?e.response:(isprod()&&e.status>=500?'Internal Server Error':(e?.message??'')),c.set,c.request,true))}\nc.set.status=500\n` + signPrefix + `return _em(c,${map}(ise(e),c.set,c.request,true))\n}\n`;
488
+ factoryHelpers += `function _em(c,_r){return typeof _r?.then==='function'?Promise.resolve(_r).catch((_e)=>fre(rt,c,_e)):_r}\nfunction _fbm(_r,_s,_c){return ${map}(_r,_s,_c.request,true)}\n${asyncCookieSign ? "async " : ""}function _efb(e,c){\n` + (asyncCookieSign ? `let _sg\n` : ``) + signPrefix + "return _em(c,fbr(c,e,_fbm))\n}\n";
490
489
  body += `c.error=e\n` + (allowUnsafeDetail ? `if(e instanceof verr)e.allowUnsafeValidationDetails=true\n` : ``) + `if(e?.status)c.set.status=e.status
491
490
  else if(c.set.status===undefined||c.set.status===200)c.set.status=500
492
491
  let _r${hasMapResponse ? ",tmp" : ""}\n` + mapError(hook.error, [
@@ -496,9 +495,7 @@ let _r${hasMapResponse ? ",tmp" : ""}\n` + mapError(hook.error, [
496
495
  (hasMapResponse ? `c.responseValue=_r\n` + mapMapResponse(hook.mapResponse, isAsync, void 0, abortOn ? abortArm : void 0) : "") + endTrace("error") + abortCatch + schedule,
497
496
  signPrefix,
498
497
  isAsync
499
- ], abortOn ? abortArm : void 0) + endTrace("error") + abortCatch + schedule + `if(typeof e?.toResponse==='function')try{
500
- const _er=e.toResponse()
501
- if(typeof _er?.then==='function')return Promise.resolve(_er).then(${asyncCookieSign ? "async " : ""}(_v)=>{if(_v instanceof Response){${signPrefix}return _em(c,${map}(_v,c.set,c.request,true))}return _efb(e,c)},()=>_efb(e,c)).catch((_e)=>fre(rt,c,_e))\nif(_er instanceof Response){${signPrefix}return _em(c,${map}(_er,c.set,c.request,true))}\n}catch{}\nreturn _efb(e,c)\n`;
498
+ ], abortOn ? abortArm : void 0) + endTrace("error") + abortCatch + schedule + `return _efb(e,c)\n`;
502
499
  } else {
503
500
  body += endTrace("error") + schedule;
504
501
  body += `return fre(rt,c,e)\n`;