elysia 2.0.0-exp.62 → 2.0.0-exp.63

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 (171) hide show
  1. package/dist/adapter/bun/index.d.ts +1 -1
  2. package/dist/adapter/bun/index.js +347 -90
  3. package/dist/adapter/bun/index.mjs +349 -92
  4. package/dist/adapter/utils.js +51 -36
  5. package/dist/adapter/utils.mjs +52 -37
  6. package/dist/adapter/web-standard/handler.js +5 -2
  7. package/dist/adapter/web-standard/handler.mjs +5 -2
  8. package/dist/base.d.ts +18 -7
  9. package/dist/base.js +214 -101
  10. package/dist/base.mjs +216 -103
  11. package/dist/compile/aot-capture.js +1 -1
  12. package/dist/compile/aot-capture.mjs +1 -1
  13. package/dist/compile/aot.d.ts +5 -4
  14. package/dist/compile/aot.js +17 -9
  15. package/dist/compile/aot.mjs +18 -9
  16. package/dist/compile/handler/descriptor.js +1 -1
  17. package/dist/compile/handler/descriptor.mjs +1 -1
  18. package/dist/compile/handler/frozen-validator.d.ts +4 -1
  19. package/dist/compile/handler/frozen-validator.js +8 -3
  20. package/dist/compile/handler/frozen-validator.mjs +5 -3
  21. package/dist/compile/handler/index.d.ts +2 -2
  22. package/dist/compile/handler/index.js +8 -6
  23. package/dist/compile/handler/index.mjs +8 -6
  24. package/dist/compile/handler/reconstruct.d.ts +1 -1
  25. package/dist/compile/handler/reconstruct.js +4 -3
  26. package/dist/compile/handler/reconstruct.mjs +4 -3
  27. package/dist/compile/handler/utils.js +2 -2
  28. package/dist/compile/handler/utils.mjs +3 -3
  29. package/dist/compile/jit-probe.d.ts +2 -2
  30. package/dist/context.d.ts +1 -1
  31. package/dist/context.js +8 -5
  32. package/dist/context.mjs +8 -5
  33. package/dist/cookie/config.d.ts +1 -0
  34. package/dist/cookie/config.js +3 -2
  35. package/dist/cookie/config.mjs +3 -2
  36. package/dist/cookie/cookie.d.ts +1 -0
  37. package/dist/cookie/cookie.js +6 -5
  38. package/dist/cookie/cookie.mjs +6 -5
  39. package/dist/cookie/crypto.d.ts +8 -7
  40. package/dist/cookie/crypto.js +38 -31
  41. package/dist/cookie/crypto.mjs +38 -32
  42. package/dist/cookie/error.js +1 -2
  43. package/dist/cookie/error.mjs +1 -2
  44. package/dist/cookie/lib.js +5 -1
  45. package/dist/cookie/lib.mjs +5 -1
  46. package/dist/cookie/serialize.js +1 -1
  47. package/dist/cookie/serialize.mjs +1 -1
  48. package/dist/cookie/types.d.ts +10 -0
  49. package/dist/cookie/utils.js +28 -14
  50. package/dist/cookie/utils.mjs +29 -15
  51. package/dist/handler/error.d.ts +23 -12
  52. package/dist/handler/error.js +24 -21
  53. package/dist/handler/error.mjs +20 -21
  54. package/dist/handler/fetch.js +6 -7
  55. package/dist/handler/fetch.mjs +7 -8
  56. package/dist/handler/utils.js +3 -2
  57. package/dist/handler/utils.mjs +3 -2
  58. package/dist/index.js +1 -8
  59. package/dist/package.js +1 -1
  60. package/dist/package.mjs +1 -1
  61. package/dist/plugin/aot/core.d.ts +33 -6
  62. package/dist/plugin/aot/core.js +120 -40
  63. package/dist/plugin/aot/core.mjs +121 -43
  64. package/dist/plugin/aot/esbuild.js +8 -2
  65. package/dist/plugin/aot/esbuild.mjs +9 -3
  66. package/dist/plugin/aot/hooks.d.ts +2 -1
  67. package/dist/plugin/aot/hooks.js +3 -3
  68. package/dist/plugin/aot/hooks.mjs +4 -4
  69. package/dist/plugin/aot/source.d.ts +4 -1
  70. package/dist/plugin/aot/source.js +21 -14
  71. package/dist/plugin/aot/source.mjs +21 -14
  72. package/dist/plugin/aot/worker.js +2 -2
  73. package/dist/plugin/aot/worker.mjs +2 -2
  74. package/dist/route-table.d.ts +3 -0
  75. package/dist/route-table.js +16 -11
  76. package/dist/route-table.mjs +16 -11
  77. package/dist/schema-snapshot.js +17 -22
  78. package/dist/schema-snapshot.mjs +17 -22
  79. package/dist/type/bridge-live.d.ts +2 -2
  80. package/dist/type/bridge-live.js +2 -2
  81. package/dist/type/bridge-live.mjs +2 -2
  82. package/dist/type/bridge.d.ts +4 -4
  83. package/dist/type/coerce-plan.js +3 -4
  84. package/dist/type/coerce-plan.mjs +1 -1
  85. package/dist/type/compat.d.ts +3 -0
  86. package/dist/type/compat.js +32 -14
  87. package/dist/type/compat.mjs +27 -8
  88. package/dist/type/elysia/array-buffer.js +2 -3
  89. package/dist/type/elysia/array-buffer.mjs +1 -1
  90. package/dist/type/elysia/array-string.js +7 -4
  91. package/dist/type/elysia/array-string.mjs +9 -5
  92. package/dist/type/elysia/boolean-string.js +2 -3
  93. package/dist/type/elysia/boolean-string.mjs +1 -1
  94. package/dist/type/elysia/boolean.js +4 -3
  95. package/dist/type/elysia/boolean.mjs +4 -2
  96. package/dist/type/elysia/cookie.js +2 -1
  97. package/dist/type/elysia/cookie.mjs +2 -1
  98. package/dist/type/elysia/date.js +7 -7
  99. package/dist/type/elysia/date.mjs +3 -2
  100. package/dist/type/elysia/file-type.d.ts +9 -2
  101. package/dist/type/elysia/file-type.js +16 -1
  102. package/dist/type/elysia/file-type.mjs +16 -2
  103. package/dist/type/elysia/file.js +8 -4
  104. package/dist/type/elysia/file.mjs +8 -3
  105. package/dist/type/elysia/files.js +6 -4
  106. package/dist/type/elysia/files.mjs +5 -2
  107. package/dist/type/elysia/form.js +2 -3
  108. package/dist/type/elysia/form.mjs +3 -3
  109. package/dist/type/elysia/integer-string.js +4 -5
  110. package/dist/type/elysia/integer-string.mjs +3 -3
  111. package/dist/type/elysia/integer.js +4 -3
  112. package/dist/type/elysia/integer.mjs +4 -2
  113. package/dist/type/elysia/maybe-empty.js +3 -4
  114. package/dist/type/elysia/maybe-empty.mjs +1 -1
  115. package/dist/type/elysia/nullable.js +2 -3
  116. package/dist/type/elysia/nullable.mjs +1 -1
  117. package/dist/type/elysia/number.js +4 -3
  118. package/dist/type/elysia/number.mjs +4 -2
  119. package/dist/type/elysia/numeric-enum.js +2 -3
  120. package/dist/type/elysia/numeric-enum.mjs +1 -1
  121. package/dist/type/elysia/numeric.js +5 -5
  122. package/dist/type/elysia/numeric.mjs +3 -2
  123. package/dist/type/elysia/object-string.js +7 -4
  124. package/dist/type/elysia/object-string.mjs +9 -5
  125. package/dist/type/elysia/string.js +4 -3
  126. package/dist/type/elysia/string.mjs +4 -2
  127. package/dist/type/elysia/uint8-array.js +2 -3
  128. package/dist/type/elysia/uint8-array.mjs +1 -1
  129. package/dist/type/elysia/union-enum.js +2 -3
  130. package/dist/type/elysia/union-enum.mjs +1 -1
  131. package/dist/type/elysia/utils.js +2 -3
  132. package/dist/type/elysia/utils.mjs +1 -1
  133. package/dist/type/exports.js +10 -1
  134. package/dist/type/exports.mjs +7 -0
  135. package/dist/type/index.d.ts +9 -1
  136. package/dist/type/index.js +41 -13
  137. package/dist/type/index.mjs +44 -9
  138. package/dist/type/typebox-type-live.d.ts +9 -0
  139. package/dist/type/typebox-type-live.js +31 -0
  140. package/dist/type/typebox-type-live.mjs +16 -0
  141. package/dist/type/typebox-type.d.ts +24 -0
  142. package/dist/type/typebox-type.js +130 -0
  143. package/dist/type/typebox-type.mjs +66 -0
  144. package/dist/type/typebox-value-live.d.ts +9 -0
  145. package/dist/type/typebox-value-live.js +27 -0
  146. package/dist/type/typebox-value-live.mjs +11 -0
  147. package/dist/type/typebox-value.d.ts +30 -0
  148. package/dist/type/typebox-value.js +147 -0
  149. package/dist/type/typebox-value.mjs +62 -0
  150. package/dist/type/validator/custom-error.js +4 -5
  151. package/dist/type/validator/custom-error.mjs +3 -3
  152. package/dist/type/validator/default-precompute.js +4 -5
  153. package/dist/type/validator/default-precompute.mjs +1 -1
  154. package/dist/type/validator/index.d.ts +1 -1
  155. package/dist/type/validator/index.js +51 -42
  156. package/dist/type/validator/index.mjs +33 -23
  157. package/dist/type/validator/validator-cache.d.ts +1 -1
  158. package/dist/type/validator/validator-cache.js +27 -14
  159. package/dist/type/validator/validator-cache.mjs +27 -13
  160. package/dist/types.d.ts +12 -1
  161. package/dist/utils.d.ts +19 -1
  162. package/dist/utils.js +25 -3
  163. package/dist/utils.mjs +19 -3
  164. package/dist/validator/index.js +2 -1
  165. package/dist/validator/index.mjs +2 -1
  166. package/dist/ws/context.d.ts +8 -1
  167. package/dist/ws/context.js +65 -29
  168. package/dist/ws/context.mjs +64 -29
  169. package/dist/ws/route.js +176 -28
  170. package/dist/ws/route.mjs +179 -31
  171. package/package.json +5 -3
