elysia 2.0.0-beta.2 → 2.0.0-beta.4

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 (175) hide show
  1. package/dist/adapter/bun/index.d.ts +1 -1
  2. package/dist/adapter/bun/index.js +320 -56
  3. package/dist/adapter/bun/index.mjs +321 -57
  4. package/dist/adapter/utils.js +51 -30
  5. package/dist/adapter/utils.mjs +52 -31
  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 +213 -101
  10. package/dist/base.mjs +215 -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 +4 -2
  57. package/dist/handler/utils.mjs +5 -3
  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 +1 -1
  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 +1 -1
  83. package/dist/type/coerce-plan.js +3 -4
  84. package/dist/type/coerce-plan.mjs +1 -1
  85. package/dist/type/coerce.d.ts +1 -1
  86. package/dist/type/compat.d.ts +3 -0
  87. package/dist/type/compat.js +32 -14
  88. package/dist/type/compat.mjs +27 -8
  89. package/dist/type/constants.d.ts +1 -1
  90. package/dist/type/elysia/array-buffer.js +2 -3
  91. package/dist/type/elysia/array-buffer.mjs +1 -1
  92. package/dist/type/elysia/array-string.js +7 -4
  93. package/dist/type/elysia/array-string.mjs +9 -5
  94. package/dist/type/elysia/boolean-string.js +2 -3
  95. package/dist/type/elysia/boolean-string.mjs +1 -1
  96. package/dist/type/elysia/boolean.js +4 -3
  97. package/dist/type/elysia/boolean.mjs +4 -2
  98. package/dist/type/elysia/cookie.js +2 -1
  99. package/dist/type/elysia/cookie.mjs +2 -1
  100. package/dist/type/elysia/date.js +7 -7
  101. package/dist/type/elysia/date.mjs +3 -2
  102. package/dist/type/elysia/file-type.d.ts +9 -2
  103. package/dist/type/elysia/file-type.js +16 -1
  104. package/dist/type/elysia/file-type.mjs +16 -2
  105. package/dist/type/elysia/file.js +8 -4
  106. package/dist/type/elysia/file.mjs +8 -3
  107. package/dist/type/elysia/files.js +6 -4
  108. package/dist/type/elysia/files.mjs +5 -2
  109. package/dist/type/elysia/form.js +2 -3
  110. package/dist/type/elysia/form.mjs +3 -3
  111. package/dist/type/elysia/integer-string.js +4 -5
  112. package/dist/type/elysia/integer-string.mjs +3 -3
  113. package/dist/type/elysia/integer.js +4 -3
  114. package/dist/type/elysia/integer.mjs +4 -2
  115. package/dist/type/elysia/maybe-empty.js +3 -4
  116. package/dist/type/elysia/maybe-empty.mjs +1 -1
  117. package/dist/type/elysia/nullable.js +2 -3
  118. package/dist/type/elysia/nullable.mjs +1 -1
  119. package/dist/type/elysia/number.js +4 -3
  120. package/dist/type/elysia/number.mjs +4 -2
  121. package/dist/type/elysia/numeric-enum.js +2 -3
  122. package/dist/type/elysia/numeric-enum.mjs +1 -1
  123. package/dist/type/elysia/numeric.js +5 -5
  124. package/dist/type/elysia/numeric.mjs +3 -2
  125. package/dist/type/elysia/object-string.js +7 -4
  126. package/dist/type/elysia/object-string.mjs +9 -5
  127. package/dist/type/elysia/string.js +4 -3
  128. package/dist/type/elysia/string.mjs +4 -2
  129. package/dist/type/elysia/uint8-array.js +2 -3
  130. package/dist/type/elysia/uint8-array.mjs +1 -1
  131. package/dist/type/elysia/union-enum.js +2 -3
  132. package/dist/type/elysia/union-enum.mjs +1 -1
  133. package/dist/type/elysia/utils.js +2 -3
  134. package/dist/type/elysia/utils.mjs +1 -1
  135. package/dist/type/exports.js +10 -1
  136. package/dist/type/exports.mjs +7 -0
  137. package/dist/type/index.d.ts +9 -1
  138. package/dist/type/index.js +41 -13
  139. package/dist/type/index.mjs +44 -9
  140. package/dist/type/typebox-type-live.d.ts +9 -0
  141. package/dist/type/typebox-type-live.js +31 -0
  142. package/dist/type/typebox-type-live.mjs +16 -0
  143. package/dist/type/typebox-type.d.ts +24 -0
  144. package/dist/type/typebox-type.js +130 -0
  145. package/dist/type/typebox-type.mjs +66 -0
  146. package/dist/type/typebox-value-live.d.ts +9 -0
  147. package/dist/type/typebox-value-live.js +27 -0
  148. package/dist/type/typebox-value-live.mjs +11 -0
  149. package/dist/type/typebox-value.d.ts +30 -0
  150. package/dist/type/typebox-value.js +147 -0
  151. package/dist/type/typebox-value.mjs +62 -0
  152. package/dist/type/validator/custom-error.js +4 -5
  153. package/dist/type/validator/custom-error.mjs +3 -3
  154. package/dist/type/validator/default-precompute.js +4 -5
  155. package/dist/type/validator/default-precompute.mjs +1 -1
  156. package/dist/type/validator/index.d.ts +1 -1
  157. package/dist/type/validator/index.js +51 -42
  158. package/dist/type/validator/index.mjs +33 -23
  159. package/dist/type/validator/validator-cache.d.ts +1 -1
  160. package/dist/type/validator/validator-cache.js +27 -14
  161. package/dist/type/validator/validator-cache.mjs +27 -13
  162. package/dist/universal/constants.d.ts +2 -1
  163. package/dist/universal/constants.js +3 -1
  164. package/dist/universal/constants.mjs +2 -1
  165. package/dist/utils.d.ts +19 -1
  166. package/dist/utils.js +25 -3
  167. package/dist/utils.mjs +19 -3
  168. package/dist/validator/index.js +2 -1
  169. package/dist/validator/index.mjs +2 -1
  170. package/dist/ws/context.d.ts +8 -1
  171. package/dist/ws/context.js +65 -29
  172. package/dist/ws/context.mjs +64 -29
  173. package/dist/ws/route.js +176 -28
  174. package/dist/ws/route.mjs +179 -31
  175. package/package.json +5 -3
