elysia 2.0.0-exp.2 → 2.0.0-exp.21

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 (135) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +2 -0
  2. package/dist/adapter/bun/index.d.ts +2 -25
  3. package/dist/adapter/bun/index.js +18 -12
  4. package/dist/adapter/bun/index.mjs +19 -13
  5. package/dist/adapter/bun/router.js +1 -1
  6. package/dist/adapter/bun/router.mjs +1 -1
  7. package/dist/adapter/constants.d.ts +3 -26
  8. package/dist/adapter/index.d.ts +1 -26
  9. package/dist/adapter/index.js +1 -17
  10. package/dist/adapter/index.mjs +1 -17
  11. package/dist/adapter/types.d.ts +1 -0
  12. package/dist/adapter/utils.d.ts +3 -4
  13. package/dist/adapter/utils.js +83 -81
  14. package/dist/adapter/utils.mjs +82 -80
  15. package/dist/adapter/web-standard/handler.js +6 -3
  16. package/dist/adapter/web-standard/handler.mjs +6 -3
  17. package/dist/adapter/web-standard/index.d.ts +2 -26
  18. package/dist/adapter/web-standard/index.js +12 -1
  19. package/dist/adapter/web-standard/index.mjs +12 -1
  20. package/dist/base.d.ts +38 -68
  21. package/dist/base.js +133 -97
  22. package/dist/base.mjs +133 -97
  23. package/dist/compile/aot.d.ts +22 -1
  24. package/dist/compile/aot.js +22 -0
  25. package/dist/compile/aot.mjs +22 -0
  26. package/dist/compile/handler/index.d.ts +2 -2
  27. package/dist/compile/handler/index.js +85 -456
  28. package/dist/compile/handler/index.mjs +86 -457
  29. package/dist/compile/handler/jit.d.ts +35 -0
  30. package/dist/compile/handler/jit.js +445 -0
  31. package/dist/compile/handler/jit.mjs +443 -0
  32. package/dist/compile/handler/params.js +3 -2
  33. package/dist/compile/handler/params.mjs +4 -3
  34. package/dist/compile/handler/reconstruct.d.ts +13 -0
  35. package/dist/compile/handler/reconstruct.js +29 -0
  36. package/dist/compile/handler/reconstruct.mjs +28 -0
  37. package/dist/compile/handler/utils.d.ts +2 -1
  38. package/dist/compile/handler/utils.js +9 -3
  39. package/dist/compile/handler/utils.mjs +9 -4
  40. package/dist/compile/jit-probe.d.ts +19 -0
  41. package/dist/compile/jit-probe.js +38 -0
  42. package/dist/compile/jit-probe.mjs +36 -0
  43. package/dist/cookie/index.d.ts +4 -3
  44. package/dist/cookie/index.js +2 -1
  45. package/dist/cookie/index.mjs +2 -1
  46. package/dist/cookie/serialize.d.ts +6 -0
  47. package/dist/cookie/serialize.js +28 -0
  48. package/dist/cookie/serialize.mjs +27 -0
  49. package/dist/cookie/utils.d.ts +1 -2
  50. package/dist/cookie/utils.js +2 -23
  51. package/dist/cookie/utils.mjs +5 -25
  52. package/dist/handler/error.js +2 -2
  53. package/dist/handler/error.mjs +3 -3
  54. package/dist/handler/fetch.js +49 -42
  55. package/dist/handler/fetch.mjs +50 -43
  56. package/dist/index.d.ts +13 -8
  57. package/dist/index.js +11 -4
  58. package/dist/index.mjs +7 -6
  59. package/dist/parse-query.js +1 -1
  60. package/dist/parse-query.mjs +1 -1
  61. package/dist/plugin/bun.d.ts +10 -0
  62. package/dist/plugin/bun.js +18 -1
  63. package/dist/plugin/bun.mjs +19 -2
  64. package/dist/plugin/core.d.ts +61 -1
  65. package/dist/plugin/core.js +90 -10
  66. package/dist/plugin/core.mjs +90 -12
  67. package/dist/plugin/esbuild.d.ts +10 -0
  68. package/dist/plugin/esbuild.js +18 -1
  69. package/dist/plugin/esbuild.mjs +19 -2
  70. package/dist/plugin/source.d.ts +38 -1
  71. package/dist/plugin/source.js +104 -13
  72. package/dist/plugin/source.mjs +102 -14
  73. package/dist/plugin/vite.d.ts +7 -0
  74. package/dist/plugin/vite.js +22 -1
  75. package/dist/plugin/vite.mjs +23 -2
  76. package/dist/sucrose.js +23 -10
  77. package/dist/sucrose.mjs +23 -10
  78. package/dist/trace.d.ts +1 -1
  79. package/dist/trace.js +4 -6
  80. package/dist/trace.mjs +4 -6
  81. package/dist/type/bridge.d.ts +9 -8
  82. package/dist/type/coerce.d.ts +20 -2
  83. package/dist/type/coerce.js +110 -0
  84. package/dist/type/coerce.mjs +109 -2
  85. package/dist/type/compat.js +4 -3
  86. package/dist/type/compat.mjs +2 -1
  87. package/dist/type/constants.d.ts +1 -1
  88. package/dist/type/elysia/boolean-string.js +1 -1
  89. package/dist/type/elysia/boolean-string.mjs +1 -1
  90. package/dist/type/elysia/file-type.js +1 -1
  91. package/dist/type/elysia/file-type.mjs +1 -1
  92. package/dist/type/elysia/integer-string.js +1 -1
  93. package/dist/type/elysia/integer-string.mjs +1 -1
  94. package/dist/type/exports.js +29 -2059
  95. package/dist/type/exports.mjs +7 -295
  96. package/dist/type/index.d.ts +6 -2
  97. package/dist/type/index.js +4 -0
  98. package/dist/type/index.mjs +3 -1
  99. package/dist/type/types.d.ts +1 -1
  100. package/dist/type/utils.js +4 -4
  101. package/dist/type/utils.mjs +4 -4
  102. package/dist/type/validator/custom-error.d.ts +10 -0
  103. package/dist/type/validator/custom-error.js +113 -0
  104. package/dist/type/validator/custom-error.mjs +110 -0
  105. package/dist/type/validator/default-precompute.d.ts +22 -0
  106. package/dist/type/validator/default-precompute.js +476 -0
  107. package/dist/type/validator/default-precompute.mjs +465 -0
  108. package/dist/type/validator/frozen-check.d.ts +11 -0
  109. package/dist/type/validator/frozen-check.js +19 -0
  110. package/dist/type/validator/frozen-check.mjs +18 -0
  111. package/dist/type/{validator.d.ts → validator/index.d.ts} +7 -20
  112. package/dist/type/validator/index.js +572 -0
  113. package/dist/type/validator/index.mjs +567 -0
  114. package/dist/type/validator/string-codec-aot.d.ts +9 -0
  115. package/dist/type/validator/string-codec-aot.js +106 -0
  116. package/dist/type/validator/string-codec-aot.mjs +102 -0
  117. package/dist/type/validator/validator-cache.d.ts +21 -0
  118. package/dist/type/validator/validator-cache.js +163 -0
  119. package/dist/type/validator/validator-cache.mjs +161 -0
  120. package/dist/types.d.ts +22 -14
  121. package/dist/universal/file.d.ts +1 -1
  122. package/dist/universal/file.js +35 -29
  123. package/dist/universal/file.mjs +35 -29
  124. package/dist/utils.d.ts +12 -1
  125. package/dist/utils.js +89 -45
  126. package/dist/utils.mjs +88 -46
  127. package/dist/validator/index.d.ts +1 -1
  128. package/dist/validator/index.js +15 -2
  129. package/dist/validator/index.mjs +15 -2
  130. package/dist/validator/route.d.ts +0 -1
  131. package/dist/ws/route.js +47 -24
  132. package/dist/ws/route.mjs +48 -25
  133. package/package.json +10 -4
  134. package/dist/type/validator.js +0 -1033
  135. package/dist/type/validator.mjs +0 -1029