@@ -1,7 +1,7 @@
1
1
  import { AnyElysia } from "../../base.js";
2
2
  import { ElysiaAdapterOptions } from "../types.js";
3
3
  //#region src/adapter/bun/index.d.ts
4
- declare function collectStaticRoutes(app: AnyElysia): readonly [Record<string, Record<string, Response>>, readonly []] | undefined;
4
+ declare function collectStaticRoutes(app: AnyElysia): Record<string, Record<string, Response>> | undefined;
5
5
  declare const BunAdapter: ElysiaAdapterOptions<void>;
6
6
  //#endregion
7
7
  export { BunAdapter, collectStaticRoutes };
@@ -1,6 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_adapter_index = require('../index.js');
3
- const require_constants = require('../../constants.js');
4
3
  const require_utils = require('../../utils.js');
5
4
  const require_adapter_web_standard_index = require('../web-standard/index.js');
6
5
  const require_generation = require('../../generation.js');
@@ -9,6 +8,77 @@ const require_compile_handler_index = require('../../compile/handler/index.js');
9
8
  const require_route_table = require('../../route-table.js');
10
9
 
11
10
  //#region src/adapter/bun/index.ts
11
+ function runLifecycle(epoch, callback, ...args) {
12
+ const invoking = epoch.invoking;
13
+ epoch.invoking = true;
14
+ try {
15
+ return callback(...args);
16
+ } finally {
17
+ epoch.invoking = invoking;
18
+ }
19
+ }
20
+ const unavailableFetch = () => new Response(null, {
21
+ headers: { connection: "close" },
22
+ status: 503
23
+ });
24
+ function reloadServer(server, serve) {
25
+ try {
26
+ server.reload(serve);
27
+ } catch (error) {
28
+ if (!serve.routes) throw error;
29
+ delete serve.routes;
30
+ console.warn("[Elysia] Native static promotion was skipped:", error);
31
+ try {
32
+ server.reload(serve);
33
+ } catch (fallbackError) {
34
+ console.error("[Elysia] Failed to reload Bun server:", fallbackError);
35
+ throw fallbackError;
36
+ }
37
+ }
38
+ }
39
+ function releaseLifecycle(app, ext, createdExt, stop, registerCleanup) {
40
+ if (ext.stop === stop) delete ext.stop;
41
+ if (ext.cleanupEpoch === registerCleanup) delete ext.cleanupEpoch;
42
+ if (createdExt && app["~ext"] === ext && !Object.keys(ext).length) app["~ext"] = void 0;
43
+ }
44
+ function clearAppServer(app, server) {
45
+ if (app.server === server) app.server = void 0;
46
+ }
47
+ async function waitForServerRequests(server, abandoned) {
48
+ while (server.pendingRequests && !abandoned()) await Bun.sleep(1);
49
+ }
50
+ async function settleServerWebSockets(lifecycle, errors) {
51
+ if (!lifecycle) return true;
52
+ lifecycle.closing = true;
53
+ let failed = false;
54
+ do {
55
+ for (const socket of lifecycle.sockets) if (socket.readyState < 3) try {
56
+ socket.terminate();
57
+ } catch (error) {
58
+ errors.push(error);
59
+ failed = true;
60
+ }
61
+ if (failed) return false;
62
+ await Bun.sleep(1);
63
+ const abandon = lifecycle.abandon === true;
64
+ for (const socket of lifecycle.sockets) if (abandon || require_utils.isSocketQuiet(socket)) {
65
+ delete socket.data["~lifecycleRun"];
66
+ lifecycle.sockets.delete(socket);
67
+ }
68
+ } while (lifecycle.sockets.size);
69
+ return true;
70
+ }
71
+ const closeServerIdle = (server, errors) => {
72
+ const close = server.closeIdleConnections;
73
+ if (!close) return true;
74
+ try {
75
+ close.call(server);
76
+ return true;
77
+ } catch (error) {
78
+ errors.push(error);
79
+ return false;
80
+ }
81
+ };
12
82
  /**
13
83
  * ! This may looks like it would cause race condition, but it is not
14
84
  * Bun is single-threaded and synchronous, so the `finally` block will
@@ -26,15 +96,7 @@ const withOrigin = (fetch) => (request, server) => {
26
96
  require_adapter_origin.origin.request = void 0;
27
97
  }
28
98
  };
29
- const nativeStaticMethods = new Set([
30
- "GET",
31
- "POST",
32
- "PUT",
33
- "DELETE",
34
- "PATCH",
35
- "HEAD",
36
- "OPTIONS"
37
- ]);
99
+ const isNativeStaticMethod = (method) => method === "GET" || method === "POST" || method === "PUT" || method === "DELETE" || method === "PATCH" || method === "HEAD" || method === "OPTIONS";
38
100
  function collectStaticRoutes(app) {
39
101
  if (app["~config"]?.nativeStaticResponse === false) return;
40
102
  app.fetch;
@@ -44,59 +106,58 @@ function collectStaticRoutes(app) {
44
106
  const table = app["~generation"]?.routeTable ?? app["~routeTable"];
45
107
  const length = table?.length ?? 0;
46
108
  if (!table || !length) return;
47
- const methods = table.method;
48
- const paths = table.path;
49
- const handlers = table.handler;
109
+ const { method: methods, path: paths, handler: handlers, flags } = table;
50
110
  let hasCandidate = false;
51
111
  for (let i = 0; i < length; i++) {
112
+ if (!isNativeStaticMethod(methods[i]) || (flags[i] & require_route_table.RouteFlag.Dynamic) !== 0) continue;
52
113
  const h = handlers[i];
53
- if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
54
- if (!nativeStaticMethods.has(methods[i])) continue;
55
- hasCandidate = true;
56
- break;
114
+ if (typeof h !== "function" && !(h instanceof Error) && !(h instanceof Promise)) {
115
+ hasCandidate = true;
116
+ break;
117
+ }
57
118
  }
58
119
  if (!hasCandidate) return;
59
- const ready = require_utils.nullObject();
60
120
  const strictPath = frozenRoot["~config"]?.strictPath === true;
61
- const seen = /* @__PURE__ */ new Map();
62
- for (let i = 0; i < length; i++) seen.set(methods[i] + " " + paths[i], i);
63
- let explicitPaths;
64
- if (!strictPath) {
65
- explicitPaths = /* @__PURE__ */ new Map();
66
- for (let i = 0; i < length; i++) {
67
- const method = methods[i];
68
- const path = paths[i];
69
- let set = explicitPaths.get(method);
70
- if (!set) explicitPaths.set(method, set = /* @__PURE__ */ new Set());
71
- set.add(path);
72
- if (require_constants.needEncodeRegex.test(path)) {
73
- const encoded = encodeURI(path);
74
- if (encoded !== path) set.add(encoded);
75
- }
121
+ const routeIndex = /* @__PURE__ */ new Map();
122
+ for (let i = 0; i < length; i++) {
123
+ const method = methods[i];
124
+ if (!isNativeStaticMethod(method) || (flags[i] & require_route_table.RouteFlag.Dynamic) !== 0) continue;
125
+ const path = paths[i];
126
+ let pathsByMethod = routeIndex.get(method);
127
+ if (!pathsByMethod) routeIndex.set(method, pathsByMethod = /* @__PURE__ */ new Map());
128
+ pathsByMethod.set(path, i);
129
+ if (!strictPath && (flags[i] & require_route_table.RouteFlag.Encode) !== 0) {
130
+ const encoded = encodeURI(path);
131
+ if (encoded !== path && !pathsByMethod.has(encoded)) pathsByMethod.set(encoded, -1);
76
132
  }
77
133
  }
78
- const add = (method, path, value) => {
79
- if (require_constants.needEncodeRegex.test(path)) path = encodeURI(path);
134
+ const ready = require_utils.nullObject();
135
+ let hasReady = false;
136
+ const add = (method, path, value, needsEncode) => {
137
+ if (needsEncode) path = encodeURI(path);
80
138
  (ready[path] ??= require_utils.nullObject())[method] = value;
139
+ hasReady = true;
81
140
  };
82
141
  for (let i = 0; i < length; i++) {
83
142
  const method = methods[i];
84
- if (method === "WS") continue;
143
+ const routeFlags = flags[i];
144
+ if (!isNativeStaticMethod(method) || (routeFlags & require_route_table.RouteFlag.Dynamic) !== 0) continue;
145
+ const pathsByMethod = routeIndex.get(method);
85
146
  const path = paths[i];
86
- if (seen.get(method + " " + path) !== i) continue;
87
- if (!nativeStaticMethods.has(method)) continue;
147
+ if (pathsByMethod.get(path) !== i) continue;
88
148
  const h = handlers[i];
89
149
  if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
90
150
  const value = require_compile_handler_index.buildNativeStaticResponse(require_route_table.routeRow(table, i), app);
91
151
  if (!value) continue;
92
- add(method, path, value);
93
- if (!strictPath && !require_constants.isDynamicRegex.test(path)) {
152
+ const needsEncode = (routeFlags & require_route_table.RouteFlag.Encode) !== 0;
153
+ add(method, path, value, needsEncode);
154
+ if (!strictPath) {
94
155
  const loose = require_utils.getLoosePath(path);
95
- if (loose !== path && !explicitPaths?.get(method)?.has(loose)) add(method, loose, value);
156
+ if (loose !== path && !pathsByMethod.has(loose)) add(method, loose, value, needsEncode);
96
157
  }
97
158
  }
98
- if (!Object.keys(ready).length) return;
99
- return [ready, []];
159
+ if (!hasReady) return;
160
+ return ready;
100
161
  }
101
162
  const BunAdapter = require_adapter_index.createAdapter({
102
163
  name: "bun",
@@ -105,23 +166,41 @@ const BunAdapter = require_adapter_index.createAdapter({
105
166
  parse: require_adapter_web_standard_index.WebStandardAdapter.parse,
106
167
  response: require_adapter_web_standard_index.WebStandardAdapter.response,
107
168
  listen(app, options, callback) {
108
- const _config = app["~config"]?.serve;
169
+ if (app.server || app["~ext"]?.stop) throw new Error("[Elysia] Cannot call listen() while a server or teardown is active");
170
+ function gatedFetch(request, server) {
171
+ return live ? live(request, server) : Promise.resolve(ready).then(async () => {
172
+ if (!live) {
173
+ await startupShutdown;
174
+ throw new Error("[Elysia] Server was stopped before it was ready");
175
+ }
176
+ return live(request, server);
177
+ });
178
+ }
109
179
  const optionsIsObject = typeof options === "object";
110
- let live;
111
- const gatedFetch = (request, server) => live ? live(request, server) : Promise.resolve(ready).then(() => {
112
- if (!live) throw new Error("[Elysia] Server was stopped before it was ready");
113
- return live(request, server);
114
- });
115
180
  const _options = optionsIsObject ? { ...options } : {
116
181
  port: +options,
117
182
  fetch: gatedFetch
118
183
  };
119
184
  if (optionsIsObject) _options.fetch = gatedFetch;
185
+ const _config = app["~config"]?.serve;
120
186
  const serve = _config ? {
121
187
  ..._config,
122
188
  ..._options
123
189
  } : _options;
190
+ const server = app.server = Bun.serve(serve.routes || serve.error ? {
191
+ ...serve,
192
+ error: unavailableFetch,
193
+ routes: {}
194
+ } : serve);
195
+ let live;
196
+ let cancelled = false;
197
+ let startupShutdown;
198
+ let shutdownAttempt;
124
199
  let ready;
200
+ let wsLifecycle;
201
+ let modulesReady;
202
+ let built;
203
+ let pendingSetups;
125
204
  const build = () => {
126
205
  const fetch = app.fetch;
127
206
  let routes;
@@ -134,7 +213,17 @@ const BunAdapter = require_adapter_index.createAdapter({
134
213
  if (app["~hasWS"]) {
135
214
  const resolved = require_generation.resolvedWsOf(app);
136
215
  if (!resolved) throw new Error("[Elysia] internal: WebSocket routes are present but no capability provider was resolved");
137
- websocket = resolved.config ? Object.assign(resolved.provider.buildGlobalWSHandler(), resolved.config) : resolved.provider.buildGlobalWSHandler();
216
+ const handler = resolved.provider.buildGlobalWSHandler();
217
+ websocket = resolved.config ? Object.assign(handler, resolved.config) : handler;
218
+ const setter = Object.getOwnPropertyDescriptor(handler, "~lifecycle")?.set;
219
+ if (setter) {
220
+ wsLifecycle = {
221
+ closing: false,
222
+ sockets: /* @__PURE__ */ new Set(),
223
+ run: runLifecycle.bind(null, epoch)
224
+ };
225
+ setter.call(handler, wsLifecycle);
226
+ }
138
227
  }
139
228
  return {
140
229
  fetch,
@@ -142,75 +231,243 @@ const BunAdapter = require_adapter_index.createAdapter({
142
231
  websocket
143
232
  };
144
233
  };
145
- let built;
146
- const server = app.server = Bun.serve(serve);
147
- const reload = () => {
234
+ let startupFailure;
235
+ let forceRequested = false;
236
+ let forceDone = false;
237
+ let nativeStopped = false;
238
+ let abandoned = false;
239
+ let published = false;
240
+ let cleanupCompleted = false;
241
+ let idleRequired = false;
242
+ let cleanupFailures;
243
+ let observedOutcome;
244
+ let persistentCleanup;
245
+ let persistentCleanupLength = -1;
246
+ const epochCleanup = [];
247
+ const createdExt = app["~ext"] === void 0;
248
+ const ext = app["~ext"] ??= require_utils.nullObject();
249
+ const epoch = {
250
+ setup: false,
251
+ invoking: false
252
+ };
253
+ const snapshotCleanup = () => {
254
+ if (persistentCleanupLength !== -1) return;
255
+ persistentCleanup = ext.cleanup;
256
+ persistentCleanupLength = persistentCleanup?.length ?? 0;
257
+ };
258
+ const registerCleanup = (handler) => {
259
+ if (ext.cleanupEpoch !== registerCleanup) return false;
260
+ if (!epoch.setup) throw new Error("[Elysia] .cleanup() called after its setup epoch settled");
261
+ if (Array.isArray(handler)) epochCleanup.push(...handler);
262
+ else epochCleanup.push(handler);
263
+ return true;
264
+ };
265
+ const gate = () => {
266
+ if (!published) return;
267
+ live = void 0;
268
+ if (wsLifecycle) wsLifecycle.closing = true;
148
269
  try {
149
- server.reload(serve);
270
+ server.reload({
271
+ ...serve,
272
+ fetch: unavailableFetch,
273
+ error: unavailableFetch,
274
+ routes: {}
275
+ });
150
276
  } catch (error) {
151
- if (!serve.routes) throw error;
152
- delete serve.routes;
153
- console.warn("[Elysia] Native static promotion was skipped:", error);
154
- try {
155
- server.reload(serve);
156
- } catch (fallbackError) {
157
- console.error("[Elysia] Failed to reload Bun server:", fallbackError);
158
- throw fallbackError;
277
+ return { error };
278
+ }
279
+ };
280
+ const nativeStop = async (closeActiveConnections, errors) => {
281
+ try {
282
+ await server.stop(closeActiveConnections);
283
+ nativeStopped = true;
284
+ if (closeActiveConnections) {
285
+ forceDone = true;
286
+ forceRequested = false;
287
+ }
288
+ return true;
289
+ } catch (error) {
290
+ if (closeActiveConnections) forceRequested = true;
291
+ errors.push(error);
292
+ return false;
293
+ }
294
+ };
295
+ const isAbandoned = () => abandoned;
296
+ const quiesce = async (force) => {
297
+ const errors = [];
298
+ if (!published) return {
299
+ errors,
300
+ releasable: await nativeStop(true, errors),
301
+ safe: true
302
+ };
303
+ if (force && !idleRequired && !wsLifecycle?.closing) {
304
+ const stopped = await nativeStop(true, errors);
305
+ return {
306
+ errors,
307
+ releasable: stopped,
308
+ safe: stopped
309
+ };
310
+ }
311
+ const gateFailure = gate();
312
+ if (gateFailure) errors.push(gateFailure.error);
313
+ let socketsSettled = await settleServerWebSockets(wsLifecycle, errors);
314
+ await Promise.resolve();
315
+ let close = forceRequested || gateFailure !== void 0 || !socketsSettled;
316
+ if (!close && nativeStopped) await waitForServerRequests(server, isAbandoned);
317
+ idleRequired = true;
318
+ let stopped = true;
319
+ while (!nativeStopped || forceRequested && !forceDone) {
320
+ if (nativeStopped) close = true;
321
+ stopped = await nativeStop(close, errors);
322
+ if (stopped) {
323
+ if (socketsSettled) socketsSettled = await settleServerWebSockets(wsLifecycle, errors);
324
+ continue;
159
325
  }
326
+ if (close) break;
327
+ await waitForServerRequests(server, isAbandoned);
328
+ close = true;
160
329
  }
330
+ let idleClosed = true;
331
+ if (idleRequired) {
332
+ idleClosed = closeServerIdle(server, errors);
333
+ if (idleClosed && !gateFailure) idleRequired = false;
334
+ }
335
+ const safe = socketsSettled && stopped && idleClosed && (!gateFailure || forceDone);
336
+ return {
337
+ errors,
338
+ releasable: safe,
339
+ safe
340
+ };
161
341
  };
162
342
  const setup = () => {
163
- const onSetup = app["~ext"]?.setup;
343
+ snapshotCleanup();
344
+ const onSetup = ext.setup;
164
345
  if (!onSetup) return;
165
- let pendingSetups;
346
+ epoch.setup = true;
347
+ ext.cleanupEpoch = registerCleanup;
166
348
  for (let i = 0; i < onSetup.length; i++) {
167
- const result = onSetup[i](app);
168
- if (result && typeof result.then === "function") (pendingSetups ??= []).push(result);
349
+ if (cancelled) break;
350
+ try {
351
+ const result = runLifecycle(epoch, onSetup[i], app);
352
+ if (result && typeof result.then === "function") (pendingSetups ??= []).push(Promise.resolve(result));
353
+ } catch (error) {
354
+ if (!pendingSetups) epoch.setup = false;
355
+ stop(true, { error }).catch(() => {});
356
+ throw error;
357
+ }
169
358
  }
170
- if (pendingSetups) return Promise.all(pendingSetups);
359
+ if (pendingSetups) return Promise.all(pendingSetups).then(() => epoch.setup = false);
360
+ epoch.setup = false;
171
361
  };
172
- const rollback = (error) => {
173
- if (app.server !== server) return;
174
- try {
175
- server.stop(true);
176
- } catch (stopError) {
177
- console.error(stopError);
178
- } finally {
179
- app.server = void 0;
362
+ const stop = (closeActiveConnections, failure) => {
363
+ const reentrant = epoch.invoking;
364
+ if (failure) startupFailure ??= failure;
365
+ if (closeActiveConnections === true && !forceDone) forceRequested = true;
366
+ cancelled = true;
367
+ clearAppServer(app, server);
368
+ let outcome;
369
+ if (shutdownAttempt) {
370
+ if (closeActiveConnections === true && !forceDone) {
371
+ abandoned = true;
372
+ if (wsLifecycle) wsLifecycle.abandon = true;
373
+ }
374
+ outcome = shutdownAttempt;
375
+ } else {
376
+ const { promise, resolve, reject } = Promise.withResolvers();
377
+ outcome = shutdownAttempt = promise;
378
+ const quiescence = quiesce(forceRequested || !published);
379
+ let releasable = false;
380
+ (async () => {
381
+ try {
382
+ await Promise.resolve();
383
+ if (modulesReady) try {
384
+ await modulesReady;
385
+ } catch (error) {
386
+ startupFailure ??= { error };
387
+ }
388
+ if (pendingSetups) {
389
+ const setupResults = await Promise.allSettled(pendingSetups);
390
+ if (!startupFailure) for (let i = 0; i < setupResults.length; i++) {
391
+ const result = setupResults[i];
392
+ if (result.status === "rejected") {
393
+ startupFailure = { error: result.reason };
394
+ break;
395
+ }
396
+ }
397
+ }
398
+ epoch.setup = false;
399
+ const errors = [];
400
+ const quiesced = await quiescence;
401
+ if (startupFailure) errors.push(startupFailure.error);
402
+ errors.push(...quiesced.errors);
403
+ releasable = quiesced.releasable;
404
+ if (!quiesced.safe) {
405
+ if (cleanupFailures) errors.push(...cleanupFailures);
406
+ require_utils.throwLifecycleErrors(errors);
407
+ }
408
+ if (!cleanupCompleted) {
409
+ snapshotCleanup();
410
+ if (ext.stop === stop) {
411
+ const length = persistentCleanupLength + epochCleanup.length;
412
+ for (let n = 0; n < length; n++) {
413
+ if (ext.stop !== stop) break;
414
+ const i = startupFailure ? length - 1 - n : n;
415
+ const handler = i < persistentCleanupLength ? persistentCleanup[i] : epochCleanup[i - persistentCleanupLength];
416
+ try {
417
+ await runLifecycle(epoch, handler, app);
418
+ } catch (error) {
419
+ (cleanupFailures ??= []).push(error);
420
+ }
421
+ }
422
+ }
423
+ cleanupCompleted = true;
424
+ epochCleanup.length = 0;
425
+ }
426
+ if (cleanupFailures) errors.push(...cleanupFailures);
427
+ if (releasable) releaseLifecycle(app, ext, createdExt, stop, registerCleanup);
428
+ require_utils.throwLifecycleErrors(errors);
429
+ } finally {
430
+ epoch.setup = false;
431
+ if (!releasable) shutdownAttempt = void 0;
432
+ }
433
+ })().then(resolve, reject);
180
434
  }
181
- const cleanup = app["~ext"]?.cleanup;
182
- if (cleanup) for (let i = cleanup.length - 1; i >= 0; i--) try {
183
- const result = cleanup[i](app);
184
- if (result && typeof result.then === "function") Promise.resolve(result).catch(console.error);
185
- } catch (cleanupError) {
186
- console.error(cleanupError);
435
+ if (!published) startupShutdown ??= outcome;
436
+ if (!reentrant) return outcome;
437
+ if (observedOutcome !== outcome) {
438
+ observedOutcome = outcome;
439
+ outcome.catch((error) => {
440
+ console.error("[Elysia] stop() failed:", error);
441
+ });
187
442
  }
188
- return error;
443
+ return Promise.resolve();
189
444
  };
445
+ ext.stop = stop;
190
446
  const publish = () => {
191
- if (app.server !== server) return;
447
+ if (cancelled || app.server !== server) return;
192
448
  built ??= build();
193
449
  live = serve.fetch = withOrigin(built.fetch);
450
+ published = true;
194
451
  if (built.websocket) serve.websocket = built.websocket;
195
- if (built.routes) serve.routes = built.routes[0];
196
- reload();
452
+ if (built.routes) serve.routes = built.routes;
453
+ reloadServer(server, serve);
197
454
  if (callback) callback(server);
198
455
  };
199
456
  const start = () => {
200
- if (app.server !== server) return;
457
+ modulesReady = void 0;
458
+ if (cancelled || app.server !== server) return;
201
459
  const setupReady = setup();
202
460
  if (setupReady && typeof setupReady.then === "function") return Promise.resolve(setupReady).then(publish);
203
461
  publish();
204
462
  };
205
463
  try {
206
- if (app.pending) ready = app.modules.then(start);
207
- else ready = Promise.resolve().then(start);
464
+ ready = (modulesReady = app.modules).then(start);
465
+ ready = ready.catch((error) => stop(true, { error }));
208
466
  ready.catch((error) => {
209
467
  console.error("[Elysia] listen() failed:", error);
210
- return rollback(error);
211
468
  });
212
469
  } catch (error) {
213
- rollback(error);
470
+ stop(true, { error }).catch(console.error);
214
471
  throw error;
215
472
  }
216
473
  }