elysia 2.0.0-beta.3 → 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.
- package/dist/adapter/bun/index.d.ts +1 -1
- package/dist/adapter/bun/index.js +320 -56
- package/dist/adapter/bun/index.mjs +321 -57
- package/dist/adapter/utils.js +48 -27
- package/dist/adapter/utils.mjs +48 -27
- package/dist/base.d.ts +16 -5
- package/dist/base.js +171 -74
- package/dist/base.mjs +172 -75
- package/dist/compile/aot-capture.js +1 -1
- package/dist/compile/aot-capture.mjs +1 -1
- package/dist/compile/aot.d.ts +1 -0
- package/dist/compile/aot.js +3 -0
- package/dist/compile/aot.mjs +3 -0
- package/dist/compile/handler/frozen-validator.d.ts +4 -1
- package/dist/compile/handler/frozen-validator.js +8 -3
- package/dist/compile/handler/frozen-validator.mjs +5 -3
- package/dist/compile/handler/index.d.ts +1 -1
- package/dist/compile/handler/index.js +3 -3
- package/dist/compile/handler/index.mjs +3 -3
- package/dist/compile/handler/reconstruct.d.ts +1 -1
- package/dist/compile/handler/reconstruct.js +4 -3
- package/dist/compile/handler/reconstruct.mjs +4 -3
- package/dist/compile/jit-probe.d.ts +2 -2
- package/dist/context.d.ts +1 -1
- package/dist/context.js +5 -1
- package/dist/context.mjs +5 -1
- package/dist/package.js +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugin/aot/core.d.ts +11 -5
- package/dist/plugin/aot/core.js +86 -38
- package/dist/plugin/aot/core.mjs +87 -41
- package/dist/plugin/aot/esbuild.js +8 -2
- package/dist/plugin/aot/esbuild.mjs +9 -3
- package/dist/plugin/aot/hooks.d.ts +2 -1
- package/dist/plugin/aot/hooks.js +3 -3
- package/dist/plugin/aot/hooks.mjs +4 -4
- package/dist/plugin/aot/source.d.ts +4 -1
- package/dist/plugin/aot/source.js +21 -14
- package/dist/plugin/aot/source.mjs +21 -14
- package/dist/plugin/aot/worker.js +2 -2
- package/dist/plugin/aot/worker.mjs +2 -2
- package/dist/route-table.d.ts +3 -0
- package/dist/route-table.js +4 -1
- package/dist/route-table.mjs +4 -1
- package/dist/schema-snapshot.js +17 -22
- package/dist/schema-snapshot.mjs +17 -22
- package/dist/type/bridge-live.js +1 -1
- package/dist/type/bridge-live.mjs +1 -1
- package/dist/type/coerce.d.ts +1 -1
- package/dist/type/constants.d.ts +1 -1
- package/dist/type/typebox-value-live.d.ts +2 -2
- package/dist/type/typebox-value-live.js +2 -2
- package/dist/type/typebox-value-live.mjs +2 -2
- package/dist/type/typebox-value.d.ts +6 -6
- package/dist/type/validator/index.d.ts +1 -1
- package/dist/type/validator/index.js +10 -7
- package/dist/type/validator/index.mjs +10 -7
- package/dist/type/validator/validator-cache.d.ts +1 -1
- package/dist/type/validator/validator-cache.js +17 -9
- package/dist/type/validator/validator-cache.mjs +17 -9
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +8 -1
- package/dist/utils.mjs +6 -1
- package/dist/ws/context.d.ts +4 -1
- package/dist/ws/context.js +21 -3
- package/dist/ws/context.mjs +20 -3
- package/dist/ws/route.js +57 -12
- package/dist/ws/route.mjs +59 -14
- package/package.json +2 -2
package/dist/adapter/utils.mjs
CHANGED
|
@@ -157,10 +157,12 @@ function createStreamHandler({ mapResponse, mapCompactResponse }) {
|
|
|
157
157
|
return new Response(generator, { headers: { "content-type": "application/octet-stream" } });
|
|
158
158
|
}
|
|
159
159
|
const typedSSE = !skipFormat && "sse" in generator && generator.sse === true;
|
|
160
|
+
const sourceIterator = typeof generator.next === "function" ? generator : void 0;
|
|
160
161
|
let init = typedSSE ? void 0 : generator.next?.();
|
|
161
162
|
if (set) handleSet(set);
|
|
162
163
|
if (init instanceof Promise) init = await init;
|
|
163
|
-
|
|
164
|
+
const yieldedStream = init?.value instanceof ReadableStream;
|
|
165
|
+
if (yieldedStream) generator = init.value;
|
|
164
166
|
else if (init && (typeof init?.done === "undefined" || init?.done)) {
|
|
165
167
|
if (set) return mapResponse(init.value, set, request, owned);
|
|
166
168
|
return mapCompactResponse(init.value, request, owned);
|
|
@@ -194,8 +196,32 @@ function createStreamHandler({ mapResponse, mapCompactResponse }) {
|
|
|
194
196
|
connection: "keep-alive"
|
|
195
197
|
}
|
|
196
198
|
};
|
|
197
|
-
const
|
|
199
|
+
const sourceStream = generator instanceof ReadableStream ? generator : void 0;
|
|
200
|
+
let streamReader;
|
|
201
|
+
const iterator = sourceStream ? {
|
|
202
|
+
next: () => (streamReader ??= sourceStream.getReader()).read(),
|
|
203
|
+
async return() {
|
|
204
|
+
if (!streamReader) {
|
|
205
|
+
await sourceStream.cancel();
|
|
206
|
+
return {
|
|
207
|
+
done: true,
|
|
208
|
+
value: void 0
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
await streamReader.cancel();
|
|
213
|
+
} finally {
|
|
214
|
+
streamReader.releaseLock();
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
done: true,
|
|
218
|
+
value: void 0
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
} : sourceIterator ?? generator[Symbol.asyncIterator]();
|
|
222
|
+
const outerIterator = yieldedStream && !init.done ? sourceIterator : void 0;
|
|
198
223
|
let end = false;
|
|
224
|
+
let finalizing;
|
|
199
225
|
const signal = request?.signal;
|
|
200
226
|
let onAbort;
|
|
201
227
|
const cleanupAbort = () => {
|
|
@@ -204,17 +230,21 @@ function createStreamHandler({ mapResponse, mapCompactResponse }) {
|
|
|
204
230
|
onAbort = void 0;
|
|
205
231
|
}
|
|
206
232
|
};
|
|
207
|
-
const safeReturn = () => {
|
|
233
|
+
const safeReturn = async (target) => {
|
|
208
234
|
try {
|
|
209
|
-
|
|
210
|
-
if (r && typeof r.then === "function") r.catch(() => {});
|
|
235
|
+
await target?.return?.();
|
|
211
236
|
} catch {}
|
|
212
237
|
};
|
|
213
|
-
const
|
|
238
|
+
const finalize = (mode, controller, error) => {
|
|
239
|
+
if (end) return finalizing;
|
|
240
|
+
end = true;
|
|
241
|
+
cleanupAbort();
|
|
242
|
+
finalizing = safeReturn(iterator).then(() => safeReturn(outerIterator));
|
|
243
|
+
if (!controller) return finalizing;
|
|
214
244
|
try {
|
|
215
|
-
controller.
|
|
245
|
+
if (mode === "error") controller.error(error);
|
|
246
|
+
else controller.close();
|
|
216
247
|
} catch {}
|
|
217
|
-
cleanupAbort();
|
|
218
248
|
};
|
|
219
249
|
const enqueueValue = async (controller, value) => {
|
|
220
250
|
if (value.toSSE) {
|
|
@@ -233,42 +263,33 @@ function createStreamHandler({ mapResponse, mapCompactResponse }) {
|
|
|
233
263
|
return new Response(new ReadableStream({
|
|
234
264
|
async start(controller) {
|
|
235
265
|
if (signal) {
|
|
236
|
-
onAbort = () =>
|
|
237
|
-
cleanupAbort();
|
|
238
|
-
end = true;
|
|
239
|
-
safeReturn();
|
|
240
|
-
try {
|
|
241
|
-
controller.close();
|
|
242
|
-
} catch {}
|
|
243
|
-
};
|
|
266
|
+
onAbort = () => finalize("close", controller);
|
|
244
267
|
if (signal.aborted) onAbort();
|
|
245
268
|
else signal.addEventListener("abort", onAbort, { once: true });
|
|
246
269
|
}
|
|
247
270
|
if (!init || init.value instanceof ReadableStream || init.value === void 0 || init.value === null) return;
|
|
248
|
-
|
|
271
|
+
try {
|
|
272
|
+
await enqueueValue(controller, init.value);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
finalize("error", controller, error);
|
|
275
|
+
}
|
|
249
276
|
},
|
|
250
277
|
async pull(controller) {
|
|
251
|
-
if (end)
|
|
252
|
-
closeSafely(controller);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
278
|
+
if (end) return;
|
|
255
279
|
try {
|
|
256
280
|
const { value: chunk, done } = await iterator.next();
|
|
257
281
|
if (done || end) {
|
|
258
|
-
|
|
282
|
+
finalize("close", controller);
|
|
259
283
|
return;
|
|
260
284
|
}
|
|
261
285
|
if (chunk === void 0 || chunk === null) return;
|
|
262
286
|
await enqueueValue(controller, chunk);
|
|
263
287
|
} catch (error) {
|
|
264
|
-
|
|
265
|
-
controller.error(error);
|
|
288
|
+
finalize("error", controller, error);
|
|
266
289
|
}
|
|
267
290
|
},
|
|
268
291
|
cancel() {
|
|
269
|
-
|
|
270
|
-
cleanupAbort();
|
|
271
|
-
safeReturn();
|
|
292
|
+
finalize("close");
|
|
272
293
|
}
|
|
273
294
|
}, typedSSE ? { highWaterMark: 0 } : void 0), set);
|
|
274
295
|
};
|
package/dist/base.d.ts
CHANGED
|
@@ -39,6 +39,10 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
|
|
|
39
39
|
hoc?: WrapFn<any>[];
|
|
40
40
|
setup?: GracefulHandler<any>[];
|
|
41
41
|
cleanup?: GracefulHandler<any>[];
|
|
42
|
+
cleanupEpoch?: (handler: GracefulHandler<any> | GracefulHandler<any>[]) => boolean;
|
|
43
|
+
stop?: (closeActiveConnections?: boolean, failure?: {
|
|
44
|
+
error: unknown;
|
|
45
|
+
}) => Promise<void>;
|
|
42
46
|
capability?: {
|
|
43
47
|
trace?: {
|
|
44
48
|
provider: TraceCapability;
|
|
@@ -900,12 +904,19 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
|
|
|
900
904
|
*/
|
|
901
905
|
cleanup(handler: MaybeArray<GracefulHandler<this>>): this;
|
|
902
906
|
/**
|
|
903
|
-
* Stop the underlying server (if any),
|
|
904
|
-
*
|
|
907
|
+
* Stop the underlying server (if any), then run every `cleanup` handler.
|
|
908
|
+
* Omitted and `false` are the same graceful stop: new requests are gated,
|
|
909
|
+
* tracked WebSockets are settled and active HTTP is drained, then cleanup
|
|
910
|
+
* runs and the epoch is released. `true` force-closes the transport
|
|
911
|
+
* instead of draining it, and escalates a graceful stop already in flight.
|
|
905
912
|
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
913
|
+
* Awaiting `stop()` from inside a `setup`, `cleanup` or WebSocket lifecycle
|
|
914
|
+
* callback is only supported while that callback is still synchronous; the
|
|
915
|
+
* teardown is waiting on the callback, so after an `await` it can only be
|
|
916
|
+
* issued as `void app.stop()`.
|
|
917
|
+
*
|
|
918
|
+
* @param closeActiveConnections Pass `true` to terminate active
|
|
919
|
+
* transports. Omit (or pass `false`) to drain safely.
|
|
909
920
|
*/
|
|
910
921
|
stop(closeActiveConnections?: boolean): Promise<void> | void;
|
|
911
922
|
}
|
package/dist/base.js
CHANGED
|
@@ -9,6 +9,7 @@ const require_generation = require('./generation.js');
|
|
|
9
9
|
const require_compile_handler_index = require('./compile/handler/index.js');
|
|
10
10
|
const require_route_table = require('./route-table.js');
|
|
11
11
|
const require_adapter_bun_index = require('./adapter/bun/index.js');
|
|
12
|
+
const require_context = require('./context.js');
|
|
12
13
|
const require_handler_fetch = require('./handler/fetch.js');
|
|
13
14
|
const require_compile_analysis_cache = require('./compile/analysis-cache.js');
|
|
14
15
|
const require_schema_snapshot = require('./schema-snapshot.js');
|
|
@@ -18,6 +19,23 @@ memoirist = require_runtime.__toESM(memoirist);
|
|
|
18
19
|
//#region src/base.ts
|
|
19
20
|
const useNodesBuffer = [];
|
|
20
21
|
const emptyHistory = Object.freeze([]);
|
|
22
|
+
const extCallbackIndexes = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
const mergeExtCallbacks = (target, incoming) => {
|
|
24
|
+
let index = extCallbackIndexes.get(target);
|
|
25
|
+
if (!index) {
|
|
26
|
+
index = {
|
|
27
|
+
indexedLength: target.length,
|
|
28
|
+
seen: new Set(target)
|
|
29
|
+
};
|
|
30
|
+
extCallbackIndexes.set(target, index);
|
|
31
|
+
} else for (let i = index.indexedLength; i < target.length; i++) index.seen.add(target[i]);
|
|
32
|
+
for (const fn of incoming) {
|
|
33
|
+
if (index.seen.has(fn)) continue;
|
|
34
|
+
target.push(fn);
|
|
35
|
+
index.seen.add(fn);
|
|
36
|
+
}
|
|
37
|
+
index.indexedLength = target.length;
|
|
38
|
+
};
|
|
21
39
|
const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
|
|
22
40
|
/**
|
|
23
41
|
* Every key a single route must answer to, in registration order.
|
|
@@ -755,27 +773,12 @@ var Elysia = class Elysia {
|
|
|
755
773
|
}
|
|
756
774
|
if (error) if (ext.error) for (const [code, handler] of error) ext.error.set(code, handler);
|
|
757
775
|
else ext.error = new Map(error);
|
|
758
|
-
if (hoc) if (ext.hoc)
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
} else ext.hoc = hoc.slice();
|
|
765
|
-
if (setup) if (ext.setup) {
|
|
766
|
-
const seen = new Set(ext.setup);
|
|
767
|
-
for (const fn of setup) if (!seen.has(fn)) {
|
|
768
|
-
seen.add(fn);
|
|
769
|
-
ext.setup.push(fn);
|
|
770
|
-
}
|
|
771
|
-
} else ext.setup = setup.slice();
|
|
772
|
-
if (cleanup) if (ext.cleanup) {
|
|
773
|
-
const seen = new Set(ext.cleanup);
|
|
774
|
-
for (const fn of cleanup) if (!seen.has(fn)) {
|
|
775
|
-
seen.add(fn);
|
|
776
|
-
ext.cleanup.push(fn);
|
|
777
|
-
}
|
|
778
|
-
} else ext.cleanup = cleanup.slice();
|
|
776
|
+
if (hoc) if (ext.hoc) mergeExtCallbacks(ext.hoc, hoc);
|
|
777
|
+
else ext.hoc = hoc.slice();
|
|
778
|
+
if (setup) if (ext.setup) mergeExtCallbacks(ext.setup, setup);
|
|
779
|
+
else ext.setup = setup.slice();
|
|
780
|
+
if (cleanup) if (ext.cleanup) mergeExtCallbacks(ext.cleanup, cleanup);
|
|
781
|
+
else ext.cleanup = cleanup.slice();
|
|
779
782
|
if (capability) {
|
|
780
783
|
const target = ext.capability ??= require_utils.nullObject();
|
|
781
784
|
if (capability.trace) {
|
|
@@ -954,11 +957,11 @@ var Elysia = class Elysia {
|
|
|
954
957
|
get modules() {
|
|
955
958
|
const ready = this.#ready;
|
|
956
959
|
if (!ready) {
|
|
957
|
-
if (this.#error !== void 0) return Promise.reject(this.#error);
|
|
960
|
+
if (this.#error !== void 0) return Promise.reject(this.#error.error);
|
|
958
961
|
return Promise.resolve();
|
|
959
962
|
}
|
|
960
963
|
return ready.then(() => {
|
|
961
|
-
if (this.#error !== void 0) throw this.#error;
|
|
964
|
+
if (this.#error !== void 0) throw this.#error.error;
|
|
962
965
|
if (this.#ready && this.#ready !== ready) return this.modules;
|
|
963
966
|
});
|
|
964
967
|
}
|
|
@@ -973,13 +976,13 @@ var Elysia = class Elysia {
|
|
|
973
976
|
if (plugin) try {
|
|
974
977
|
this.use(plugin);
|
|
975
978
|
} catch (err) {
|
|
976
|
-
this.#error ??= err;
|
|
979
|
+
this.#error ??= { error: err };
|
|
977
980
|
console.error(err);
|
|
978
981
|
}
|
|
979
982
|
}).finally(() => {
|
|
980
983
|
this.#pending--;
|
|
981
984
|
}).then(() => {}, (err) => {
|
|
982
|
-
this.#error ??= err;
|
|
985
|
+
this.#error ??= { error: err };
|
|
983
986
|
console.error(err);
|
|
984
987
|
}).finally(() => this.#tryDrain(next));
|
|
985
988
|
this.#ready = next;
|
|
@@ -988,10 +991,20 @@ var Elysia = class Elysia {
|
|
|
988
991
|
#tryDrain(sentinel) {
|
|
989
992
|
if (this.#pending > 0) return;
|
|
990
993
|
if (this.#ready !== sentinel) return;
|
|
994
|
+
const previousCompiled = this.#compiled;
|
|
995
|
+
const previousJitColdRemaining = this.#jitColdRemaining;
|
|
991
996
|
this.#ready = void 0;
|
|
997
|
+
this.#compiled = void 0;
|
|
992
998
|
this.#fetchFn = void 0;
|
|
993
999
|
this.#routerBuilt = false;
|
|
994
|
-
this
|
|
1000
|
+
require_context.clearContextCache(this);
|
|
1001
|
+
try {
|
|
1002
|
+
this.#buildRouter(false);
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
this.#compiled = previousCompiled;
|
|
1005
|
+
this.#jitColdRemaining = previousJitColdRemaining;
|
|
1006
|
+
this.#error ??= { error };
|
|
1007
|
+
}
|
|
995
1008
|
}
|
|
996
1009
|
#add(method, path, hookOrFn, fn, hasHook = fn !== void 0) {
|
|
997
1010
|
if (this["~Prefix"]) path = require_utils.joinPath(this["~Prefix"], path);
|
|
@@ -1211,20 +1224,22 @@ var Elysia = class Elysia {
|
|
|
1211
1224
|
}
|
|
1212
1225
|
handler(index, immediate, route, precomputedStatic, aliases, table) {
|
|
1213
1226
|
if (this.#compiled?.[index]) return this.#compiled[index];
|
|
1214
|
-
const
|
|
1227
|
+
const indexedTable = table ?? (this.#routerBuilt ? this["~routeTable"] : void 0);
|
|
1228
|
+
const compiled = this.#compiled ??= new Array(indexedTable?.length ?? this["~routes"].length);
|
|
1215
1229
|
if (immediate ?? this["~config"]?.precompile) {
|
|
1216
|
-
const row = route ?? (
|
|
1230
|
+
const row = route ?? (indexedTable ? require_route_table.routeRow(indexedTable, index) : this["~routes"][index]);
|
|
1231
|
+
const exactDuplicate = ((indexedTable?.flags[index] ?? 0) & require_route_table.RouteFlag.ExactDuplicate) !== 0;
|
|
1217
1232
|
let handler;
|
|
1218
1233
|
try {
|
|
1219
|
-
handler = require_compile_handler_index.compileHandler(row, this, precomputedStatic);
|
|
1234
|
+
handler = require_compile_handler_index.compileHandler(row, this, precomputedStatic, exactDuplicate && require_compile_aot.Compiled.hasProgram(this["~programId"]));
|
|
1220
1235
|
} catch (error) {
|
|
1221
1236
|
throw new Error(`[Elysia] Failed to compile route ${row[0]} ${row[1]}: ${error?.message ?? error}`, { cause: error });
|
|
1222
1237
|
}
|
|
1223
1238
|
compiled[index] = handler;
|
|
1224
|
-
this.#
|
|
1239
|
+
if (indexedTable) this.#satisfyJit(indexedTable, index);
|
|
1225
1240
|
return handler;
|
|
1226
1241
|
}
|
|
1227
|
-
return this.#jitHandler(index, route ?? (
|
|
1242
|
+
return this.#jitHandler(index, route ?? (indexedTable ? void 0 : this["~routes"][index]), precomputedStatic, aliases, indexedTable);
|
|
1228
1243
|
}
|
|
1229
1244
|
#jitHandler(index, route, precomputedStatic, aliases, table) {
|
|
1230
1245
|
if (table !== void 0) this.#jitTable = table;
|
|
@@ -1233,12 +1248,58 @@ var Elysia = class Elysia {
|
|
|
1233
1248
|
if (aliases !== void 0) (this.#jitAliases ??= [])[index] = aliases;
|
|
1234
1249
|
return (context) => this.#jitDispatch(index, context);
|
|
1235
1250
|
}
|
|
1251
|
+
#staticAliases(table, index) {
|
|
1252
|
+
const flags = table.flags[index];
|
|
1253
|
+
if ((flags & (require_route_table.RouteFlag.WS | require_route_table.RouteFlag.Dynamic)) !== 0) return;
|
|
1254
|
+
const path = table.path[index];
|
|
1255
|
+
const method = table.method[index];
|
|
1256
|
+
const needsEncode = (flags & require_route_table.RouteFlag.Encode) !== 0;
|
|
1257
|
+
const registerLoose = this["~config"]?.strictPath !== true && canRegisterLoose(path, false);
|
|
1258
|
+
if (!needsEncode && !registerLoose) return;
|
|
1259
|
+
let explicit;
|
|
1260
|
+
if (registerLoose) {
|
|
1261
|
+
explicit = /* @__PURE__ */ new Set();
|
|
1262
|
+
for (let i = 0; i < table.length; i++) {
|
|
1263
|
+
if (table.method[i] !== method) continue;
|
|
1264
|
+
const declared = table.path[i];
|
|
1265
|
+
explicit.add(declared);
|
|
1266
|
+
if ((table.flags[i] & require_route_table.RouteFlag.Encode) !== 0) explicit.add(encodeURI(declared));
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return {
|
|
1270
|
+
method,
|
|
1271
|
+
paths: expandPaths(path, needsEncode, registerLoose, explicit)
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
#releaseJit() {
|
|
1275
|
+
require_compile_aot.Compiled.release(this["~programId"]);
|
|
1276
|
+
this.#jitColdRemaining = void 0;
|
|
1277
|
+
this.#jitRoute = void 0;
|
|
1278
|
+
this.#jitStatic = void 0;
|
|
1279
|
+
this.#jitAliases = void 0;
|
|
1280
|
+
this.#jitTable = void 0;
|
|
1281
|
+
}
|
|
1282
|
+
#satisfyJit(table, index) {
|
|
1283
|
+
if ((table.flags[index] & require_route_table.RouteFlag.ExactDuplicate) !== 0) return false;
|
|
1284
|
+
if (this.#jitColdRemaining === void 0) {
|
|
1285
|
+
if (this["~generation"] === void 0 && this["~config"]?.precompile !== true && require_universal_is_production.isProduction() && !require_compile_aot.Capture.isAotBuildEnv()) table.flags[index] |= require_route_table.RouteFlag.JITSatisfied;
|
|
1286
|
+
return false;
|
|
1287
|
+
}
|
|
1288
|
+
if ((table.flags[index] & require_route_table.RouteFlag.JITCold) === 0) return false;
|
|
1289
|
+
table.flags[index] &= ~require_route_table.RouteFlag.JITCold;
|
|
1290
|
+
if (--this.#jitColdRemaining > 0) return false;
|
|
1291
|
+
this.#releaseJit();
|
|
1292
|
+
return true;
|
|
1293
|
+
}
|
|
1236
1294
|
#jitDispatch(index, context) {
|
|
1237
1295
|
if (this.#compiled[index]) return this.#compiled[index](context);
|
|
1238
|
-
const
|
|
1296
|
+
const route = this.#jitRoute?.[index];
|
|
1297
|
+
const table = this.#jitTable ?? this["~routeTable"];
|
|
1298
|
+
const materialized = route ?? require_route_table.routeRow(table, index);
|
|
1299
|
+
const exactDuplicate = ((table?.flags[index] ?? 0) & require_route_table.RouteFlag.ExactDuplicate) !== 0;
|
|
1239
1300
|
let handler;
|
|
1240
1301
|
try {
|
|
1241
|
-
handler = require_compile_handler_index.compileHandler(materialized, this, this.#jitStatic?.[index]);
|
|
1302
|
+
handler = require_compile_handler_index.compileHandler(materialized, this, this.#jitStatic?.[index], exactDuplicate && require_compile_aot.Compiled.hasProgram(this["~programId"]));
|
|
1242
1303
|
} catch (error) {
|
|
1243
1304
|
const routeError = new Error(`[Elysia] Failed to compile route ${materialized[0]} ${materialized[1]}: ${error?.message ?? error}`, { cause: error });
|
|
1244
1305
|
const finalize = this["~finalizeError"];
|
|
@@ -1246,24 +1307,15 @@ var Elysia = class Elysia {
|
|
|
1246
1307
|
throw routeError;
|
|
1247
1308
|
}
|
|
1248
1309
|
this.#compiled[index] = handler;
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1310
|
+
if (!exactDuplicate) {
|
|
1311
|
+
const aliases = this.#jitAliases?.[index] ?? (table ? this.#staticAliases(table, index) : void 0);
|
|
1312
|
+
if (aliases) {
|
|
1313
|
+
this.#initMap();
|
|
1314
|
+
const map = this["~map"][aliases.method] ??= require_utils.nullObject();
|
|
1315
|
+
for (let p = 0; p < aliases.paths.length; p++) map[aliases.paths[p]] = handler;
|
|
1316
|
+
} else this.#saveHandler(materialized[0], materialized[1], handler);
|
|
1254
1317
|
}
|
|
1255
|
-
|
|
1256
|
-
if (aliases) {
|
|
1257
|
-
this.#initMap();
|
|
1258
|
-
const map = this["~map"][aliases.method] ??= require_utils.nullObject();
|
|
1259
|
-
for (let p = 0; p < aliases.paths.length; p++) map[aliases.paths[p]] = handler;
|
|
1260
|
-
} else this.#saveHandler(materialized[0], materialized[1], handler);
|
|
1261
|
-
if (releasedNow) {
|
|
1262
|
-
this.#jitRoute = void 0;
|
|
1263
|
-
this.#jitStatic = void 0;
|
|
1264
|
-
this.#jitAliases = void 0;
|
|
1265
|
-
this.#jitTable = void 0;
|
|
1266
|
-
} else {
|
|
1318
|
+
if (!(table ? this.#satisfyJit(table, index) : false)) {
|
|
1267
1319
|
if (this.#jitRoute) this.#jitRoute[index] = void 0;
|
|
1268
1320
|
if (this.#jitStatic) this.#jitStatic[index] = void 0;
|
|
1269
1321
|
if (this.#jitAliases) this.#jitAliases[index] = void 0;
|
|
@@ -1404,19 +1456,30 @@ var Elysia = class Elysia {
|
|
|
1404
1456
|
"~wsConfig": this["~wsConfig"]
|
|
1405
1457
|
};
|
|
1406
1458
|
if (require_universal_is_production.isProduction() && !require_compile_aot.Capture.isAotBuildEnv()) {
|
|
1407
|
-
if (this["~config"]?.precompile)
|
|
1459
|
+
if (this["~config"]?.precompile) this.#releaseJit();
|
|
1408
1460
|
else {
|
|
1409
1461
|
const table = this["~routeTable"];
|
|
1410
|
-
const routeCount = table
|
|
1411
|
-
let cold = routeCount;
|
|
1462
|
+
const routeCount = table.length;
|
|
1412
1463
|
const compiled = this.#compiled;
|
|
1413
|
-
|
|
1414
|
-
|
|
1464
|
+
let cold = 0;
|
|
1465
|
+
for (let i = 0; i < routeCount; i++) {
|
|
1466
|
+
const satisfied = (table.flags[i] & require_route_table.RouteFlag.JITSatisfied) !== 0;
|
|
1467
|
+
table.flags[i] &= ~(require_route_table.RouteFlag.JITCold | require_route_table.RouteFlag.JITSatisfied);
|
|
1468
|
+
const flags = table.flags[i];
|
|
1469
|
+
if (satisfied || (flags & (require_route_table.RouteFlag.WS | require_route_table.RouteFlag.ExactDuplicate)) !== 0 || compiled?.[i] !== void 0) continue;
|
|
1470
|
+
table.flags[i] |= require_route_table.RouteFlag.JITCold;
|
|
1471
|
+
cold++;
|
|
1472
|
+
}
|
|
1473
|
+
if (cold === 0) this.#releaseJit();
|
|
1415
1474
|
else this.#jitColdRemaining = cold;
|
|
1416
1475
|
}
|
|
1417
1476
|
require_compile_analysis_cache.clearAuthoringAnalysisCaches(this);
|
|
1418
1477
|
if (!this["~ext"]?.macro && !this["~scopeChildren"]) this.#declaredRoutes = void 0;
|
|
1419
1478
|
}
|
|
1479
|
+
const ext = this["~ext"];
|
|
1480
|
+
if (ext?.hoc) extCallbackIndexes.delete(ext.hoc);
|
|
1481
|
+
if (ext?.setup) extCallbackIndexes.delete(ext.setup);
|
|
1482
|
+
if (ext?.cleanup) extCallbackIndexes.delete(ext.cleanup);
|
|
1420
1483
|
}
|
|
1421
1484
|
["~newGeneration"]() {
|
|
1422
1485
|
this.#fetchFn = void 0;
|
|
@@ -1440,23 +1503,31 @@ var Elysia = class Elysia {
|
|
|
1440
1503
|
const appChain = this["~hookChain"];
|
|
1441
1504
|
if (this["~ext"]?.macro || this["~scopeChildren"] || appChain !== void 0 && appChain.refs) for (let i = 0; i < length; i++) this.#assertRouteModelRefs(require_route_table.routeRow(table, i), method[i]);
|
|
1442
1505
|
else for (let i = 0; i < length; i++) if (this.#routeMayHaveModelRef(table, i)) this.#assertRouteModelRefs(require_route_table.routeRow(table, i), method[i]);
|
|
1506
|
+
let markDuplicates = false;
|
|
1443
1507
|
if (length) {
|
|
1444
1508
|
const programId = this["~programId"];
|
|
1445
1509
|
if (!require_compile_aot.Compiled.claim(programId, this["~aotFingerprint"] = require_compile_aot.createAotFingerprint())) require_compile_aot.Compiled.assertUncontested(programId);
|
|
1510
|
+
markDuplicates = require_compile_aot.Compiled.hasProgram(programId) || precompile !== true && require_universal_is_production.isProduction() && !require_compile_aot.Capture.isAotBuildEnv();
|
|
1446
1511
|
}
|
|
1447
1512
|
const isLoose = this["~config"]?.strictPath !== true;
|
|
1513
|
+
const collectExplicit = isLoose && table.hasLoose;
|
|
1448
1514
|
let explicitPaths;
|
|
1449
|
-
if (
|
|
1450
|
-
|
|
1515
|
+
if (markDuplicates || collectExplicit) {
|
|
1516
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1517
|
+
if (collectExplicit) explicitPaths = seen;
|
|
1451
1518
|
for (let i = 0; i < length; i++) {
|
|
1452
1519
|
const m = method[i];
|
|
1453
1520
|
const p = path[i];
|
|
1454
|
-
let
|
|
1455
|
-
if (!
|
|
1456
|
-
|
|
1457
|
-
|
|
1521
|
+
let paths = seen.get(m);
|
|
1522
|
+
if (!paths) seen.set(m, paths = /* @__PURE__ */ new Map());
|
|
1523
|
+
if (markDuplicates && (flags[i] & require_route_table.RouteFlag.WS) === 0) {
|
|
1524
|
+
const displaced = paths.get(p);
|
|
1525
|
+
if (displaced !== void 0 && displaced >= 0) flags[displaced] |= require_route_table.RouteFlag.ExactDuplicate;
|
|
1526
|
+
paths.set(p, i);
|
|
1527
|
+
} else paths.set(p, -1);
|
|
1528
|
+
if (collectExplicit && (flags[i] & require_route_table.RouteFlag.Encode) !== 0) {
|
|
1458
1529
|
const encoded = encodeURI(p);
|
|
1459
|
-
if (encoded !== p) set
|
|
1530
|
+
if (encoded !== p && !paths.has(encoded)) paths.set(encoded, -1);
|
|
1460
1531
|
}
|
|
1461
1532
|
}
|
|
1462
1533
|
}
|
|
@@ -1563,6 +1634,7 @@ var Elysia = class Elysia {
|
|
|
1563
1634
|
* ```
|
|
1564
1635
|
*/
|
|
1565
1636
|
cleanup(handler) {
|
|
1637
|
+
if (this["~ext"]?.cleanupEpoch?.(handler)) return this;
|
|
1566
1638
|
this.#assertMutable("cleanup");
|
|
1567
1639
|
const arr = this.#ext.cleanup ??= [];
|
|
1568
1640
|
if (Array.isArray(handler)) arr.push(...handler);
|
|
@@ -1570,24 +1642,49 @@ var Elysia = class Elysia {
|
|
|
1570
1642
|
return this;
|
|
1571
1643
|
}
|
|
1572
1644
|
/**
|
|
1573
|
-
* Stop the underlying server (if any),
|
|
1574
|
-
*
|
|
1645
|
+
* Stop the underlying server (if any), then run every `cleanup` handler.
|
|
1646
|
+
* Omitted and `false` are the same graceful stop: new requests are gated,
|
|
1647
|
+
* tracked WebSockets are settled and active HTTP is drained, then cleanup
|
|
1648
|
+
* runs and the epoch is released. `true` force-closes the transport
|
|
1649
|
+
* instead of draining it, and escalates a graceful stop already in flight.
|
|
1650
|
+
*
|
|
1651
|
+
* Awaiting `stop()` from inside a `setup`, `cleanup` or WebSocket lifecycle
|
|
1652
|
+
* callback is only supported while that callback is still synchronous; the
|
|
1653
|
+
* teardown is waiting on the callback, so after an `await` it can only be
|
|
1654
|
+
* issued as `void app.stop()`.
|
|
1575
1655
|
*
|
|
1576
|
-
* @param closeActiveConnections Pass `true` to terminate
|
|
1577
|
-
*
|
|
1578
|
-
* draining gracefully.
|
|
1656
|
+
* @param closeActiveConnections Pass `true` to terminate active
|
|
1657
|
+
* transports. Omit (or pass `false`) to drain safely.
|
|
1579
1658
|
*/
|
|
1580
1659
|
stop(closeActiveConnections) {
|
|
1660
|
+
const stop = this["~ext"]?.stop;
|
|
1661
|
+
if (stop) return stop(closeActiveConnections);
|
|
1581
1662
|
const server = this.server;
|
|
1582
1663
|
if (!server) return;
|
|
1583
|
-
|
|
1584
|
-
|
|
1664
|
+
let result;
|
|
1665
|
+
const errors = [];
|
|
1666
|
+
try {
|
|
1667
|
+
result = server.stop?.(closeActiveConnections);
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
errors.push(error);
|
|
1670
|
+
} finally {
|
|
1671
|
+
this.server = void 0;
|
|
1672
|
+
}
|
|
1585
1673
|
const handlers = this["~ext"]?.cleanup;
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1674
|
+
if (!errors.length && !handlers?.length) return result && typeof result.then === "function" ? result : void 0;
|
|
1675
|
+
return (async () => {
|
|
1676
|
+
try {
|
|
1677
|
+
await result;
|
|
1678
|
+
} catch (error) {
|
|
1679
|
+
errors.push(error);
|
|
1680
|
+
}
|
|
1681
|
+
if (handlers) for (let i = 0; i < handlers.length; i++) try {
|
|
1682
|
+
await handlers[i](this);
|
|
1683
|
+
} catch (error) {
|
|
1684
|
+
errors.push(error);
|
|
1685
|
+
}
|
|
1686
|
+
require_utils.throwLifecycleErrors(errors);
|
|
1687
|
+
})();
|
|
1591
1688
|
}
|
|
1592
1689
|
};
|
|
1593
1690
|
|