package/dist/ws/route.mjs CHANGED
@@ -1,18 +1,19 @@
1
1
  import { isBun } from "../universal/constants.mjs";
2
- import { deriveEntryFn, isNotEmpty, nullObject } from "../utils.mjs";
2
+ import { assignOwn, deriveEntryFn, isNotEmpty, isSocketQuiet, nullObject } from "../utils.mjs";
3
3
  import { isBridgeLive } from "../type/bridge.mjs";
4
- import { isProduction } from "../universal/is-production.mjs";
5
4
  import { ElysiaError, ElysiaStatus, ValidationError, internalServerErrorBodyString, problemBody, problemResponse } from "../error.mjs";
6
5
  import { mapResponse } from "../adapter/web-standard/handler.mjs";
7
6
  import { parseQueryFromURL } from "../parse-query.mjs";
8
7
  import { frozenRootOf } from "../generation.mjs";
9
- import { createErrorHandler } from "../handler/error.mjs";
8
+ import { compileCookieConfig } from "../cookie/config.mjs";
9
+ import { buildCookieJar, parseCookieRaw } from "../cookie/utils.mjs";
10
+ import { adoptErrorType, claimsProblemType, createErrorHandler, readAnnotation, resolveStatus, statusFallbackBody } from "../handler/error.mjs";
10
11
  import { deriveModes, getQueryParseChannels, replaceDeriveContext } from "../compile/handler/utils.mjs";
11
12
  import { StandardValidator } from "../validator/index.mjs";
12
13
  import { RouteValidator } from "../validator/route.mjs";
13
14
  import { buildFrozenRouteValidator, isBridgeNotInitialized } from "../compile/handler/frozen-validator.mjs";
14
15
  import { composeRouteHook, localMacroRoot, resolveWSLocalHook } from "../compile/handler/index.mjs";