package/dist/base.js CHANGED
@@ -5,34 +5,19 @@ const require_constants = require('./constants.js');
5
5
  const require_utils = require('./utils.js');
6
6
  const require_type_bridge = require('./type/bridge.js');
7
7
  const require_universal_env = require('./universal/env.js');
8
+ const require_compile_aot = require('./compile/aot.js');
9
+ const require_compile_handler_index = require('./compile/handler/index.js');
8
10
  const require_ws_route = require('./ws/route.js');
9
11
  const require_adapter_bun_index = require('./adapter/bun/index.js');
10
12
  const require_handler_fetch = require('./handler/fetch.js');
11
- const require_compile_handler_index = require('./compile/handler/index.js');
12
13
  let memoirist = require("memoirist");
13
14
  memoirist = require_runtime.__toESM(memoirist);
14
15
 
15
16
  //#region src/base.ts
16
17
  const useNodesBuffer = [];
17
- const isPlainObject = (v) => {
18
- if (!v || typeof v !== "object" || Array.isArray(v)) return false;
19
- const proto = Object.getPrototypeOf(v);
20
- return proto === Object.prototype || proto === null;
21
- };
22
- function clonePlainDecorators(source, seen = /* @__PURE__ */ new WeakMap()) {
23
- const existing = seen.get(source);
24
- if (existing) return existing;
25
- const out = require_utils.nullObject();
26
- seen.set(source, out);
27
- for (const key in source) {
28
- const value = source[key];
29
- out[key] = isPlainObject(value) ? clonePlainDecorators(value, seen) : value;
30
- }
31
- return out;
32
- }
33
18
  var Elysia = class Elysia {
34
- #hasPlugin = false;
35
- #hasGlobal = false;
19
+ #hasPlugin;
20
+ #hasGlobal;
36
21
  #ready;
37
22
  #pending = 0;
38
23
  #error;
@@ -53,6 +38,7 @@ var Elysia = class Elysia {
53
38
  }
54
39
  #compiled;
55
40
  #cachedRoutes;
41
+ #hasMapResponse;
56
42
  constructor(config) {
57
43
  this["~config"] = config;
58
44
  this["~Prefix"] = config?.prefix;
@@ -173,23 +159,8 @@ var Elysia = class Elysia {
173
159
  #onBranch(type, scopeOrFn, fn) {
174
160
  return fn ? this.#on(type, fn, scopeOrFn) : this.#on(type, scopeOrFn);
175
161
  }
176
- on(...args) {
177
- if (args.length === 2) {
178
- const [event, fn] = args;
179
- if (event === "parse" && typeof fn === "string") {
180
- const named = this["~ext"]?.parser?.[fn];
181
- return this.#onBranch("parse", named ?? fn);
182
- }
183
- return this.#onBranch(event, fn);
184
- }
185
- if (args.length === 3) {
186
- const [scope, event, fn] = args;
187
- return this.#onBranch(event, scope, fn);
188
- }
189
- return this;
190
- }
191
- request(scopeOrFn, fn) {
192
- return this.#onBranch("request", scopeOrFn, fn);
162
+ request(fn) {
163
+ return this.#on("request", fn, "global");
193
164
  }
194
165
  parse(scopeOrFnOrName, fn) {
195
166
  if (fn === void 0 && typeof scopeOrFnOrName === "string") {
@@ -204,10 +175,24 @@ var Elysia = class Elysia {
204
175
  parsers[name] = fn;
205
176
  return this;
206
177
  }
207
- onStart(_listener) {
208
- return this;
209
- }
210
- onStop(_listener) {
178
+ /**
179
+ * ### setup | Life cycle event
180
+ * Called after server is ready for serving
181
+ *
182
+ * ---
183
+ * @example
184
+ * ```typescript
185
+ * new Elysia()
186
+ * .setup(({ server }) => {
187
+ * console.log("Running at ${server?.url}:${server?.port}")
188
+ * })
189
+ * .listen(3000)
190
+ * ```
191
+ */
192
+ setup(handler) {
193
+ const arr = this.#ext.setup ??= [];
194
+ if (Array.isArray(handler)) arr.push(...handler);
195
+ else arr.push(handler);
211
196
  return this;
212
197
  }
213
198
  transform(scopeOrFn, fn) {
@@ -228,6 +213,7 @@ var Elysia = class Elysia {
228
213
  return this.#onBranch("afterHandle", scopeOrFn, fn);
229
214
  }
230
215
  mapResponse(scopeOrFn, fn) {
216
+ this.#hasMapResponse = true;
231
217
  return this.#onBranch("mapResponse", scopeOrFn, fn);
232
218
  }
233
219
  afterResponse(scopeOrFn, fn) {
@@ -289,15 +275,7 @@ var Elysia = class Elysia {
289
275
  }
290
276
  }
291
277
  guard() {
292
- if (arguments.length === 1) {
293
- const arg = arguments[0];
294
- let scope = "local";
295
- if (arg && typeof arg === "object" && "as" in arg && arg.as) {
296
- scope = arg.as;
297
- delete arg.as;
298
- }
299
- return this.#guard(scope, arg);
300
- }
278
+ if (arguments.length === 1) return this.#guard("local", arguments[0]);
301
279
  if (arguments.length === 2) {
302
280
  if (typeof arguments[1] === "function") return this.group("", arguments[0], arguments[1]);
303
281
  return this.#guard(arguments[0], arguments[1]);
@@ -354,9 +332,8 @@ var Elysia = class Elysia {
354
332
  const finalize = () => {
355
333
  const childFlat = require_utils.flattenChain(child["~hookChain"]);
356
334
  const lifted = require_utils.nullObject();
357
- if (childFlat?.request) lifted.request = childFlat.request;
358
335
  if (childFlat?.parse) lifted.parse = childFlat.parse;
359
- if (lifted.request || lifted.parse) this.#pushHook(lifted);
336
+ if (lifted.parse) this.#pushHook(lifted);
360
337
  return child;
361
338
  };
362
339
  if (child.pending) return this.#useAsync(child.modules.then(finalize));
@@ -394,7 +371,7 @@ var Elysia = class Elysia {
394
371
  return this;
395
372
  }
396
373
  macro(macro) {
397
- if (typeof macro === "function") throw new Error("Use `.macro({ name: fn })` instead of `.macro(fn)`");
374
+ if (typeof macro === "function") throw new Error("use `.macro({ name: fn })` instead of `.macro(fn)`");
398
375
  const ext = this.#ext;
399
376
  const m = ext.macro ??= require_utils.nullObject();
400
377
  for (const key in macro) if (typeof macro[key] === "object") macro[key] = require_utils.hookToGuard(macro[key]);
@@ -490,7 +467,8 @@ var Elysia = class Elysia {
490
467
  for (const plugin of app) this.#use(plugin);
491
468
  return this;
492
469
  }
493
- if (app !== this && app.pending) return this.#useAsync(app.modules.then(() => app));
470
+ if (app === this) return this;
471
+ if (app.pending) return this.#useAsync(app.modules.then(() => app));
494
472
  this.#use(app);
495
473
  return this;
496
474
  }
@@ -556,11 +534,12 @@ var Elysia = class Elysia {
556
534
  }
557
535
  }
558
536
  const hookChain = app["~hookChain"];
537
+ if (!this.#hasMapResponse && app.#hasMapResponse) this.#hasMapResponse = true;
559
538
  if (app["~ext"]) {
560
- const { decorator, store, headers, models, parser, macro, error, hoc } = app["~ext"];
539
+ const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup } = app["~ext"];
561
540
  const ext = this["~ext"] ??= require_utils.nullObject();
562
541
  if (decorator) {
563
- const cloned = clonePlainDecorators(decorator);
542
+ const cloned = require_utils.clonePlainDecorators(decorator);
564
543
  if (ext.decorator) require_utils.mergeDeep(ext.decorator, cloned);
565
544
  else ext.decorator = Object.assign(require_utils.nullObject(), cloned);
566
545
  }
@@ -579,6 +558,12 @@ var Elysia = class Elysia {
579
558
  if (hoc) if (ext.hoc) {
580
559
  for (const fn of hoc) if (!ext.hoc.includes(fn)) ext.hoc.push(fn);
581
560
  } else ext.hoc = hoc.slice();
561
+ if (setup) if (ext.setup) {
562
+ for (const fn of setup) if (!ext.setup.includes(fn)) ext.setup.push(fn);
563
+ } else ext.setup = setup.slice();
564
+ if (cleanup) if (ext.cleanup) {
565
+ for (const fn of cleanup) if (!ext.cleanup.includes(fn)) ext.cleanup.push(fn);
566
+ } else ext.cleanup = cleanup.slice();
582
567
  }
583
568
  if (app.#hasPlugin || app.#hasGlobal || hookChain) {
584
569
  let pluginEvents;
@@ -829,18 +814,23 @@ var Elysia = class Elysia {
829
814
  }
830
815
  #initMap() {
831
816
  this["~map"] ??= {
832
- GET: require_utils.nullObject(),
833
- POST: require_utils.nullObject(),
834
- PUT: require_utils.nullObject(),
835
- DELETE: require_utils.nullObject(),
836
- PATCH: require_utils.nullObject(),
837
- HEAD: require_utils.nullObject(),
838
- OPTIONS: require_utils.nullObject()
817
+ GET: void 0,
818
+ POST: void 0,
819
+ PUT: void 0,
820
+ DELETE: void 0,
821
+ PATCH: void 0,
822
+ HEAD: void 0,
823
+ OPTIONS: void 0
839
824
  };
840
825
  }
841
826
  compile() {
842
827
  this["~config"] ??= require_utils.nullObject();
843
828
  this["~config"].precompile = true;
829
+ this.#routerBuilt = false;
830
+ if (require_compile_aot.Capture.isCapturing()) {
831
+ this.#compiled = void 0;
832
+ this.#fetchFn = void 0;
833
+ }
844
834
  this.fetch;
845
835
  return this;
846
836
  }
@@ -867,6 +857,7 @@ var Elysia = class Elysia {
867
857
  };
868
858
  }
869
859
  #saveHandler(method, path, handler) {
860
+ if (require_constants.isDynamicRegex.test(path)) return;
870
861
  this.#initMap();
871
862
  const map = this["~map"][require_utils.mapMethodBack(method)] ??= require_utils.nullObject();
872
863
  map[path] = handler;
@@ -911,9 +902,9 @@ var Elysia = class Elysia {
911
902
  for (let i = 0; i < length; i++) if (require_utils.mapMethodBack(this.#history[i][0]) === "HEAD") (explicitHead ??= /* @__PURE__ */ new Set()).add(this.#history[i][1]);
912
903
  }
913
904
  const wrapHeadHandler = Elysia.#wrapHeadHandler;
914
- const strict = !!this["~config"]?.strictPath;
905
+ const preferLoosePath = this["~config"]?.strictPath !== true;
915
906
  let explicitPaths;
916
- if (!strict) {
907
+ if (preferLoosePath && this["~config"]?.distinctPath) {
917
908
  explicitPaths = /* @__PURE__ */ new Map();
918
909
  for (let i = 0; i < length; i++) {
919
910
  const route = this.#history[i];
@@ -936,7 +927,7 @@ var Elysia = class Elysia {
936
927
  const ws = require_ws_route.buildWSRoute(route, this);
937
928
  const handler = ws[0];
938
929
  const options = ws[1];
939
- if (require_constants.isDynamicRegex.test(path)) (this["~router"] ??= new memoirist.default()).add("WS", path, handler, false);
930
+ if (require_constants.isDynamicRegex.test(path)) (this["~router"] ??= new memoirist.default({ loosePath: preferLoosePath })).add("WS", path, handler, false);
940
931
  else {
941
932
  this.#initMap();
942
933
  const wsMap = this["~map"]["WS"] ??= require_utils.nullObject();
@@ -963,51 +954,70 @@ var Elysia = class Elysia {
963
954
  let staticResponse;
964
955
  const maybeStatic = buildStatic && typeof route[2] !== "function";
965
956
  if (maybeStatic) {
966
- staticResponse = require_compile_handler_index.buildNativeStaticResponse(route, this);
957
+ staticResponse = require_compile_handler_index.buildNativeStaticResponse(route, this, this.#hasMapResponse);
967
958
  if (staticResponse) {
968
- const target = this["~staticResponse"] ??= require_utils.nullObject();
969
- (target[path] ??= require_utils.nullObject())[method] = staticResponse;
959
+ const target = this["~staticResponse"] ??= {
960
+ GET: void 0,
961
+ POST: void 0,
962
+ PUT: void 0,
963
+ DELETE: void 0,
964
+ PATCH: void 0,
965
+ HEAD: void 0,
966
+ OPTIONS: void 0
967
+ };
968
+ (target[method] ??= require_utils.nullObject())[path] = staticResponse;
970
969
  if (!this["~config"]?.strictPath) {
971
970
  const loose = require_utils.getLoosePath(path);
972
- if (!explicitPaths?.get(method)?.has(loose)) (target[loose] ??= require_utils.nullObject())[method] = staticResponse;
971
+ if (!explicitPaths?.get(method)?.has(loose)) (target[method] ??= require_utils.nullObject())[loose] = staticResponse;
973
972
  }
974
973
  }
975
974
  }
976
975
  const sharedStatic = maybeStatic && staticResponse instanceof Response ? staticResponse : void 0;
977
976
  const autoHead = enableAutoHead && method === "GET" && !explicitHead?.has(path);
978
- const registerPattern = (registerMain, registerHead, handler, headHandler, registerLoose) => {
979
- const explicitMain = explicitPaths?.get(method);
980
- const add = (p) => {
981
- registerMain(p, handler);
982
- if (headHandler) registerHead(p, headHandler);
983
- if (registerLoose) {
984
- const loose = require_utils.getLoosePath(p);
985
- if (loose !== p && !explicitMain?.has(loose)) {
986
- registerMain(loose, handler);
987
- if (headHandler) registerHead(loose, headHandler);
988
- }
989
- }
990
- };
991
- add(path);
992
- if (require_constants.needEncodeRegex.test(path)) {
993
- const encoded = encodeURI(path);
994
- if (encoded !== path) add(encoded);
977
+ const isDynamic = require_constants.isDynamicRegex.test(path);
978
+ const registerLoose = !isDynamic && preferLoosePath && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
979
+ const explicitMain = registerLoose ? explicitPaths?.get(method) : void 0;
980
+ if (!isDynamic && !require_constants.needEncodeRegex.test(path) && !registerLoose) {
981
+ const map = methods[method] ??= require_utils.nullObject();
982
+ const handler = this.handler(i, precompile, route, sharedStatic);
983
+ map[path] = handler;
984
+ if (autoHead) {
985
+ const head = methods["HEAD"] ??= require_utils.nullObject();
986
+ head[path] = wrapHeadHandler(handler);
995
987
  }
996
- };
997
- if (require_constants.isDynamicRegex.test(path)) {
998
- const router = this["~router"] ??= new memoirist.default();
988
+ continue;
989
+ }
990
+ const variants = [path];
991
+ if (require_constants.needEncodeRegex.test(path)) {
992
+ const encoded = encodeURI(path);
993
+ if (encoded !== path) variants.push(encoded);
994
+ }
995
+ const paths = [];
996
+ for (let v = 0; v < variants.length; v++) {
997
+ const p = variants[v];
998
+ paths.push(p);
999
+ if (registerLoose) {
1000
+ const loose = require_utils.getLoosePath(p);
1001
+ if (loose !== p && !explicitMain?.has(loose)) paths.push(loose);
1002
+ }
1003
+ }
1004
+ if (isDynamic) {
1005
+ const router = this["~router"] ??= new memoirist.default({ loosePath: preferLoosePath });
999
1006
  const handler = this.handler(i, precompile, void 0, sharedStatic);
1000
- registerPattern((p, h) => router.add(method, p, h, false), (p, h) => router.add("HEAD", p, h, false), handler, autoHead ? wrapHeadHandler(handler) : void 0, false);
1007
+ const headHandler = autoHead ? wrapHeadHandler(handler) : void 0;
1008
+ for (let p = 0; p < paths.length; p++) {
1009
+ router.add(method, paths[p], handler, false);
1010
+ if (headHandler) router.add("HEAD", paths[p], headHandler, false);
1011
+ }
1001
1012
  } else {
1002
1013
  const map = methods[method] ??= require_utils.nullObject();
1003
1014
  const handler = this.handler(i, precompile, route, sharedStatic);
1004
1015
  const headHandler = autoHead ? wrapHeadHandler(handler) : void 0;
1005
1016
  const head = autoHead ? methods["HEAD"] ??= require_utils.nullObject() : void 0;
1006
- registerPattern((p, h) => {
1007
- map[p] = h;
1008
- }, (p, h) => {
1009
- head[p] = h;
1010
- }, handler, headHandler, !strict);
1017
+ for (let p = 0; p < paths.length; p++) {
1018
+ map[paths[p]] = handler;
1019
+ if (headHandler) head[paths[p]] = headHandler;
1020
+ }
1011
1021
  }
1012
1022
  }
1013
1023
  }
@@ -1032,13 +1042,33 @@ var Elysia = class Elysia {
1032
1042
  return this;
1033
1043
  }
1034
1044
  wrap(callback) {
1035
- if (this.#fetchFn) console.warn("[Elysia] .wrap() was called after the fetch handler was built, so it will not take effect. Register .wrap() before .listen() or before accessing .fetch/.handle.");
1045
+ if (this.#fetchFn) console.warn("[Elysia] .wrap() was called after the fetch handler was built");
1036
1046
  const ext = this.#ext;
1037
1047
  (ext.hoc ??= []).push(callback);
1038
1048
  return this;
1039
1049
  }
1040
1050
  /**
1041
- * Stop the underlying server (if any). Mirrors `Server.stop()`.
1051
+ * ### cleanup | Life cycle event
1052
+ * Called after server stop serving request
1053
+ *
1054
+ * ---
1055
+ * @example
1056
+ * ```typescript
1057
+ * new Elysia()
1058
+ * .cleanup((app) => {
1059
+ * closeDatabase()
1060
+ * })
1061
+ * ```
1062
+ */
1063
+ cleanup(handler) {
1064
+ const arr = this.#ext.cleanup ??= [];
1065
+ if (Array.isArray(handler)) arr.push(...handler);
1066
+ else arr.push(handler);
1067
+ return this;
1068
+ }
1069
+ /**
1070
+ * Stop the underlying server (if any), running every `cleanup` handler once
1071
+ * it has stopped. Mirrors `Server.stop()`.
1042
1072
  *
1043
1073
  * @param closeActiveConnections Pass `true` to terminate in-flight
1044
1074
  * requests and WebSocket connections immediately. Defaults to
@@ -1049,6 +1079,12 @@ var Elysia = class Elysia {
1049
1079
  if (!server) return;
1050
1080
  const r = server.stop?.(closeActiveConnections);
1051
1081
  this.server = void 0;
1082
+ const handlers = this["~ext"]?.cleanup;
1083
+ const fire = handlers ? () => {
1084
+ for (let i = 0; i < handlers.length; i++) handlers[i](this);
1085
+ } : void 0;
1086
+ if (r && typeof r.then === "function") return fire ? r.then(fire) : r;
1087
+ fire?.();
1052
1088
  return r;
1053
1089
  }
1054
1090
  };