elysia 2.0.0-exp.60 → 2.0.0-exp.61

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.
@@ -34,7 +34,7 @@ function mapResponseWithSet(response, set, request, owned) {
34
34
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
35
35
  return Response.json(response, set);
36
36
  case "Number":
37
- case "Boolean": return new Response(response.toString(), set);
37
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString(), set);
38
38
  case "ElysiaFile": return handleElysiaFile(response, set, request);
39
39
  case "File":
40
40
  case "Blob": return require_adapter_utils.handleFile(response, set, request);
@@ -73,7 +73,7 @@ function mapCompactResponse(response, request, owned) {
73
73
  if (response["~ely-form"]) return new Response(require_utils.formToFormData(response));
74
74
  return Response.json(response);
75
75
  case "Number":
76
- case "Boolean": return new Response(response.toString());
76
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
77
77
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
78
78
  case "File":
79
79
  case "Blob": return require_adapter_utils.handleFile(response, void 0, request);
@@ -33,7 +33,7 @@ function mapResponseWithSet(response, set, request, owned) {
33
33
  if (typeof response?.next === "function") return handleStream(response, set, request, void 0, owned);
34
34
  return Response.json(response, set);
35
35
  case "Number":
36
- case "Boolean": return new Response(response.toString(), set);
36
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString(), set);
37
37
  case "ElysiaFile": return handleElysiaFile(response, set, request);
38
38
  case "File":
39
39
  case "Blob": return handleFile(response, set, request);
@@ -72,7 +72,7 @@ function mapCompactResponse(response, request, owned) {
72
72
  if (response["~ely-form"]) return new Response(formToFormData(response));
73
73
  return Response.json(response);
74
74
  case "Number":
75
- case "Boolean": return new Response(response.toString());
75
+ case "Boolean": return new Response(typeof response === "boolean" ? response ? "true" : "false" : response.toString());
76
76
  case "ElysiaFile": return handleElysiaFile(response, void 0, request);
77
77
  case "File":
78
78
  case "Blob": return handleFile(response, void 0, request);
package/dist/base.d.ts CHANGED
@@ -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'];
package/dist/base.js CHANGED
@@ -554,7 +554,7 @@ var Elysia = class Elysia {
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,7 +564,7 @@ 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
  }
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";
@@ -551,7 +551,7 @@ var Elysia = class Elysia {
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,7 +561,7 @@ 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
  }
@@ -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));
@@ -32,8 +32,8 @@ interface FrozenRouteValidatorShape {
32
32
  response?: Record<number, FrozenSlotValidator>;
33
33
  }
34
34
  declare const isStandardSchema: (schema: unknown) => schema is object & Record<"~standard", unknown>;
35
- declare function standaloneAllStandard(schemas: Array<Record<string, unknown>> | undefined): boolean;
35
+ declare function mergeSchemasAllStandard(schemas: Array<Record<string, unknown>> | undefined): boolean;
36
36
  declare function buildFrozenRouteValidator(hook: AnyLocalHook, root: AnyElysia, method: HTTPMethod, path: string): FrozenRouteValidatorShape | undefined;
37
37
  declare function isCapturedBridgeFree(c: CapturedValidator, schema: unknown, coerced?: unknown): boolean;
38
38
  //#endregion
39
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, standaloneAllStandard };
39
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, mergeSchemasAllStandard };
@@ -224,7 +224,7 @@ const REQUEST_SLOTS = [
224
224
  "cookie"
225
225
  ];
226
226
  const isStandardSchema = (schema) => schema != null && typeof schema === "object" && "~standard" in schema;