15
- import { ElysiaWS, isGeneratorObject } from "./context.mjs";
16
+ import { ElysiaWS, isGeneratorObject, trackWSSettling } from "./context.mjs";
16
17
  import { createMessageParser } from "./parser.mjs";
17
18
 
18
19
  //#region src/ws/route.ts
@@ -180,9 +181,45 @@ function wsErrorFrame(error) {
180
181
  }
181
182
  return wsErrorFrameFallback(error);
182
183
  }
184
+ /**
185
+ * Frame served by an error that claims an RFC 9457 problem document, mirroring
186
+ * the HTTP tiers in `handler/error.ts`: `value` replaces the whole frame,
187
+ * `detail` fills the `detail` member, the message is the last resort.
188
+ *
189
+ * A frame carries no headers, so a `headers` annotation is ignored outright
190
+ * rather than half-applied
191
+ */
192
+ function wsProblemFrame(error) {
193
+ const status = resolveStatus(error.status);
194
+ const served = typeof status === "number" && status >= 100 ? status : 500;
195
+ const stringify = (value) => typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
196
+ const problemFrame = (detail) => JSON.stringify(problemBody({
197
+ type: error.type ?? "about:blank",
198
+ detail,
199
+ status: served
200
+ }));
201
+ const serveMessage = () => problemFrame(statusFallbackBody(error, served));
202
+ const serveDetail = () => {
203
+ const detail = readAnnotation(error, "detail", true);
204
+ if (detail === void 0) return serveMessage();
205
+ if (detail instanceof Promise) return detail.then((resolved) => resolved === void 0 ? serveMessage() : problemFrame(resolved)).catch(() => wsLegacyFrame(error));
206
+ return problemFrame(detail);
207
+ };
208
+ const value = readAnnotation(error, "value", true);
209
+ if (value === void 0) return serveDetail();
210
+ if (value instanceof Promise) return value.then((resolved) => resolved === void 0 ? serveDetail() : stringify(resolved)).catch(() => wsLegacyFrame(error));
211
+ return stringify(value);
212
+ }
183
213
  function wsErrorFrameFallback(error) {
214
+ if (claimsProblemType(error)) try {
215
+ return wsProblemFrame(error);
216
+ } catch {}
217
+ return wsLegacyFrame(error);
218
+ }
219
+ /** Frame an error that never self-described has always served */
220
+ function wsLegacyFrame(error) {
184
221
  if (error?.status) {
185
- const body = error.response !== void 0 ? error.response : isProduction() ? error.status >= 500 ? "Internal Server Error" : "" : error.message ?? "";
222
+ const body = statusFallbackBody(error, error.status);
186
223
  return typeof body === "object" ? JSON.stringify(body) : String(body);
187
224
  }
188
225
  return internalServerErrorBodyString(error);
@@ -217,13 +254,20 @@ const wsOptions = [
217
254
  ];
218
255
  function buildWSRoute(route, app) {
219
256
  const hook = resolveWSLocalHook(localMacroRoot(route[7] ?? route[3] ?? app, app), route[4], app) ?? nullObject();
257
+ const instance = route[3] ?? app;
258
+ const appHookChain = route[5];
259
+ const inheritedChain = route[6];
260
+ const composed = composeRouteHook(instance, route[4], appHookChain, inheritedChain, app, route[7]) ?? hook;
220
261
  let validators;
221
- const frozenEager = isBridgeLive() ? void 0 : buildFrozenRouteValidator(hook, app, "WS", route[1]);
262
+ const frozenEager = isBridgeLive() ? void 0 : buildFrozenRouteValidator(composed, app, "WS", route[1]);
222
263
  if (frozenEager) validators = frozenEager;
223
264
  else try {
224
- validators = new RouteValidator(hook, {
265
+ validators = new RouteValidator(composed, {
225
266
  models: frozenRootOf(app)["~ext"]?.models,
226
267
  app,
268
+ normalize: frozenRootOf(app)["~config"]?.normalize,
269
+ sanitize: frozenRootOf(app)["~config"]?.sanitize,
270
+ schemas: composed.schemas,
227
271
  aot: {
228
272
  method: "WS",
229
273
  path: route[1]
@@ -232,18 +276,17 @@ function buildWSRoute(route, app) {
232
276
  });
233
277
  } catch (error) {
234
278
  if (!isBridgeNotInitialized(error)) throw error;
235
- const frozen = buildFrozenRouteValidator(hook, app, "WS", route[1]);
279
+ const frozen = buildFrozenRouteValidator(composed, app, "WS", route[1]);
236
280
  if (!frozen) throw error;
237
281
  validators = frozen;
238
282
  }
239
283
  const responseValidator = validators.response;
240
284
  const defaultResponseValidator = responseValidator ? responseValidator[200] ?? responseValidator[Object.keys(responseValidator)[0]] : void 0;
285
+ const cookieConfig = validators.cookie ? compileCookieConfig(composed.cookie, frozenRootOf(app)["~config"]?.cookie) : void 0;
286
+ const cookieIsOptional = !!composed.cookie?.["~optional"];
241
287
  const queryChannels = getQueryParseChannels(validators.query?.schema);
242
288
  const queryArray = queryChannels?.array;
243
289
  const queryObject = queryChannels?.object;
244
- const instance = route[3] ?? app;
245
- const appHookChain = route[5];
246
- const inheritedChain = route[6];
247
290
  const flatAppHook = composeRouteHook(instance, void 0, appHookChain, inheritedChain, app, route[7]) ?? {};
248
291
  const parseHooks = hook.parse == null ? [] : Array.isArray(hook.parse) ? hook.parse : [hook.parse];
249
292
  const transforms = concatHooks(flatAppHook.transform, hook.transform);
@@ -271,6 +314,7 @@ function buildWSRoute(route, app) {
271
314
  break;
272
315
  }
273
316
  if (r !== void 0) {
317
+ r = adoptErrorType(r, error);
274
318
  try {
275
319
  await handleWSResponse(ws, r, mapResponses);
276
320
  } catch {}
@@ -418,6 +462,15 @@ function buildWSRoute(route, app) {
418
462
  if (r instanceof Promise) r = await r;
419
463
  context.headers = r;
420
464
  }
465
+ if (cookieConfig) {
466
+ const raw = await parseCookieRaw(request.headers.get("cookie"), cookieConfig);
467
+ let r = raw;
468
+ if (!cookieIsOptional || Object.keys(raw).length) {
469
+ r = validateUpgradeChannel(validators.cookie, raw, "cookie");
470
+ if (r instanceof Promise) r = await r;
471
+ }
472
+ context.cookie = buildCookieJar(context.set, r, cookieConfig);
473
+ }
421
474
  for (let i = 0; i < transforms.length; i++) {
422
475
  const r = transforms[i](context);
423
476
  if (r instanceof Promise) await r;
@@ -429,7 +482,7 @@ function buildWSRoute(route, app) {
429
482
  const deriveMode = upgradeDeriveModes?.[i];
430
483
  if (deriveMode !== void 0 && !(r instanceof ElysiaStatus)) {
431
484
  if (r && typeof r === "object") if (deriveMode) context = replaceDeriveContext(context, r);
432
- else Object.assign(context, r);
485
+ else assignOwn(context, r);
433
486
  } else if (r !== void 0) {
434
487
  if (r instanceof Response) return r;
435
488
  return mapResponse(r, context.set, context.request);
@@ -484,23 +537,40 @@ function resolveWSOptions(entries) {
484
537
  const incoming = entry.value[key];
485
538
  if (key in result && result[key] !== incoming && !warned?.has(key)) {
486
539
  (warned ??= /* @__PURE__ */ new Set()).add(key);
487
- console.warn(`[Elysia] Conflicting WebSocket option '${key}' across .use(websocket()) registrations; the shallowest (nearest-root) registration wins.`);
540
+ console.warn(`[Elysia] Conflicting WebSocket option '${key}' across .use(websocket()). Using nearest-root registration.`);
488
541
  }
489
542
  result[key] = incoming;
490
543
  }
491
544
  return result;
492
545
  }
546
+ const wsLimits = [
547
+ "maxPayloadLength",
548
+ "backpressureLimit",
549
+ "idleTimeout"
550
+ ];
551
+ const routeOwnedKeys = /* @__PURE__ */ new WeakMap();
493
552
  function accumulateWSOptions(target, routeOptions, _path) {
494
553
  if (!isNotEmpty(routeOptions)) return;
495
- if (isBun) {
496
- for (const key in routeOptions) if (key in target && target[key] !== routeOptions[key]) {
497
- console.warn(`[Elysia] Conflicting per-route WebSocket option '${key}'\nBun uses one global WebSocket config per server, per-route values are not enforced (the last-registered route wins).`);
498
- console.warn((/* @__PURE__ */ new Error()).stack);
554
+ let owned = routeOwnedKeys.get(target);
555
+ if (!owned) routeOwnedKeys.set(target, owned = /* @__PURE__ */ new Set());
556
+ for (const key in routeOptions) {
557
+ const incoming = routeOptions[key];
558
+ const current = target[key];
559
+ if (key in target && current !== incoming) {
560
+ if (isBun) {
561
+ console.warn(`[Elysia] Conflicting per-route WebSocket option '${key}'\nBun uses one global WebSocket config per server, per-route values are not enforced (for limits the strictest route wins, otherwise the last-registered route).`);
562
+ console.warn((/* @__PURE__ */ new Error()).stack);
563
+ }
564
+ if (owned.has(key) && typeof current === "number" && typeof incoming === "number" && current < incoming && wsLimits.includes(key)) continue;
499
565
  }
566
+ owned.add(key);
567
+ target[key] = incoming;
500
568
  }
501
- Object.assign(target, routeOptions);
502
569
  }
570
+ const MAX_INFLIGHT_MESSAGES = 256;
503
571
  function buildGlobalWSHandler() {
572
+ let lifecycle;
573
+ const runLifecycle = (callback, ...args) => lifecycle ? lifecycle.run(callback, ...args) : callback(...args);
504
574
  function getElysia(ws) {
505
575
  let elysia = ws.data.elysia;
506
576
  if (!elysia) {
@@ -515,39 +585,117 @@ function buildGlobalWSHandler() {
515
585
  ws.send(typeof error?.message === "string" ? error.message : "Internal Server Error");
516
586
  } catch {}
517
587
  };
518
- return {
588
+ const releaseLifecycle = (ws) => {
589
+ if (!lifecycle?.closing && isSocketQuiet(ws)) {
590
+ delete ws.data["~lifecycleRun"];
591
+ lifecycle?.sockets.delete(ws);
592
+ }
593
+ };
594
+ const release = (ws) => {
595
+ const data = ws.data;
596
+ const inflight = data.inflight;
597
+ if (inflight) {
598
+ data.inflight = inflight - 1;
599
+ if (inflight === 1 && data.closeHandlerInvoked) releaseLifecycle(ws);
600
+ }
601
+ };
602
+ function dispatch(ws, message) {
603
+ let result;
604
+ try {
605
+ result = ws.data.message(getElysia(ws), message);
606
+ } catch (error) {
607
+ release(ws);
608
+ sendErrMsg(ws, error);
609
+ return;
610
+ }
611
+ if (result instanceof Promise) result.then(() => release(ws), (error) => {
612
+ release(ws);
613
+ sendErrMsg(ws, error);
614
+ });
615
+ else release(ws);
616
+ }
617
+ const handler = {
519
618
  message(ws, message) {
520
- let result;
521
- try {
522
- result = ws.data.message?.(getElysia(ws), message);
523
- } catch (error) {
524
- sendErrMsg(ws, error);
619
+ if (lifecycle?.closing) return;
620
+ const data = ws.data;
621
+ if (!data.message) return;
622
+ const inflight = (data.inflight ?? 0) + 1;
623
+ if (inflight > MAX_INFLIGHT_MESSAGES) {
624
+ try {
625
+ ws.close(1013, "Too many in-flight messages");
626
+ } catch {}
525
627
  return;
526
628
  }
527
- if (result instanceof Promise) result.catch((error) => sendErrMsg(ws, error));
629
+ data.inflight = inflight;
630
+ const opening = data.opening;
631
+ if (opening) return void opening.then(() => {
632
+ if (lifecycle?.closing || ws.readyState > 1) return release(ws);
633
+ dispatch(ws, message);
634
+ });
635
+ dispatch(ws, message);
528
636
  },
529
637
  open(ws) {
530
- ws.data.open?.(getElysia(ws));
638
+ if (lifecycle) Object.defineProperty(ws.data, "~lifecycleRun", {
639
+ configurable: true,
640
+ value: lifecycle.run
641
+ });
642
+ lifecycle?.sockets.add(ws);
643
+ if (lifecycle?.closing) {
644
+ ws.data.closeHandlerInvoked = true;
645
+ try {
646
+ ws.terminate();
647
+ } catch {}
648
+ return;
649
+ }
650
+ const open = ws.data.open;
651
+ const result = open && runLifecycle(open, getElysia(ws));
652
+ if (result instanceof Promise) {
653
+ const clear = () => {
654
+ ws.data.opening = void 0;
655
+ releaseLifecycle(ws);
656
+ };
657
+ ws.data.opening = result.then(clear, clear);
658
+ }
531
659
  },
532
660
  drain(ws) {
661
+ if (lifecycle?.closing) return;
533
662
  const elyWs = getElysia(ws);
534
663
  drainWaiters(elyWs);
535
- ws.data.drain?.(elyWs);
664
+ const drain = ws.data.drain;
665
+ trackWSSettling(ws.data, drain && runLifecycle(drain, elyWs), () => releaseLifecycle(ws));
536
666
  },
537
667
  close(ws, code, reason) {
538
668
  const elyWs = getElysia(ws);
539
669
  drainWaiters(elyWs);
540
- if (ws.data.closeHandlerInvoked) return;
670
+ if (ws.data.closeHandlerInvoked) return releaseLifecycle(ws);
541
671
  ws.data.closeHandlerInvoked = true;
542
- ws.data.close?.(elyWs, code, reason);
672
+ let result;
673
+ try {
674
+ const close = ws.data.close;
675
+ result = close && runLifecycle(close, elyWs, code, reason);
676
+ } finally {
677
+ if (!(result instanceof Promise)) releaseLifecycle(ws);
678
+ }
679
+ if (result instanceof Promise) {
680
+ const closing = result.catch(() => {});
681
+ trackWSSettling(ws.data, closing, () => releaseLifecycle(ws));
682
+ }
543
683
  },
544
684
  ping(ws, data) {
545
- ws.data.ping?.(getElysia(ws), data);
685
+ if (lifecycle?.closing) return;
686
+ const ping = ws.data.ping;
687
+ trackWSSettling(ws.data, ping && runLifecycle(ping, getElysia(ws), data), () => releaseLifecycle(ws));
546
688
  },
547
689
  pong(ws, data) {
548
- ws.data.pong?.(getElysia(ws), data);
690
+ if (lifecycle?.closing) return;
691
+ const pong = ws.data.pong;
692
+ trackWSSettling(ws.data, pong && runLifecycle(pong, getElysia(ws), data), () => releaseLifecycle(ws));
549
693
  }
550
694
  };
695
+ Object.defineProperty(handler, "~lifecycle", { set(value) {
696
+ lifecycle = value;
697
+ } });
698
+ return handler;
551
699
  }
552
700
 
553
701
  //#endregion
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-beta.2",
4
+ "version": "2.0.0-beta.4",
5
5
  "author": {
6
6
  "name": "saltyAom",
7
7
  "url": "https://github.com/SaltyAom",
@@ -238,11 +238,13 @@
238
238
  "./dist/type/exports.mjs",
239
239
  "./dist/type/exports.js",
240
240
  "./dist/type/bridge-live.mjs",
241
- "./dist/type/bridge-live.js"
241
+ "./dist/type/bridge-live.js",
242
+ "./dist/type/typebox-value-live.mjs",
243
+ "./dist/type/typebox-value-live.js"
242
244
  ],
243
245
  "dependencies": {
244
246
  "deuri": "^3.0.0",
245
- "memoirist": "1.2.1"
247
+ "memoirist": "1.2.2"
246
248
  },
247
249
  "devDependencies": {
248
250
  "@eslint/eslintrc": "^3.3.5",