elysia 2.0.0-beta.13 → 2.0.0-beta.15

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 (90) hide show
  1. package/dist/adapter/bun/index.d.ts +4 -2
  2. package/dist/adapter/bun/index.js +35 -38
  3. package/dist/adapter/bun/index.mjs +35 -39
  4. package/dist/adapter/utils.js +16 -21
  5. package/dist/adapter/utils.mjs +16 -21
  6. package/dist/base.d.ts +28 -0
  7. package/dist/base.js +109 -59
  8. package/dist/base.mjs +110 -60
  9. package/dist/compile/aot.js +14 -21
  10. package/dist/compile/aot.mjs +14 -21
  11. package/dist/compile/handler/frozen-validator.js +51 -42
  12. package/dist/compile/handler/frozen-validator.mjs +51 -42
  13. package/dist/compile/handler/index.js +57 -50
  14. package/dist/compile/handler/index.mjs +57 -50
  15. package/dist/compile/handler/jit.js +36 -26
  16. package/dist/compile/handler/jit.mjs +37 -27
  17. package/dist/compile/handler/params.js +2 -0
  18. package/dist/compile/handler/params.mjs +3 -1
  19. package/dist/compile/handler/utils.d.ts +2 -2
  20. package/dist/compile/handler/utils.js +115 -111
  21. package/dist/compile/handler/utils.mjs +115 -113
  22. package/dist/context.d.ts +3 -1
  23. package/dist/context.js +2 -0
  24. package/dist/context.mjs +3 -1
  25. package/dist/cookie/config.js +6 -7
  26. package/dist/cookie/config.mjs +6 -7
  27. package/dist/error.d.ts +6 -3
  28. package/dist/error.js +26 -28
  29. package/dist/error.mjs +26 -28
  30. package/dist/handler/fetch.js +2 -1
  31. package/dist/handler/fetch.mjs +3 -2
  32. package/dist/handler/utils.d.ts +3 -1
  33. package/dist/handler/utils.js +19 -1
  34. package/dist/handler/utils.mjs +17 -1
  35. package/dist/index.d.ts +3 -3
  36. package/dist/package.js +1 -1
  37. package/dist/package.mjs +1 -1
  38. package/dist/plugin/aot/core.js +4 -0
  39. package/dist/plugin/aot/core.mjs +4 -0
  40. package/dist/sucrose.js +60 -59
  41. package/dist/sucrose.mjs +60 -59
  42. package/dist/trace.js +6 -9
  43. package/dist/trace.mjs +6 -9
  44. package/dist/type/coerce-plan.js +41 -36
  45. package/dist/type/coerce-plan.mjs +41 -36
  46. package/dist/type/coerce.d.ts +1 -1
  47. package/dist/type/constants.d.ts +1 -1
  48. package/dist/type/elysia/cookie.js +8 -17
  49. package/dist/type/elysia/cookie.mjs +8 -17
  50. package/dist/type/elysia/date.js +6 -7
  51. package/dist/type/elysia/date.mjs +6 -7
  52. package/dist/type/elysia/numeric.js +8 -9
  53. package/dist/type/elysia/numeric.mjs +8 -9
  54. package/dist/type/elysia/problem.d.ts +20 -0
  55. package/dist/type/elysia/problem.js +25 -0
  56. package/dist/type/elysia/problem.mjs +24 -0
  57. package/dist/type/exports.d.ts +3 -2
  58. package/dist/type/exports.js +2 -0
  59. package/dist/type/exports.mjs +2 -1
  60. package/dist/type/index.js +2 -0
  61. package/dist/type/index.mjs +2 -0
  62. package/dist/type/validator/clean-safe.d.ts +1 -2
  63. package/dist/type/validator/clean-safe.js +0 -2
  64. package/dist/type/validator/clean-safe.mjs +1 -2
  65. package/dist/type/validator/custom-error.js +37 -26
  66. package/dist/type/validator/custom-error.mjs +37 -26
  67. package/dist/type/validator/default-precompute.js +24 -26
  68. package/dist/type/validator/default-precompute.mjs +24 -26
  69. package/dist/type/validator/exact-mirror.js +6 -8
  70. package/dist/type/validator/exact-mirror.mjs +6 -8
  71. package/dist/type/validator/index.js +64 -66
  72. package/dist/type/validator/index.mjs +65 -67
  73. package/dist/type/validator/validator-cache.d.ts +2 -2
  74. package/dist/type/validator/validator-cache.js +7 -10
  75. package/dist/type/validator/validator-cache.mjs +6 -9
  76. package/dist/types.d.ts +4 -3
  77. package/dist/universal/file.js +2 -6
  78. package/dist/universal/file.mjs +2 -6
  79. package/dist/utils.d.ts +11 -2
  80. package/dist/utils.js +85 -47
  81. package/dist/utils.mjs +82 -48
  82. package/dist/validator/index.js +14 -18
  83. package/dist/validator/index.mjs +14 -18
  84. package/dist/ws/context.js +9 -11
  85. package/dist/ws/context.mjs +9 -11
  86. package/dist/ws/parser.js +23 -20
  87. package/dist/ws/parser.mjs +23 -20
  88. package/dist/ws/route.js +76 -87
  89. package/dist/ws/route.mjs +76 -87
  90. package/package.json +5 -2