227
- function standaloneAllStandard(schemas) {
227
+ function mergeSchemasAllStandard(schemas) {
228
228
  if (!schemas || schemas.length === 0) return true;
229
229
  for (const entry of schemas) for (const key in entry) {
230
230
  const value = entry[key];
@@ -316,4 +316,4 @@ exports.isBridgeNotInitialized = isBridgeNotInitialized;
316
316
  exports.isCapturedBridgeFree = isCapturedBridgeFree;
317
317
  exports.isCompactDiagnosable = isCompactDiagnosable;
318
318
  exports.isStandardSchema = isStandardSchema;
319
- exports.standaloneAllStandard = standaloneAllStandard;
319
+ exports.mergeSchemasAllStandard = mergeSchemasAllStandard;
@@ -223,7 +223,7 @@ const REQUEST_SLOTS = [
223
223
  "cookie"
224
224
  ];
225
225
  const isStandardSchema = (schema) => schema != null && typeof schema === "object" && "~standard" in schema;
226
- function standaloneAllStandard(schemas) {
226
+ function mergeSchemasAllStandard(schemas) {
227
227
  if (!schemas || schemas.length === 0) return true;
228
228
  for (const entry of schemas) for (const key in entry) {
229
229
  const value = entry[key];
@@ -310,4 +310,4 @@ function isCapturedBridgeFree(c, schema, coerced = schema) {
310
310
  }
311
311
 
312
312
  //#endregion
313
- export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, standaloneAllStandard };
313
+ export { buildFrozenRouteValidator, isBridgeNotInitialized, isCapturedBridgeFree, isCompactDiagnosable, isStandardSchema, mergeSchemasAllStandard };
@@ -158,6 +158,8 @@ const createInlineHandlerWithDefaultHeaders = (map, h) => ((c) => {
158
158
  });
159
159
  function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, state }) {
160
160
  const { vali, inference, cookieConfig, beforeHandlePrefix, traceHandlers, tracePhases, hasAnyPhase, traceHandleOn, descriptor: { async: isAsync, responseMode, hasBody, bodyValiIsAsync, headersValiIsAsync, paramsValiIsAsync, queryValiIsAsync, cookieValiIsAsync: cookieValidIsAsync, responseValiAsync, hasCookieSign, syncCookieSign, asyncCookieSign, lazyCookieVerify, hasErrorHook, hasAfterResponse, hasBeforeHandle, hasAfterHandle, hasMapResponse, hasResponseValidator, hasTrace, traceCount, hasLifecycleHook, callHandlerSyncOnAsync, syncErrorHook, syncAfterResponse } } = state;
161
+ const hasStaticAfterResponse = !!hook?.afterResponse?.length;
162
+ const hasDynamicAfterResponse = !!inference.afterResponse;
161
163
  const seenKeys = new Set(["rt", "fre"]);
162
164
  const paramValues = [errorRoot, require_handler_utils.finalizeRouteError];
163
165
  const aliasKeys = [];
@@ -350,7 +352,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
350
352
  if (isStaticResponse || isPromiseHandler) link(require_compile_handler_utils.cloneResponse, "cr");
351
353
  const handleInstruction = isHandleFunction ? "h(c)" : isStaticResponse ? "cr(h)" : isPromiseHandler ? "h.then(cr)" : "h";
352
354
  const mapReturn = hasSet ? `rm(${handleInstruction},c.set,c.request,true)\n` : `rc(${handleInstruction},c.request,true)\n`;
353
- if (hasAfterResponse) link(hook.afterResponse, "ar");
355
+ if (hasStaticAfterResponse) link(hook.afterResponse, "ar");
354
356
  const drainTraceStream = traceHandleOn ? `let _ser\nif(_trs){try{for await(const v of _trs){}}catch(_te){_ser=_te}}\n` : "";
355
357
  const resolveHandlePostDrain = traceHandleOn ? (() => {
356
358
  let s = "";
@@ -358,7 +360,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
358
360
  return s;
359
361
  })() : "";
360
362
  const traceNeedsSchedule = traceHandleOn || phaseOn("afterResponse");
361
- 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) + (hasAfterResponse ? require_compile_handler_utils.mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + 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 ? 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` : "";
362
364
  const dedupSchedule = !!scheduleAfterResponse && (hasErrorHook || hasTrace) && !syncAfterResponse && !syncErrorHook;
363
365
  const scheduleDecl = dedupSchedule ? `function _sc(){\n${scheduleAfterResponse}}\n` : "";
364
366
  const schedule = dedupSchedule ? `_sc()\n` : scheduleAfterResponse;
@@ -157,6 +157,8 @@ const createInlineHandlerWithDefaultHeaders = (map, h) => ((c) => {
157
157
  });
158
158
  function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, state }) {
159
159
  const { vali, inference, cookieConfig, beforeHandlePrefix, traceHandlers, tracePhases, hasAnyPhase, traceHandleOn, descriptor: { async: isAsync, responseMode, hasBody, bodyValiIsAsync, headersValiIsAsync, paramsValiIsAsync, queryValiIsAsync, cookieValiIsAsync: cookieValidIsAsync, responseValiAsync, hasCookieSign, syncCookieSign, asyncCookieSign, lazyCookieVerify, hasErrorHook, hasAfterResponse, hasBeforeHandle, hasAfterHandle, hasMapResponse, hasResponseValidator, hasTrace, traceCount, hasLifecycleHook, callHandlerSyncOnAsync, syncErrorHook, syncAfterResponse } } = state;
160
+ const hasStaticAfterResponse = !!hook?.afterResponse?.length;
161
+ const hasDynamicAfterResponse = !!inference.afterResponse;
160
162
  const seenKeys = new Set(["rt", "fre"]);
161
163
  const paramValues = [errorRoot, finalizeRouteError];
162
164
  const aliasKeys = [];
@@ -349,7 +351,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
349
351
  if (isStaticResponse || isPromiseHandler) link(cloneResponse, "cr");
350
352
  const handleInstruction = isHandleFunction ? "h(c)" : isStaticResponse ? "cr(h)" : isPromiseHandler ? "h.then(cr)" : "h";
351
353
  const mapReturn = hasSet ? `rm(${handleInstruction},c.set,c.request,true)\n` : `rc(${handleInstruction},c.request,true)\n`;
352
- if (hasAfterResponse) link(hook.afterResponse, "ar");
354
+ if (hasStaticAfterResponse) link(hook.afterResponse, "ar");
353
355
  const drainTraceStream = traceHandleOn ? `let _ser\nif(_trs){try{for await(const v of _trs){}}catch(_te){_ser=_te}}\n` : "";
354
356
  const resolveHandlePostDrain = traceHandleOn ? (() => {
355
357
  let s = "";
@@ -357,7 +359,7 @@ function compileHandlerJit({ method, path, handler, root, errorRoot, hook, adapt
357
359
  return s;
358
360
  })() : "";
359
361
  const traceNeedsSchedule = traceHandleOn || phaseOn("afterResponse");
360
- 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) + (hasAfterResponse ? mapAfterResponse(hook.afterResponse, [buildReport("afterResponse")]) : "") + endTrace("afterResponse") + `})\n` : "";
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` : "";
361
363
  const dedupSchedule = !!scheduleAfterResponse && (hasErrorHook || hasTrace) && !syncAfterResponse && !syncErrorHook;
362
364
  const scheduleDecl = dedupSchedule ? `function _sc(){\n${scheduleAfterResponse}}\n` : "";
363
365
  const schedule = dedupSchedule ? `_sc()\n` : scheduleAfterResponse;
@@ -62,6 +62,7 @@ function replaceDeriveContext(context, derivative) {
62
62
  Object.assign(next, derivative);
63
63
  next.request = context.request;
64
64
  next["~sig"] = context["~sig"];
65
+ next["~afterResponse"] = context["~afterResponse"];
65
66
  next.store = context.store;
66
67
  next.set = context.set;
67
68
  next.body = context.body;
@@ -61,6 +61,7 @@ function replaceDeriveContext(context, derivative) {
61
61
  Object.assign(next, derivative);
62
62
  next.request = context.request;
63
63
  next["~sig"] = context["~sig"];
64
+ next["~afterResponse"] = context["~afterResponse"];
64
65
  next.store = context.store;
65
66
  next.set = context.set;
66
67
  next.body = context.body;
package/dist/context.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Cookie } from "./cookie/cookie.js";
3
3
  import { StatusMap } from "./constants.js";
4
4
  import { SelectiveStatus, status } from "./error.js";
5
5
  import { Server } from "./universal/server.js";
6
- import { DefaultSingleton, HTTPHeaders, InputSchema, Prettify, ResolvePath, RouteSchema, SingletonBase } from "./types.js";
6
+ import { AfterResponseHandler, DefaultSingleton, HTTPHeaders, InputSchema, MaybePromise, Prettify, ResolvePath, RouteSchema, SingletonBase } from "./types.js";
7
7
  import { redirect } from "./utils.js";
8
8
  import { AnyElysia } from "./base.js";
9
9
 
@@ -25,6 +25,10 @@ interface ContextBase<in out Route extends RouteSchema, in out Singleton extends
25
25
  cookie?: Record<string, BaseCookie>;
26
26
  };
27
27
  status: {} extends Route['response'] ? typeof status : SelectiveStatus<Route['response']>;
28
+ /**
29
+ * Append a callback to run after the response is sent
30
+ */
31
+ defer(fn: AfterResponseHandler<Route, Singleton>): MaybePromise<void>;
28
32
  /**
29
33
  * Path extracted from incoming URL
30
34
  *
package/dist/context.js CHANGED
@@ -8,12 +8,22 @@ const require_adapter_default_headers = require('./adapter/default-headers.js');
8
8
  let contextCache = /* @__PURE__ */ new WeakMap();
9
9
  let sharedEmptyDecorator = null;
10
10
  let sharedEmptyContext = null;
11
+ const defer = {
12
+ configurable: true,
13
+ get() {
14
+ const queue = this["~afterResponse"] ??= [];
15
+ const append = (fn) => queue.push(fn);
16
+ Object.defineProperty(this, "defer", { value: append });
17
+ return append;
18
+ }
19
+ };
11
20
  function buildEmptyDecorator() {
12
21
  class Decorator {}
13
22
  Object.assign(Decorator.prototype, {
14
23
  status: require_error.status,
15
24
  redirect: require_utils.redirect
16
25
  });
26
+ Object.defineProperty(Decorator.prototype, "defer", defer);
17
27
  return Decorator;
18
28
  }
19
29
  function createBaseContext(app) {
@@ -28,6 +38,7 @@ function createBaseContext(app) {
28
38
  status: require_error.status,
29
39
  redirect: require_utils.redirect
30
40
  });
41
+ Object.defineProperty(Decorator.prototype, "defer", defer);
31
42
  return Decorator;
32
43
  }
33
44
  function clearContextCache() {
package/dist/context.mjs CHANGED
@@ -7,12 +7,22 @@ import { defaultHeaders } from "./adapter/default-headers.mjs";
7
7
  let contextCache = /* @__PURE__ */ new WeakMap();
8
8
  let sharedEmptyDecorator = null;
9
9
  let sharedEmptyContext = null;
10
+ const defer = {
11
+ configurable: true,
12
+ get() {
13
+ const queue = this["~afterResponse"] ??= [];
14
+ const append = (fn) => queue.push(fn);
15
+ Object.defineProperty(this, "defer", { value: append });
16
+ return append;
17
+ }
18
+ };
10
19
  function buildEmptyDecorator() {
11
20
  class Decorator {}
12
21
  Object.assign(Decorator.prototype, {
13
22
  status,
14
23
  redirect
15
24
  });
25
+ Object.defineProperty(Decorator.prototype, "defer", defer);
16
26
  return Decorator;
17
27
  }
18
28
  function createBaseContext(app) {
@@ -27,6 +37,7 @@ function createBaseContext(app) {
27
37
  status,
28
38
  redirect
29
39
  });
40
+ Object.defineProperty(Decorator.prototype, "defer", defer);
30
41
  return Decorator;
31
42
  }
32
43
  function clearContextCache() {
@@ -15,7 +15,8 @@ deuri = require_runtime.__toESM(deuri);
15
15
  //#region src/handler/fetch.ts
16
16
  function extractPath(url, context, pathStart) {
17
17
  const s = url.indexOf("/", pathStart);
18
- return context.path = url.substring(s, (context.qi = url.indexOf("?", s)) === -1 ? url.length : context.qi);
18
+ const q = context.qi = url.indexOf("?", s);
19
+ return context.path = q === -1 ? url.slice(s) : url.substring(s, q);
19
20
  }
20
21
  function notFound(context) {
21
22
  const set = context.set;
@@ -162,18 +163,23 @@ function createFetchHandler(app) {
162
163
  const traceAfterResponsePhase = hasTrace && (tracePhases === null || tracePhases.has("afterResponse"));
163
164
  const tracerFactories = hasTrace ? traceHandlers.map((fn) => traceProvider.createTracer(fn)) : void 0;
164
165
  const afterResponses = hook?.afterResponse;
165
- const afterResponse = afterResponses?.length || traceAfterResponsePhase ? (context, status) => {
166
+ const afterResponse = (context, status) => {
166
167
  if (context._arf) return;
168
+ const queue = context["~afterResponse"];
169
+ if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length) return;
167
170
  context._arf = true;
168
171
  if (status !== void 0) context.set.status = status;
169
172
  queueMicrotask(async () => {
170
- if (afterResponses) {
171
- require_adapter_utils.materializeSetHeaders(context.set);
172
- for (let i = 0; i < afterResponses.length; i++) try {
173
- await afterResponses[i](context);
174
- } catch (e) {
175
- console.error(e);
176
- }
173
+ if (afterResponses?.length || queue?.length) require_adapter_utils.materializeSetHeaders(context.set);
174
+ if (afterResponses) for (let i = 0; i < afterResponses.length; i++) try {
175
+ await afterResponses[i](context);
176
+ } catch (e) {
177
+ console.error(e);
178
+ }
179
+ if (queue) for (let i = 0; i < queue.length; i++) try {
180
+ await queue[i](context);
181
+ } catch (e) {
182
+ console.error(e);
177
183
  }
178
184
  if (traceAfterResponsePhase) {
179
185
  let cache = context.trace;
@@ -198,7 +204,7 @@ function createFetchHandler(app) {
198
204
  }
199
205
  }
200
206
  });
201
- } : void 0;
207
+ };
202
208
  app["~finalizeError"] = (context, error) => finalizeError(context, handleError, afterResponse, error);
203
209
  if (traceRequestPhase) {
204
210
  const onRequests = hook?.request ?? [];
@@ -12,7 +12,8 @@ import decodeComponent from "deuri";
12
12
  //#region src/handler/fetch.ts
13
13
  function extractPath(url, context, pathStart) {
14
14
  const s = url.indexOf("/", pathStart);
15
- return context.path = url.substring(s, (context.qi = url.indexOf("?", s)) === -1 ? url.length : context.qi);
15
+ const q = context.qi = url.indexOf("?", s);
16
+ return context.path = q === -1 ? url.slice(s) : url.substring(s, q);
16
17
  }
17
18
  function notFound(context) {
18
19
  const set = context.set;
@@ -159,18 +160,23 @@ function createFetchHandler(app) {
159
160
  const traceAfterResponsePhase = hasTrace && (tracePhases === null || tracePhases.has("afterResponse"));
160
161
  const tracerFactories = hasTrace ? traceHandlers.map((fn) => traceProvider.createTracer(fn)) : void 0;
161
162
  const afterResponses = hook?.afterResponse;
162
- const afterResponse = afterResponses?.length || traceAfterResponsePhase ? (context, status) => {
163
+ const afterResponse = (context, status) => {
163
164
  if (context._arf) return;
165
+ const queue = context["~afterResponse"];
166
+ if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length) return;
164
167
  context._arf = true;
165
168
  if (status !== void 0) context.set.status = status;
166
169
  queueMicrotask(async () => {
167
- if (afterResponses) {
168
- materializeSetHeaders(context.set);
169
- for (let i = 0; i < afterResponses.length; i++) try {
170
- await afterResponses[i](context);
171
- } catch (e) {
172
- console.error(e);
173
- }
170
+ if (afterResponses?.length || queue?.length) materializeSetHeaders(context.set);
171
+ if (afterResponses) for (let i = 0; i < afterResponses.length; i++) try {
172
+ await afterResponses[i](context);
173
+ } catch (e) {
174
+ console.error(e);
175
+ }
176
+ if (queue) for (let i = 0; i < queue.length; i++) try {
177
+ await queue[i](context);
178
+ } catch (e) {
179
+ console.error(e);
174
180
  }
175
181
  if (traceAfterResponsePhase) {
176
182
  let cache = context.trace;
@@ -195,7 +201,7 @@ function createFetchHandler(app) {
195
201
  }
196
202
  }
197
203
  });
198
- } : void 0;
204
+ };
199
205
  app["~finalizeError"] = (context, error) => finalizeError(context, handleError, afterResponse, error);
200
206
  if (traceRequestPhase) {
201
207
  const onRequests = hook?.request ?? [];
package/dist/package.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region package.json
3
- var version = "2.0.0-exp.60";
3
+ var version = "2.0.0-exp.61";
4
4
 
5
5
  //#endregion
6
6
  Object.defineProperty(exports, 'version', {
package/dist/package.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "2.0.0-exp.60";
2
+ var version = "2.0.0-exp.61";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -444,9 +444,9 @@ async function generateCompiledArtifacts(file, options) {
444
444
  routeHasTypeBoxDirectSlot = true;
445
445
  expectedSlots++;
446
446
  }
447
- const standalone = hooks.schemas;
448
- if (Array.isArray(standalone) && standalone.length > 0) {
449
- if (routeHasTypeBoxDirectSlot || !require_compile_handler_frozen_validator.standaloneAllStandard(standalone)) routesForbidSeal = true;
447
+ const mergeSchemas = hooks.schemas;
448
+ if (Array.isArray(mergeSchemas) && mergeSchemas.length > 0) {
449
+ if (routeHasTypeBoxDirectSlot || !require_compile_handler_frozen_validator.mergeSchemasAllStandard(mergeSchemas)) routesForbidSeal = true;
450
450
  }
451
451
  }
452
452
  if (typedApp["~config"]?.normalize === "typebox") routesForbidSeal = true;
@@ -1,4 +1,4 @@
1
- import { isStandardSchema, standaloneAllStandard } from "../../compile/handler/frozen-validator.mjs";
1
+ import { isStandardSchema, mergeSchemasAllStandard } from "../../compile/handler/frozen-validator.mjs";
2
2
  import { composeRouteHook } from "../../compile/handler/index.mjs";
3
3
  import { captureArtifacts, compileToSource, replayStubbability } from "./source.mjs";
4
4
  import { createRequire } from "node:module";
@@ -442,9 +442,9 @@ async function generateCompiledArtifacts(file, options) {
442
442
  routeHasTypeBoxDirectSlot = true;
443
443
  expectedSlots++;
444
444
  }
445
- const standalone = hooks.schemas;
446
- if (Array.isArray(standalone) && standalone.length > 0) {
447
- if (routeHasTypeBoxDirectSlot || !standaloneAllStandard(standalone)) routesForbidSeal = true;
445
+ const mergeSchemas = hooks.schemas;
446
+ if (Array.isArray(mergeSchemas) && mergeSchemas.length > 0) {
447
+ if (routeHasTypeBoxDirectSlot || !mergeSchemasAllStandard(mergeSchemas)) routesForbidSeal = true;
448
448
  }
449
449
  }
450
450
  if (typedApp["~config"]?.normalize === "typebox") routesForbidSeal = true;
package/dist/sucrose.d.ts CHANGED
@@ -9,6 +9,7 @@ declare namespace Sucrose {
9
9
  cookie: boolean;
10
10
  set: boolean;
11
11
  route: boolean;
12
+ afterResponse?: boolean;
12
13
  }
13
14
  type LifeCycle = Partial<Partial<AppHook>>;
14
15
  }
@@ -67,14 +68,7 @@ declare function retrieveRootparameters(parameter: string): {
67
68
  declare function findAlias(type: string, body: string, seen?: Set<string>): string[];
68
69
  declare function removeDefaultParameter(parameter: string): string;
69
70
  declare function clearSucroseCache(delay?: number | null): void;
70
- declare const mergeInference: (a: Sucrose.Inference, b: Sucrose.Inference) => {
71
- body: boolean;
72
- cookie: boolean;
73
- headers: boolean;
74
- query: boolean;
75
- set: boolean;
76
- route: boolean;
77
- };
71
+ declare const mergeInference: (a: Sucrose.Inference, b: Sucrose.Inference) => Sucrose.Inference;
78
72
  declare function sucrose(handler: Handler | undefined, lifeCycle: Sucrose.LifeCycle | undefined): Sucrose.Inference;
79
73
  //#endregion
80
74
  export { Sucrose, bracketPairRange, bracketPairRangeReverse, clearSucroseCache, findAlias, mergeInference, removeColonAlias, removeDefaultParameter, retrieveRootparameters, separateFunction, sucrose };
package/dist/sucrose.js CHANGED
@@ -272,6 +272,7 @@ function removeDefaultParameter(parameter) {
272
272
  }
273
273
  function markAllAccessed(i) {
274
274
  i.query = i.headers = i.body = i.cookie = i.set = i.route = true;
275
+ i.afterResponse = true;
275
276
  }
276
277
  const DEFAULT_CACHE_LIMIT = 1024;
277
278
  const globalSourceCache = /* @__PURE__ */ new Map();
@@ -305,7 +306,8 @@ const mergeInference = (a, b) => ({
305
306
  headers: a.headers || b.headers,
306
307
  query: a.query || b.query,
307
308
  set: a.set || b.set,
308
- route: a.route || b.route
309
+ route: a.route || b.route,
310
+ ...a.afterResponse || b.afterResponse ? { afterResponse: true } : {}
309
311
  });
310
312
  const defaultSucrose = () => ({
311
313
  query: false,
@@ -563,6 +565,7 @@ const channel = (value) => {
563
565
  case "cookie":
564
566
  case "set":
565
567
  case "route": return value;
568
+ case "defer": return "afterResponse";
566
569
  }
567
570
  };
568
571
  function computedDestructuringChannel(tokens, index) {
@@ -731,7 +734,7 @@ function inferFunction(source) {
731
734
  const key = property?.k === "s" && channel(property.value);
732
735
  if (key && tokens[next + 2]?.value === "]") inference[key] = true;
733
736
  else markAllAccessed(inference);
734
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route) break;
737
+ if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route && inference.afterResponse) break;
735
738
  continue;
736
739
  }
737
740
  if (tokens[i - 1]?.value === "=" && (tokens[i - 2]?.k === "i" || tokens[i - 2]?.value === "}")) continue;
@@ -790,7 +793,7 @@ function sucrose(handler, lifeCycle) {
790
793
  inference = mergeInference(inference, inferred);
791
794
  merged = true;
792
795
  } else inference = inferred;
793
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route) break;
796
+ if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route && inference.afterResponse) break;
794
797
  }
795
798
  } finally {
796
799
  events.length = 0;
package/dist/sucrose.mjs CHANGED
@@ -271,6 +271,7 @@ function removeDefaultParameter(parameter) {
271
271
  }
272
272
  function markAllAccessed(i) {
273
273
  i.query = i.headers = i.body = i.cookie = i.set = i.route = true;
274
+ i.afterResponse = true;
274
275
  }
275
276
  const DEFAULT_CACHE_LIMIT = 1024;
276
277
  const globalSourceCache = /* @__PURE__ */ new Map();
@@ -304,7 +305,8 @@ const mergeInference = (a, b) => ({
304
305
  headers: a.headers || b.headers,
305
306
  query: a.query || b.query,
306
307
  set: a.set || b.set,
307
- route: a.route || b.route
308
+ route: a.route || b.route,
309
+ ...a.afterResponse || b.afterResponse ? { afterResponse: true } : {}
308
310
  });
309
311
  const defaultSucrose = () => ({
310
312
  query: false,
@@ -562,6 +564,7 @@ const channel = (value) => {
562
564
  case "cookie":
563
565
  case "set":
564
566
  case "route": return value;
567
+ case "defer": return "afterResponse";
565
568
  }
566
569
  };
567
570
  function computedDestructuringChannel(tokens, index) {
@@ -730,7 +733,7 @@ function inferFunction(source) {
730
733
  const key = property?.k === "s" && channel(property.value);
731
734
  if (key && tokens[next + 2]?.value === "]") inference[key] = true;
732
735
  else markAllAccessed(inference);
733
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route) break;
736
+ if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route && inference.afterResponse) break;
734
737
  continue;
735
738
  }
736
739
  if (tokens[i - 1]?.value === "=" && (tokens[i - 2]?.k === "i" || tokens[i - 2]?.value === "}")) continue;
@@ -789,7 +792,7 @@ function sucrose(handler, lifeCycle) {
789
792
  inference = mergeInference(inference, inferred);
790
793
  merged = true;
791
794
  } else inference = inferred;
792
- if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route) break;
795
+ if (inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.route && inference.afterResponse) break;
793
796
  }
794
797
  } finally {
795
798
  events.length = 0;
@@ -17,7 +17,7 @@ declare const ELYSIA_TYPES: {
17
17
  readonly NoValidate: 15;
18
18
  };
19
19
  type ELYSIA_TYPES = typeof ELYSIA_TYPES;
20
- declare const primitiveElysiaTypes: Set<6 | 1 | 2 | 3 | 10 | 11 | 13 | 14>;
20
+ declare const primitiveElysiaTypes: Set<1 | 2 | 6 | 3 | 10 | 11 | 13 | 14>;
21
21
  declare const noEnumerable: {
22
22
  readonly enumerable: false;
23
23
  };
package/dist/types.d.ts CHANGED
@@ -187,7 +187,7 @@ type IsAny<T> = 0 extends 1 & T ? true : false;
187
187
  type IsTuple<T> = T extends readonly any[] ? number extends T['length'] ? false : true : false;
188
188
  type Replace<Original, Target, With> = IsAny<Target> extends true ? Original : Original extends Record<string, unknown> ? { [K in keyof Original]: Original[K] extends Target ? With : Original[K] } : Original extends Target ? With : Original;
189
189
  type EventScope = 'global' | 'local' | 'plugin';
190
- type GuardSchemaType = 'override' | 'standalone';
190
+ type GuardSchemaType = 'override' | 'merge';
191
191
  type ElysiaFormData<T extends Record<keyof any, unknown>> = FormData & {
192
192
  ['~ely-form']: Replace<T, Blob | ElysiaFile, File> extends infer A ? { [key in keyof A]: IsTuple<A[key]> extends true ? A[key][number] extends Blob | ElysiaFile ? File[] : A[key] : A[key] } : T;
193
193
  };
@@ -287,7 +287,7 @@ type LocalHook<Input extends BaseMacro, Schema extends RouteSchemaWithResolvedMa
287
287
  tags?: DocumentDecoration['tags'];
288
288
  } & (Input extends any ? Input : Prettify<Input>);
289
289
  type AnyLocalHook = LocalHook<any, any, any, any, any>;
290
- type GuardLocalHook<Input extends BaseMacro | undefined, Schema extends RouteSchema, Singleton extends SingletonBase, Parser extends keyof any, BeforeHandle extends MaybeArray<OptionalHandler<any, any>>, AfterHandle extends MaybeArray<AfterHandler<any, any>>, ErrorHandle extends MaybeArray<ErrorHandler<any, any, any>>, GuardType extends GuardSchemaType = 'standalone'> = (Input extends any ? Input : Prettify<Input>) & {
290
+ type GuardLocalHook<Input extends BaseMacro | undefined, Schema extends RouteSchema, Singleton extends SingletonBase, Parser extends keyof any, BeforeHandle extends MaybeArray<OptionalHandler<any, any>>, AfterHandle extends MaybeArray<AfterHandler<any, any>>, ErrorHandle extends MaybeArray<ErrorHandler<any, any, any>>, GuardType extends GuardSchemaType = 'merge'> = (Input extends any ? Input : Prettify<Input>) & {
291
291
  /**
292
292
  * @default 'override'
293
293
  * @since 1.3.0
package/dist/utils.d.ts CHANGED
@@ -156,7 +156,7 @@ declare const eventProperties: Set<string>;
156
156
  declare function hookToGuard(a: Partial<AppHook & Macro> & {
157
157
  schema?: GuardSchemaType;
158
158
  }): Partial<AppHook & Macro>;
159
- declare function coalesceStandaloneSchemas(existing: any[], incoming: any[]): void;
159
+ declare function coalesceSchemas(existing: any[], incoming: any[]): void;
160
160
  declare function mergeHook(a: Partial<AppHook>, b: Partial<AppHook> | undefined, reverse?: boolean, dedup?: boolean): Partial<AppHook>;
161
161
  declare const createErrorEventHandler: (fn: EventFn<"error">, error: Error) => (context: Context) => unknown;
162
162
  declare function mergeDeep<A extends Record<string, any>, B extends Record<string, any>>(target: A, source: B, skipKeys?: string[], override?: boolean, mergeArray?: boolean, seen?: WeakSet<object>, cloneAdopt?: {
@@ -177,4 +177,4 @@ declare namespace prefix {
177
177
  }
178
178
  declare function serializeMacroSeed(_key: string, value: unknown): unknown;
179
179
  //#endregion
180
- export { ChainNode, CompactBeforeHandleChunk, CompactBeforeHandlePrefix, DeriveEntry, bytes, clearFlattenChainMemo, cloneHook, clonePlainDecorators, clonePlainDeep, coalesceStandaloneSchemas, compactBeforeHandleConflicts, compactBeforeHandlePrefix, constantTimeEqual, createErrorEventHandler, deriveEntryFn, eventProperties, evictOldestHalf, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, fnv1a, form, formToFormData, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isBlob, isByteStream, isCompactBeforeHandleOnly, isEmpty, isLocalScope, isMapDeriveEntry, isNotEmpty, isRecordNumber, joinPath, macroEpoch, macroOrigin, mapDeriveEntry, mergeArray, mergeDeep, mergeHook, mergeResponse, nullObject, prefix, pushField, redirect, replaceUrlPath, requestId, schemaProperties, serializeMacroSeed, sse };
180
+ export { ChainNode, CompactBeforeHandleChunk, CompactBeforeHandlePrefix, DeriveEntry, bytes, clearFlattenChainMemo, cloneHook, clonePlainDecorators, clonePlainDeep, coalesceSchemas, compactBeforeHandleConflicts, compactBeforeHandlePrefix, constantTimeEqual, createErrorEventHandler, deriveEntryFn, eventProperties, evictOldestHalf, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, fnv1a, form, formToFormData, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isBlob, isByteStream, isCompactBeforeHandleOnly, isEmpty, isLocalScope, isMapDeriveEntry, isNotEmpty, isRecordNumber, joinPath, macroEpoch, macroOrigin, mapDeriveEntry, mergeArray, mergeDeep, mergeHook, mergeResponse, nullObject, prefix, pushField, redirect, replaceUrlPath, requestId, schemaProperties, serializeMacroSeed, sse };
package/dist/utils.js CHANGED
@@ -455,7 +455,7 @@ const eventProperties = new Set([
455
455
  "error"
456
456
  ]);
457
457
  function hookToGuard(a) {
458
- if (a.schema !== "standalone") return a;
458
+ if (a.schema !== "merge") return a;
459
459
  if (a.body || a.headers || a.params || a.query || a.cookie || a.response) {
460
460
  a.schemas ??= [];
461
461
  const schema = Object.create(null);
@@ -487,7 +487,7 @@ function hookToGuard(a) {
487
487
  }
488
488
  return a;
489
489
  }
490
- function coalesceStandaloneSchemas(existing, incoming) {
490
+ function coalesceSchemas(existing, incoming) {
491
491
  for (const entry of incoming) {
492
492
  if (!entry || typeof entry !== "object") continue;
493
493
  let merged = false;
@@ -690,7 +690,7 @@ exports.clearFlattenChainMemo = clearFlattenChainMemo;
690
690
  exports.cloneHook = cloneHook;
691
691
  exports.clonePlainDecorators = clonePlainDecorators;
692
692
  exports.clonePlainDeep = clonePlainDeep;
693
- exports.coalesceStandaloneSchemas = coalesceStandaloneSchemas;
693
+ exports.coalesceSchemas = coalesceSchemas;
694
694
  exports.compactBeforeHandleConflicts = compactBeforeHandleConflicts;
695
695
  exports.compactBeforeHandlePrefix = compactBeforeHandlePrefix;
696
696
  exports.constantTimeEqual = constantTimeEqual;
package/dist/utils.mjs CHANGED
@@ -454,7 +454,7 @@ const eventProperties = new Set([
454
454
  "error"
455
455
  ]);
456
456
  function hookToGuard(a) {
457
- if (a.schema !== "standalone") return a;
457
+ if (a.schema !== "merge") return a;
458
458
  if (a.body || a.headers || a.params || a.query || a.cookie || a.response) {
459
459
  a.schemas ??= [];
460
460
  const schema = Object.create(null);
@@ -486,7 +486,7 @@ function hookToGuard(a) {
486
486
  }
487
487
  return a;
488
488
  }
489
- function coalesceStandaloneSchemas(existing, incoming) {
489
+ function coalesceSchemas(existing, incoming) {
490
490
  for (const entry of incoming) {
491
491
  if (!entry || typeof entry !== "object") continue;
492
492
  let merged = false;
@@ -684,4 +684,4 @@ function serializeMacroSeed(_key, value) {
684
684
  }
685
685
 
686
686
  //#endregion
687
- export { bytes, clearFlattenChainMemo, cloneHook, clonePlainDecorators, clonePlainDeep, coalesceStandaloneSchemas, compactBeforeHandleConflicts, compactBeforeHandlePrefix, constantTimeEqual, createErrorEventHandler, deriveEntryFn, eventProperties, evictOldestHalf, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, fnv1a, form, formToFormData, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isBlob, isByteStream, isCompactBeforeHandleOnly, isEmpty, isLocalScope, isMapDeriveEntry, isNotEmpty, isRecordNumber, joinPath, macroEpoch, macroOrigin, mapDeriveEntry, mergeArray, mergeDeep, mergeHook, mergeResponse, nullObject, prefix, pushField, redirect, replaceUrlPath, requestId, schemaProperties, serializeMacroSeed, sse };
687
+ export { bytes, clearFlattenChainMemo, cloneHook, clonePlainDecorators, clonePlainDeep, coalesceSchemas, compactBeforeHandleConflicts, compactBeforeHandlePrefix, constantTimeEqual, createErrorEventHandler, deriveEntryFn, eventProperties, evictOldestHalf, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, fnv1a, form, formToFormData, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isBlob, isByteStream, isCompactBeforeHandleOnly, isEmpty, isLocalScope, isMapDeriveEntry, isNotEmpty, isRecordNumber, joinPath, macroEpoch, macroOrigin, mapDeriveEntry, mergeArray, mergeDeep, mergeHook, mergeResponse, nullObject, prefix, pushField, redirect, replaceUrlPath, requestId, schemaProperties, serializeMacroSeed, sse };
@@ -5,7 +5,7 @@ const require_validator_index = require('./index.js');
5
5
 
6
6
  //#region src/validator/route.ts
7
7
  const isTb = (schema) => "~kind" in schema;
8
- function pickStandalone(schemas, key) {
8
+ function pickMerge(schemas, key) {
9
9
  if (!schemas) return;
10
10
  const result = [];
11
11
  for (let i = 0; i < schemas.length; i++) {
@@ -26,23 +26,23 @@ const SLOTS = [
26
26
  var RouteValidator = class {
27
27
  constructor(route, options) {
28
28
  if (!route) return;
29
- const standaloneSchemas = options?.schemas;
29
+ const mergeSchemas = options?.schemas;
30
30
  for (const [slot, coerce] of SLOTS) {
31
- const standalone = pickStandalone(standaloneSchemas, slot);
32
- if (!route[slot] && !standalone?.length) continue;
33
- const reference = require_validator_index.Validator.reference(route[slot] ?? standalone[0], options?.models);
34
- const coerces = isTb(reference) ? coerce(reference) : standalone?.find(isTb) ? coerce(standalone.find(isTb)) : void 0;
31
+ const merge = pickMerge(mergeSchemas, slot);
32
+ if (!route[slot] && !merge?.length) continue;
33
+ const reference = require_validator_index.Validator.reference(route[slot] ?? merge[0], options?.models);
34
+ const coerces = isTb(reference) ? coerce(reference) : merge?.find(isTb) ? coerce(merge.find(isTb)) : void 0;
35
35
  this[slot] = require_validator_index.Validator.create(route[slot], {
36
36
  ...options,
37
37
  slot,
38
- schemas: standalone,
38
+ schemas: merge,
39
39
  coerces
40
40
  });
41
41
  }
42
- const responseStandalone = pickStandalone(standaloneSchemas, "response");
42
+ const responseMerge = pickMerge(mergeSchemas, "response");
43
43
  this.response = require_validator_index.Validator.response(route.response, {
44
44
  ...options,
45
- schemas: responseStandalone
45
+ schemas: responseMerge
46
46
  });
47
47
  }
48
48
  };
@@ -4,7 +4,7 @@ import { Validator } from "./index.mjs";
4
4
 
5
5
  //#region src/validator/route.ts
6
6
  const isTb = (schema) => "~kind" in schema;
7
- function pickStandalone(schemas, key) {
7
+ function pickMerge(schemas, key) {
8
8
  if (!schemas) return;
9
9
  const result = [];
10
10
  for (let i = 0; i < schemas.length; i++) {
@@ -25,23 +25,23 @@ const SLOTS = [
25
25
  var RouteValidator = class {
26
26
  constructor(route, options) {
27
27
  if (!route) return;
28
- const standaloneSchemas = options?.schemas;
28
+ const mergeSchemas = options?.schemas;
29
29
  for (const [slot, coerce] of SLOTS) {
30
- const standalone = pickStandalone(standaloneSchemas, slot);
31
- if (!route[slot] && !standalone?.length) continue;
32
- const reference = Validator.reference(route[slot] ?? standalone[0], options?.models);
33
- const coerces = isTb(reference) ? coerce(reference) : standalone?.find(isTb) ? coerce(standalone.find(isTb)) : void 0;
30
+ const merge = pickMerge(mergeSchemas, slot);
31
+ if (!route[slot] && !merge?.length) continue;
32
+ const reference = Validator.reference(route[slot] ?? merge[0], options?.models);
33
+ const coerces = isTb(reference) ? coerce(reference) : merge?.find(isTb) ? coerce(merge.find(isTb)) : void 0;
34
34
  this[slot] = Validator.create(route[slot], {
35
35
  ...options,
36
36
  slot,
37
- schemas: standalone,
37
+ schemas: merge,
38
38
  coerces
39
39
  });
40
40
  }
41
- const responseStandalone = pickStandalone(standaloneSchemas, "response");
41
+ const responseMerge = pickMerge(mergeSchemas, "response");
42
42
  this.response = Validator.response(route.response, {
43
43
  ...options,
44
- schemas: responseStandalone
44
+ schemas: responseMerge
45
45
  });
46
46
  }
47
47
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elysia",
3
3
  "description": "Ergonomic Framework for Human",
4
- "version": "2.0.0-exp.60",
4
+ "version": "2.0.0-exp.61",
5
5
  "author": {
6
6
  "name": "saltyAom",
7
7
  "url": "https://github.com/SaltyAom",