package/dist/context.d.ts CHANGED
@@ -4,7 +4,7 @@ import { StatusMap } from "./constants.js";
4
4
  import { Server } from "./universal/server.js";
5
5
  import { redirect } from "./utils.js";
6
6
  import { AfterResponseHandler, DefaultSingleton, HTTPHeaders, InputSchema, MaybePromise, Prettify, ResolvePath, RouteSchema, SingletonBase } from "./types.js";
7
- import { SelectiveStatus, status } from "./error.js";
7
+ import { SelectiveProblem, SelectiveStatus, problem, status } from "./error.js";
8
8
  import { AnyElysia } from "./base.js";
9
9
 
10
10
  //#region src/context.d.ts
@@ -25,6 +25,7 @@ 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
+ problem: {} extends Route['response'] ? typeof problem : SelectiveProblem<Route['response']>;
28
29
  /**
29
30
  * Append a callback to run after the response is sent
30
31
  */
@@ -87,6 +88,7 @@ type PreContext<in out Singleton extends SingletonBase = {
87
88
  status?: number;
88
89
  };
89
90
  status: typeof status;
91
+ problem: typeof problem;
90
92
  } & Singleton['decorator']>;
91
93
  //#endregion
92
94
  export { Context, ErrorContext, LifecycleContext, PreContext, clearContextCache, createBaseContext, createContext };
package/dist/context.js CHANGED
@@ -20,6 +20,7 @@ function buildEmptyDecorator() {
20
20
  class Decorator {}
21
21
  Object.assign(Decorator.prototype, {
22
22
  status: require_error.status,
23
+ problem: require_error.problem,
23
24
  redirect: require_utils.redirect
24
25
  });
25
26
  Object.defineProperty(Decorator.prototype, "defer", defer);
@@ -35,6 +36,7 @@ function createBaseContext(app) {
35
36
  ...decorator,
36
37
  store,
37
38
  status: require_error.status,
39
+ problem: require_error.problem,
38
40
  redirect: require_utils.redirect
39
41
  });
40
42
  Object.defineProperty(Decorator.prototype, "defer", defer);
package/dist/context.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isNotEmpty, nullObject, redirect } from "./utils.mjs";
2
- import { status } from "./error.mjs";
2
+ import { problem, status } from "./error.mjs";
3
3
  import { defaultHeaders } from "./adapter/default-headers.mjs";
4
4
 
5
5
  //#region src/context.ts
@@ -19,6 +19,7 @@ function buildEmptyDecorator() {
19
19
  class Decorator {}
20
20
  Object.assign(Decorator.prototype, {
21
21
  status,
22
+ problem,
22
23
  redirect
23
24
  });
24
25
  Object.defineProperty(Decorator.prototype, "defer", defer);
@@ -34,6 +35,7 @@ function createBaseContext(app) {
34
35
  ...decorator,
35
36
  store,
36
37
  status,
38
+ problem,
37
39
  redirect
38
40
  });
39
41
  Object.defineProperty(Decorator.prototype, "defer", defer);
@@ -25,12 +25,6 @@ function getAttributes(source) {
25
25
  }
26
26
  return out;
27
27
  }
28
- function normalizeSign(sign) {
29
- if (sign === void 0) return;
30
- if (sign === true) return true;
31
- if (Array.isArray(sign)) return sign.length ? sign : void 0;
32
- return [sign];
33
- }
34
28
  const hasUsableSecret = (secrets) => Array.isArray(secrets) ? secrets.some((s) => !!s?.trim()) : !!secrets?.trim();
35
29
  function compileCookieConfig(routeSchema, appConfig) {
36
30
  const routeConfig = routeSchema?.config ?? void 0;
@@ -41,7 +35,12 @@ function compileCookieConfig(routeSchema, appConfig) {
41
35
  ...routeAttributes
42
36
  } : appAttributes ?? routeAttributes ?? require_utils.nullObject();
43
37
  if (!defaults.path) defaults.path = "/";
44
- const globalSign = normalizeSign(routeConfig?.sign ?? appConfig?.sign);
38
+ const rawSign = routeConfig?.sign ?? appConfig?.sign;
39
+ let globalSign;
40
+ if (rawSign === void 0) globalSign = void 0;
41
+ else if (rawSign === true) globalSign = true;
42
+ else if (Array.isArray(rawSign)) globalSign = rawSign.length ? rawSign : void 0;
43
+ else globalSign = [rawSign];
45
44
  const globalSecrets = routeConfig?.secrets !== void 0 ? routeConfig.secrets : appConfig?.secrets;
46
45
  const fields = require_utils.nullObject();
47
46
  const properties = routeSchema?.properties;
@@ -24,12 +24,6 @@ function getAttributes(source) {
24
24
  }
25
25
  return out;
26
26
  }
27
- function normalizeSign(sign) {
28
- if (sign === void 0) return;
29
- if (sign === true) return true;
30
- if (Array.isArray(sign)) return sign.length ? sign : void 0;
31
- return [sign];
32
- }
33
27
  const hasUsableSecret = (secrets) => Array.isArray(secrets) ? secrets.some((s) => !!s?.trim()) : !!secrets?.trim();
34
28
  function compileCookieConfig(routeSchema, appConfig) {
35
29
  const routeConfig = routeSchema?.config ?? void 0;
@@ -40,7 +34,12 @@ function compileCookieConfig(routeSchema, appConfig) {
40
34
  ...routeAttributes
41
35
  } : appAttributes ?? routeAttributes ?? nullObject();
42
36
  if (!defaults.path) defaults.path = "/";
43
- const globalSign = normalizeSign(routeConfig?.sign ?? appConfig?.sign);
37
+ const rawSign = routeConfig?.sign ?? appConfig?.sign;
38
+ let globalSign;
39
+ if (rawSign === void 0) globalSign = void 0;
40
+ else if (rawSign === true) globalSign = true;
41
+ else if (Array.isArray(rawSign)) globalSign = rawSign.length ? rawSign : void 0;
42
+ else globalSign = [rawSign];
44
43
  const globalSecrets = routeConfig?.secrets !== void 0 ? routeConfig.secrets : appConfig?.secrets;
45
44
  const fields = nullObject();
46
45
  const properties = routeSchema?.properties;
package/dist/error.d.ts CHANGED
@@ -107,7 +107,7 @@ declare class ValidationError extends ElysiaError {
107
107
  detail: any;
108
108
  on: string | undefined;
109
109
  property: string;
110
- found: any;
110
+ found: unknown;
111
111
  expected: unknown;
112
112
  errors: any[];
113
113
  type: string | undefined;
@@ -118,7 +118,7 @@ declare class ValidationError extends ElysiaError {
118
118
  detail: any;
119
119
  on: string | undefined;
120
120
  property: string;
121
- found: any;
121
+ found: unknown;
122
122
  expected: unknown;
123
123
  errors: any[];
124
124
  type: string;
@@ -221,6 +221,9 @@ declare function problem<const Code extends number | keyof StatusMap, const P ex
221
221
  declare function problem<const P extends Problem>(detail: P): ElysiaStatus<ProblemStatus<P>, ProblemResponseBody<ProblemStatus<P>, P>>;
222
222
  type CheckExcessProps<T, U> = 0 extends 1 & T ? T : U extends U ? Exclude<keyof T, keyof U> extends never ? T : { [K in keyof U]: U[K] } & { [K in Exclude<keyof T, keyof U>]: never } : never;
223
223
  type SelectiveStatus<in out Res> = <const Code extends keyof Res | StatusMapBack[Extract<keyof StatusMapBack, keyof Res>], T extends (Code extends keyof Res ? Res[Code] : Code extends keyof StatusMap ? Res[StatusMap[Code]] : never)>(code: Code, response: CheckExcessProps<T, Code extends keyof Res ? Res[Code] : Code extends keyof StatusMap ? Res[StatusMap[Code]] : never>) => ElysiaStatus<Code, T>;
224
+ type ProblemInput<T> = T extends object ? Omit<T, 'type' | 'title' | 'status'> & { [K in keyof T as K extends 'type' | 'title' ? K : never]?: T[K] } : never;
225
+ type ResponseOf<Res, Code> = Code extends keyof Res ? Res[Code] : Code extends keyof StatusMap ? Res[StatusMap[Code]] : never;
226
+ type SelectiveProblem<in out Res> = <const Code extends keyof Res | StatusMapBack[Extract<keyof StatusMapBack, keyof Res>], T extends ProblemInput<ResponseOf<Res, Code>> = ProblemInput<ResponseOf<Res, Code>>>(code: Code, ...detail: {} extends ProblemInput<ResponseOf<Res, Code>> ? [detail?: CheckExcessProps<T, ProblemInput<ResponseOf<Res, Code>>>] : [detail: CheckExcessProps<T, ProblemInput<ResponseOf<Res, Code>>>]) => ElysiaStatus<NumericStatus<Code>, ResponseOf<Res, Code>>;
224
227
  /**
225
228
  * Class returned by {@link HTTPError.id}
226
229
  */
@@ -379,4 +382,4 @@ declare abstract class HTTPError<const in out T extends string = string> extends
379
382
  }>;
380
383
  }
381
384
  //#endregion
382
- export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, NumericStatus, PROBLEM_JSON, ParseError, Problem, ProblemResponseBody, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, validationDetail };
385
+ export { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, MAX_ERRORS, NotFound, NumericStatus, PROBLEM_JSON, ParseError, Problem, ProblemResponseBody, SelectiveProblem, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, elysiaErrorProblem, internalServerErrorBody, internalServerErrorBodyString, internalServerErrorResponse, isProduction, problem, problemBody, problemResponse, problemTypeOf, status, subValueAt, validationDetail };
package/dist/error.js CHANGED
@@ -213,12 +213,6 @@ function subValueAt(value, path) {
213
213
  }
214
214
  return current;
215
215
  }
216
- function scopeFound(value, first) {
217
- if (jsonLengthWithin(value, FOUND_ECHO_LIMIT) >= 0) return value;
218
- const sub = subValueAt(value, first?.instancePath ?? first?.path);
219
- if (sub !== void 0 && jsonLengthWithin(sub, FOUND_ECHO_LIMIT) >= 0) return sub;
220
- return FOUND_ECHO_OMITTED;
221
- }
222
216
  const issueLocator = new Set([
223
217
  "keyword",
224
218
  "schemaPath",
@@ -355,7 +349,22 @@ var ValidationError = class extends ElysiaError {
355
349
  }
356
350
  get all() {
357
351
  if (!this.errors) return [];
358
- return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => this.#normalizeIssue(e));
352
+ return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => {
353
+ if (!e) return e;
354
+ const issue = {
355
+ path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
356
+ message: e.message ?? "",
357
+ schemaPath: e.schemaPath,
358
+ params: e.params
359
+ };
360
+ Object.defineProperty(issue, "value", {
361
+ value: this.value,
362
+ writable: true,
363
+ enumerable: false,
364
+ configurable: true
365
+ });
366
+ return issue;
367
+ });
359
368
  }
360
369
  #collapseCoercionErrors(errors) {
361
370
  if (!this.schema || !errors.length) return errors;
@@ -395,28 +404,9 @@ var ValidationError = class extends ElysiaError {
395
404
  }
396
405
  return out ?? errors;
397
406
  }
398
- #normalizeIssue(e) {
399
- if (!e) return e;
400
- const issue = {
401
- path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
402
- message: e.message ?? "",
403
- schemaPath: e.schemaPath,
404
- params: e.params
405
- };
406
- Object.defineProperty(issue, "value", {
407
- value: this.value,
408
- writable: true,
409
- enumerable: false,
410
- configurable: true
411
- });
412
- return issue;
413
- }
414
407
  get #productionDetail() {
415
408
  return require_universal_is_production.isProduction() && !this.allowUnsafeValidationDetails;
416
409
  }
417
- get #maskResponseValue() {
418
- return this.type === "response" && this.#productionDetail;
419
- }
420
410
  detail(message) {
421
411
  if (this.#productionDetail) {
422
412
  if (this.type === "response") return {
@@ -468,6 +458,14 @@ var ValidationError = class extends ElysiaError {
468
458
  }
469
459
  else expected = created;
470
460
  } catch {}
461
+ const value = this.value;
462
+ let found;
463
+ if (jsonLengthWithin(value, FOUND_ECHO_LIMIT) >= 0) found = value;
464
+ else {
465
+ const sub = subValueAt(value, first?.instancePath ?? first?.path);
466
+ if (sub !== void 0 && jsonLengthWithin(sub, FOUND_ECHO_LIMIT) >= 0) found = sub;
467
+ else found = FOUND_ECHO_OMITTED;
468
+ }
471
469
  return {
472
470
  ...server ? internalServerErrorProblem() : {
473
471
  type: "validation",
@@ -477,13 +475,13 @@ var ValidationError = class extends ElysiaError {
477
475
  detail,
478
476
  on: this.type,
479
477
  property,
480
- found: scopeFound(this.value, first),
478
+ found,
481
479
  expected,
482
480
  errors
483
481
  };
484
482
  }
485
483
  toResponse(headers) {
486
- if (this.#maskResponseValue) return problemResponse(this.payload, headers);
484
+ if (this.type === "response" && this.#productionDetail) return problemResponse(this.payload, headers);
487
485
  if (this.customError !== void 0) {
488
486
  const isString = typeof this.customError === "string";
489
487
  const response = new Response(isString ? this.customError : JSON.stringify(this.customError), {
package/dist/error.mjs CHANGED
@@ -212,12 +212,6 @@ function subValueAt(value, path) {
212
212
  }
213
213
  return current;
214
214
  }
215
- function scopeFound(value, first) {
216
- if (jsonLengthWithin(value, FOUND_ECHO_LIMIT) >= 0) return value;
217
- const sub = subValueAt(value, first?.instancePath ?? first?.path);
218
- if (sub !== void 0 && jsonLengthWithin(sub, FOUND_ECHO_LIMIT) >= 0) return sub;
219
- return FOUND_ECHO_OMITTED;
220
- }
221
215
  const issueLocator = new Set([
222
216
  "keyword",
223
217
  "schemaPath",
@@ -354,7 +348,22 @@ var ValidationError = class extends ElysiaError {
354
348
  }
355
349
  get all() {
356
350
  if (!this.errors) return [];
357
- return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => this.#normalizeIssue(e));
351
+ return this.#collapseCoercionErrors(this.errors.filter(Boolean)).map((e) => {
352
+ if (!e) return e;
353
+ const issue = {
354
+ path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
355
+ message: e.message ?? "",
356
+ schemaPath: e.schemaPath,
357
+ params: e.params
358
+ };
359
+ Object.defineProperty(issue, "value", {
360
+ value: this.value,
361
+ writable: true,
362
+ enumerable: false,
363
+ configurable: true
364
+ });
365
+ return issue;
366
+ });
358
367
  }
359
368
  #collapseCoercionErrors(errors) {
360
369
  if (!this.schema || !errors.length) return errors;
@@ -394,28 +403,9 @@ var ValidationError = class extends ElysiaError {
394
403
  }
395
404
  return out ?? errors;
396
405
  }
397
- #normalizeIssue(e) {
398
- if (!e) return e;
399
- const issue = {
400
- path: Array.isArray(e.path) ? e.path.length ? e.path.map(segmentString).join(".") : "root" : typeof e.path === "string" ? e.path.replace(/^\//, "").replace(/\//g, ".") || "root" : "root",
401
- message: e.message ?? "",
402
- schemaPath: e.schemaPath,
403
- params: e.params
404
- };
405
- Object.defineProperty(issue, "value", {
406
- value: this.value,
407
- writable: true,
408
- enumerable: false,
409
- configurable: true
410
- });
411
- return issue;
412
- }
413
406
  get #productionDetail() {
414
407
  return isProduction() && !this.allowUnsafeValidationDetails;
415
408
  }
416
- get #maskResponseValue() {
417
- return this.type === "response" && this.#productionDetail;
418
- }
419
409
  detail(message) {
420
410
  if (this.#productionDetail) {
421
411
  if (this.type === "response") return {
@@ -467,6 +457,14 @@ var ValidationError = class extends ElysiaError {
467
457
  }
468
458
  else expected = created;
469
459
  } catch {}
460
+ const value = this.value;
461
+ let found;
462
+ if (jsonLengthWithin(value, FOUND_ECHO_LIMIT) >= 0) found = value;
463
+ else {
464
+ const sub = subValueAt(value, first?.instancePath ?? first?.path);
465
+ if (sub !== void 0 && jsonLengthWithin(sub, FOUND_ECHO_LIMIT) >= 0) found = sub;
466
+ else found = FOUND_ECHO_OMITTED;
467
+ }
470
468
  return {
471
469
  ...server ? internalServerErrorProblem() : {
472
470
  type: "validation",
@@ -476,13 +474,13 @@ var ValidationError = class extends ElysiaError {
476
474
  detail,
477
475
  on: this.type,
478
476
  property,
479
- found: scopeFound(this.value, first),
477
+ found,
480
478
  expected,
481
479
  errors
482
480
  };
483
481
  }
484
482
  toResponse(headers) {
485
- if (this.#maskResponseValue) return problemResponse(this.payload, headers);
483
+ if (this.type === "response" && this.#productionDetail) return problemResponse(this.payload, headers);
486
484
  if (this.customError !== void 0) {
487
485
  const isString = typeof this.customError === "string";
488
486
  const response = new Response(isString ? this.customError : JSON.stringify(this.customError), {
@@ -171,7 +171,7 @@ function createFetchHandler(app) {
171
171
  const afterResponse = (context, status) => {
172
172
  if (context._arf) return;
173
173
  const queue = context["~afterResponse"];
174
- if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length) return;
174
+ if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length && !context["~dispose"]) return;
175
175
  context._arf = true;
176
176
  if (status !== void 0) context.set.status = status;
177
177
  queueMicrotask(async () => {
@@ -190,6 +190,7 @@ function createFetchHandler(app) {
190
190
  console.error(e);
191
191
  }
192
192
  }
193
+ await require_handler_utils.drainDisposables(context);
193
194
  if (traceAfterResponsePhase) {
194
195
  let cache = context.trace;
195
196
  if (!cache && tracerFactories) {
@@ -2,7 +2,7 @@ import { authorityEnd, flattenChain, isNotEmpty, nullObject, requestId } from ".
2
2
  import { isProduction } from "../universal/is-production.mjs";
3
3
  import { NotFound, PROBLEM_JSON, internalServerErrorResponse } from "../error.mjs";
4
4
  import { handleSet, materializeSetHeaders } from "../adapter/utils.mjs";
5
- import { emptyResponse, getAsyncIndexes, getNotFound, getNotFoundBody } from "./utils.mjs";
5
+ import { drainDisposables, emptyResponse, getAsyncIndexes, getNotFound, getNotFoundBody } from "./utils.mjs";
6
6
  import { createErrorHandler } from "./error.mjs";
7
7
  import { origin } from "../adapter/origin.mjs";
8
8
  import { defaultAdapter } from "../adapter/constants.mjs";
@@ -168,7 +168,7 @@ function createFetchHandler(app) {
168
168
  const afterResponse = (context, status) => {
169
169
  if (context._arf) return;
170
170
  const queue = context["~afterResponse"];
171
- if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length) return;
171
+ if (!afterResponses?.length && !traceAfterResponsePhase && !queue?.length && !context["~dispose"]) return;
172
172
  context._arf = true;
173
173
  if (status !== void 0) context.set.status = status;
174
174
  queueMicrotask(async () => {
@@ -187,6 +187,7 @@ function createFetchHandler(app) {
187
187
  console.error(e);
188
188
  }
189
189
  }
190
+ await drainDisposables(context);
190
191
  if (traceAfterResponsePhase) {
191
192
  let cache = context.trace;
192
193
  if (!cache && tracerFactories) {
@@ -10,6 +10,8 @@ declare function getNotFoundBody(): string;
10
10
  declare function getNotFound(): Response;
11
11
  declare function forwardError<T>(value: T): T;
12
12
  declare function finalizeRouteError(app: AnyElysia, context: Partial<Context>, error: unknown): MaybePromise<Response>;
13
+ declare function registerDeriveDisposable(context: any, value: unknown, scan?: any): void;
14
+ declare function drainDisposables(context: any): Promise<void>;
13
15
  declare function getAsyncIndexes(onRequests: Function[]): (true | undefined)[] | undefined;
14
16
  //#endregion
15
- export { emptyResponse, finalizeRouteError, forwardError, getAsyncIndexes, getNotFound, getNotFoundBody };
17
+ export { drainDisposables, emptyResponse, finalizeRouteError, forwardError, getAsyncIndexes, getNotFound, getNotFoundBody, registerDeriveDisposable };
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_universal_constants = require('../universal/constants.js');
3
+ const require_utils = require('../utils.js');
3
4
  const require_universal_env = require('../universal/env.js');
4
5
  const require_error = require('../error.js');
5
6
  const require_compile_utils = require('../compile/utils.js');
@@ -44,6 +45,21 @@ function finalizeRouteError(app, context, error) {
44
45
  if (!finalize) throw error;
45
46
  return finalize(context, error);
46
47
  }
48
+ function registerDeriveDisposable(context, value, scan = context) {
49
+ if (!require_utils.isDisposable(value)) return;
50
+ if (require_utils.isSingleton(value)) return;
51
+ for (const key in scan) if (scan[key] === value) return;
52
+ (context["~dispose"] ??= new AsyncDisposableStack()).use(value);
53
+ }
54
+ async function drainDisposables(context) {
55
+ const stack = context["~dispose"];
56
+ if (!stack) return;
57
+ try {
58
+ await stack.disposeAsync();
59
+ } catch (error) {
60
+ console.error(error);
61
+ }
62
+ }
47
63
  function getAsyncIndexes(onRequests) {
48
64
  let asyncIndexes;
49
65
  for (let i = 0; i < onRequests.length; i++) if (require_compile_utils.isAsyncFunction(onRequests[i]) || require_compile_utils.mayReturnPromise(onRequests[i])) {
@@ -54,9 +70,11 @@ function getAsyncIndexes(onRequests) {
54
70
  }
55
71
 
56
72
  //#endregion
73
+ exports.drainDisposables = drainDisposables;
57
74
  exports.emptyResponse = emptyResponse;
58
75
  exports.finalizeRouteError = finalizeRouteError;
59
76
  exports.forwardError = forwardError;
60
77
  exports.getAsyncIndexes = getAsyncIndexes;
61
78
  exports.getNotFound = getNotFound;
62
- exports.getNotFoundBody = getNotFoundBody;
79
+ exports.getNotFoundBody = getNotFoundBody;
80
+ exports.registerDeriveDisposable = registerDeriveDisposable;
@@ -1,4 +1,5 @@
1
1
  import { isCloudflareWorker, isFastly } from "../universal/constants.mjs";
2
+ import { isDisposable, isSingleton } from "../utils.mjs";
2
3
  import { env } from "../universal/env.mjs";
3
4
  import { HTTPError, PROBLEM_JSON, problemTypeOf } from "../error.mjs";
4
5
  import { isAsyncFunction, mayReturnPromise } from "../compile/utils.mjs";
@@ -43,6 +44,21 @@ function finalizeRouteError(app, context, error) {
43
44
  if (!finalize) throw error;
44
45
  return finalize(context, error);
45
46
  }
47
+ function registerDeriveDisposable(context, value, scan = context) {
48
+ if (!isDisposable(value)) return;
49
+ if (isSingleton(value)) return;
50
+ for (const key in scan) if (scan[key] === value) return;
51
+ (context["~dispose"] ??= new AsyncDisposableStack()).use(value);
52
+ }
53
+ async function drainDisposables(context) {
54
+ const stack = context["~dispose"];
55
+ if (!stack) return;
56
+ try {
57
+ await stack.disposeAsync();
58
+ } catch (error) {
59
+ console.error(error);
60
+ }
61
+ }
46
62
  function getAsyncIndexes(onRequests) {
47
63
  let asyncIndexes;
48
64
  for (let i = 0; i < onRequests.length; i++) if (isAsyncFunction(onRequests[i]) || mayReturnPromise(onRequests[i])) {
@@ -53,4 +69,4 @@ function getAsyncIndexes(onRequests) {
53
69
  }
54
70
 
55
71
  //#endregion
56
- export { emptyResponse, finalizeRouteError, forwardError, getAsyncIndexes, getNotFound, getNotFoundBody };
72
+ export { drainDisposables, emptyResponse, finalizeRouteError, forwardError, getAsyncIndexes, getNotFound, getNotFoundBody, registerDeriveDisposable };
package/dist/index.d.ts CHANGED
@@ -5,8 +5,8 @@ import { StatusMap, StatusMapBack } from "./constants.js";
5
5
  import { env } from "./universal/env.js";
6
6
  import { Server } from "./universal/server.js";
7
7
  import { bytes, form, prefix, redirect, sse } from "./utils.js";
8
- import { DefaultEphemeral, DefaultMetadata, DefaultSingleton, HTTPHeaders, InputSchema, Macro, MacroToContext, MacroToProperty, MacroTypeLambda, RouteSchema, SSEPayload, UnwrapRoute, UnwrapSchema } from "./types.js";
9
- import { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, NotFound, NumericStatus, ParseError, Problem, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, problem, status, validationDetail } from "./error.js";
8
+ import { DefaultEphemeral, DefaultMetadata, DefaultSingleton, HTTPHeaders, InputSchema, Macro, MacroToContext, MacroToProperty, MacroTypeLambda, RouteSchema, SSEPayload, UnwrapModels, UnwrapRoute, UnwrapSchema } from "./types.js";
9
+ import { ElysiaError, ElysiaStatus, HTTPError, InternalServerError, NotFound, NumericStatus, ParseError, Problem, SelectiveProblem, SelectiveStatus, StatusResponse, TaggedHTTPError, ValidationError, ValidationErrorResponse, problem, status, validationDetail } from "./error.js";
10
10
  import { Context, ErrorContext, createBaseContext, createContext } from "./context.js";
11
11
  import { InvalidCookie } from "./cookie/error.js";
12
12
  import { AnySchema, BaseSchema, StandardJSONSchemaV1Like, StandardSchemaV1Like } from "./type/types.js";
@@ -20,4 +20,4 @@ import { TypeSystem, t } from "./type/index.js";
20
20
  import { AotFingerprint, Capture, Compiled, CompilerSession, ProgramId } from "./compile/aot.js";
21
21
  import { AnyElysia, Elysia } from "./base.js";
22
22
  import { borrow } from "./adapter/response-ownership.js";
23
- export { AnyElysia, type AnySchema, type AotFingerprint, type BaseCookie, type BaseSchema, Compiled, type CompilerSession, type Context, type Cookie, type CookieOptions, type DefaultEphemeral, type DefaultMetadata, type DefaultSingleton, Elysia, Elysia as default, ElysiaError, ElysiaFile, ElysiaStatus, type ErrorContext, type FileTypeDetector, HTTPError, type HTTPHeaders, type InputSchema, InternalServerError, InvalidCookie, type Macro, type MacroToContext, type MacroToProperty, type MacroTypeLambda, Capture as Manifest, MultiValidator, NotFound, type NumericStatus, ParseError, type Problem, type ProgramId, type RouteSchema, type SSEPayload, type SelectiveStatus, type Server, type StandardJSONSchemaV1Like, type StandardSchemaV1Like, StandardValidator, StatusMap, StatusMapBack, type StatusResponse, type TCookieField, type TCookieObject, type TFiles, type TaggedHTTPError, TypeBoxValidator, TypeSystem, type UnwrapRoute, type UnwrapSchema, ValidationError, type ValidationErrorResponse, Validator, borrow, bytes, createBaseContext, createContext, env, file, fileType, form, prefix, problem, redirect, setFileTypeDetector, setupTypebox, sse, status, t, validationDetail };
23
+ export { AnyElysia, type AnySchema, type AotFingerprint, type BaseCookie, type BaseSchema, Compiled, type CompilerSession, type Context, type Cookie, type CookieOptions, type DefaultEphemeral, type DefaultMetadata, type DefaultSingleton, Elysia, Elysia as default, ElysiaError, ElysiaFile, ElysiaStatus, type ErrorContext, type FileTypeDetector, HTTPError, type HTTPHeaders, type InputSchema, InternalServerError, InvalidCookie, type Macro, type MacroToContext, type MacroToProperty, type MacroTypeLambda, Capture as Manifest, MultiValidator, NotFound, type NumericStatus, ParseError, type Problem, type ProgramId, type RouteSchema, type SSEPayload, type SelectiveProblem, type SelectiveStatus, type Server, type StandardJSONSchemaV1Like, type StandardSchemaV1Like, StandardValidator, StatusMap, StatusMapBack, type StatusResponse, type TCookieField, type TCookieObject, type TFiles, type TaggedHTTPError, TypeBoxValidator, TypeSystem, type UnwrapModels, type UnwrapRoute, type UnwrapSchema, ValidationError, type ValidationErrorResponse, Validator, borrow, bytes, createBaseContext, createContext, env, file, fileType, form, prefix, problem, redirect, setFileTypeDetector, setupTypebox, sse, status, t, validationDetail };
package/dist/package.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region package.json
3
- var version = "2.0.0-beta.13";
3
+ var version = "2.0.0-beta.15";
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-beta.13";
2
+ var version = "2.0.0-beta.15";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -287,6 +287,10 @@ const OVERRIDE_MAP = {
287
287
  leaf: "optional",
288
288
  export: "Optional"
289
289
  },
290
+ Problem: {
291
+ leaf: "problem",
292
+ export: "Problem"
293
+ },
290
294
  String: {
291
295
  leaf: "string",
292
296
  export: "StringType"
@@ -285,6 +285,10 @@ const OVERRIDE_MAP = {
285
285
  leaf: "optional",
286
286
  export: "Optional"
287
287
  },
288
+ Problem: {
289
+ leaf: "problem",
290
+ export: "Problem"
291
+ },
288
292
  String: {
289
293
  leaf: "string",
290
294
  export: "StringType"