elysia 2.0.0-beta.13 → 2.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/bun/index.d.ts +4 -2
- package/dist/adapter/bun/index.js +35 -38
- package/dist/adapter/bun/index.mjs +35 -39
- package/dist/adapter/utils.js +16 -21
- package/dist/adapter/utils.mjs +16 -21
- package/dist/base.d.ts +28 -0
- package/dist/base.js +109 -59
- package/dist/base.mjs +110 -60
- package/dist/compile/aot.js +14 -21
- package/dist/compile/aot.mjs +14 -21
- package/dist/compile/handler/frozen-validator.js +51 -42
- package/dist/compile/handler/frozen-validator.mjs +51 -42
- package/dist/compile/handler/index.js +57 -50
- package/dist/compile/handler/index.mjs +57 -50
- package/dist/compile/handler/jit.js +36 -26
- package/dist/compile/handler/jit.mjs +37 -27
- package/dist/compile/handler/params.js +2 -0
- package/dist/compile/handler/params.mjs +3 -1
- package/dist/compile/handler/utils.d.ts +2 -2
- package/dist/compile/handler/utils.js +115 -111
- package/dist/compile/handler/utils.mjs +115 -113
- package/dist/context.d.ts +3 -1
- package/dist/context.js +2 -0
- package/dist/context.mjs +3 -1
- package/dist/cookie/config.js +6 -7
- package/dist/cookie/config.mjs +6 -7
- package/dist/error.d.ts +6 -3
- package/dist/error.js +26 -28
- package/dist/error.mjs +26 -28
- package/dist/handler/fetch.js +2 -1
- package/dist/handler/fetch.mjs +3 -2
- package/dist/handler/utils.d.ts +3 -1
- package/dist/handler/utils.js +19 -1
- package/dist/handler/utils.mjs +17 -1
- package/dist/index.d.ts +3 -3
- package/dist/package.js +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugin/aot/core.js +4 -0
- package/dist/plugin/aot/core.mjs +4 -0
- package/dist/sucrose.js +60 -59
- package/dist/sucrose.mjs +60 -59
- package/dist/trace.js +6 -9
- package/dist/trace.mjs +6 -9
- package/dist/type/coerce-plan.js +41 -36
- package/dist/type/coerce-plan.mjs +41 -36
- package/dist/type/coerce.d.ts +1 -1
- package/dist/type/constants.d.ts +1 -1
- package/dist/type/elysia/cookie.js +8 -17
- package/dist/type/elysia/cookie.mjs +8 -17
- package/dist/type/elysia/date.js +6 -7
- package/dist/type/elysia/date.mjs +6 -7
- package/dist/type/elysia/numeric.js +8 -9
- package/dist/type/elysia/numeric.mjs +8 -9
- package/dist/type/elysia/problem.d.ts +20 -0
- package/dist/type/elysia/problem.js +25 -0
- package/dist/type/elysia/problem.mjs +24 -0
- package/dist/type/exports.d.ts +3 -2
- package/dist/type/exports.js +2 -0
- package/dist/type/exports.mjs +2 -1
- package/dist/type/index.js +2 -0
- package/dist/type/index.mjs +2 -0
- package/dist/type/validator/clean-safe.d.ts +1 -2
- package/dist/type/validator/clean-safe.js +0 -2
- package/dist/type/validator/clean-safe.mjs +1 -2
- package/dist/type/validator/custom-error.js +37 -26
- package/dist/type/validator/custom-error.mjs +37 -26
- package/dist/type/validator/default-precompute.js +24 -26
- package/dist/type/validator/default-precompute.mjs +24 -26
- package/dist/type/validator/exact-mirror.js +6 -8
- package/dist/type/validator/exact-mirror.mjs +6 -8
- package/dist/type/validator/index.js +64 -66
- package/dist/type/validator/index.mjs +65 -67
- package/dist/type/validator/validator-cache.d.ts +2 -2
- package/dist/type/validator/validator-cache.js +7 -10
- package/dist/type/validator/validator-cache.mjs +6 -9
- package/dist/types.d.ts +4 -3
- package/dist/universal/file.js +2 -6
- package/dist/universal/file.mjs +2 -6
- package/dist/utils.d.ts +11 -2
- package/dist/utils.js +85 -47
- package/dist/utils.mjs +82 -48
- package/dist/validator/index.js +14 -18
- package/dist/validator/index.mjs +14 -18
- package/dist/ws/context.js +9 -11
- package/dist/ws/context.mjs +9 -11
- package/dist/ws/parser.js +23 -20
- package/dist/ws/parser.mjs +23 -20
- package/dist/ws/route.js +76 -87
- package/dist/ws/route.mjs +76 -87
- package/package.json +5 -2
package/dist/base.js
CHANGED
|
@@ -44,6 +44,23 @@ const mergeExtCallbacks = (target, incoming) => {
|
|
|
44
44
|
}
|
|
45
45
|
index.indexedLength = target.length;
|
|
46
46
|
};
|
|
47
|
+
const recordDisposable = (ext, value) => {
|
|
48
|
+
if (!require_utils.isDisposable(value)) return;
|
|
49
|
+
const disposable = ext.disposable ??= [];
|
|
50
|
+
if (!disposable.includes(value)) disposable.push(value);
|
|
51
|
+
};
|
|
52
|
+
const recordDisposables = (ext, source) => {
|
|
53
|
+
const stored = ext.decorator;
|
|
54
|
+
for (const key in source) {
|
|
55
|
+
const value = stored?.[key];
|
|
56
|
+
recordDisposable(ext, value);
|
|
57
|
+
if (!require_utils.isDisposable(value)) recordDisposable(ext, source[key]);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const markStoredSingletons = (table, source) => {
|
|
61
|
+
if (!table) return;
|
|
62
|
+
for (const key in source) require_utils.markSingletons(table[key]);
|
|
63
|
+
};
|
|
47
64
|
const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
|
|
48
65
|
const isSchemaValue = (value) => {
|
|
49
66
|
if (value == null || typeof value === "string") return true;
|
|
@@ -263,15 +280,31 @@ var Elysia = class Elysia {
|
|
|
263
280
|
const existing = target[name];
|
|
264
281
|
if (!fresh && name in target && !!existing && typeof existing === "object" && !Array.isArray(existing) && !Array.isArray(value)) target[name] = require_utils.mergeDeep(target[name], value, void 0, as === "override");
|
|
265
282
|
else target[name] = value;
|
|
283
|
+
if (field === "decorator") {
|
|
284
|
+
const stored = target[name];
|
|
285
|
+
recordDisposable(ext, stored);
|
|
286
|
+
if (!require_utils.isDisposable(stored)) recordDisposable(ext, value);
|
|
287
|
+
}
|
|
288
|
+
require_utils.markSingletons(target[name]);
|
|
266
289
|
return this;
|
|
267
290
|
}
|
|
268
291
|
if (fresh) Object.assign(target, value);
|
|
269
292
|
else ext[field] = require_utils.mergeDeep(target, value, void 0, as === "override");
|
|
293
|
+
if (field === "decorator") recordDisposables(ext, value);
|
|
294
|
+
markStoredSingletons(ext[field], value);
|
|
270
295
|
return this;
|
|
271
296
|
case "function":
|
|
272
297
|
if (name) {
|
|
273
|
-
if (as === "override" || !(name in target))
|
|
274
|
-
|
|
298
|
+
if (as === "override" || !(name in target)) {
|
|
299
|
+
target[name] = value;
|
|
300
|
+
if (field === "decorator") recordDisposable(ext, value);
|
|
301
|
+
require_utils.markSingletons(value);
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
ext[field] = value(target);
|
|
305
|
+
if (field === "decorator") recordDisposables(ext, ext[field]);
|
|
306
|
+
markStoredSingletons(ext[field], ext[field]);
|
|
307
|
+
}
|
|
275
308
|
return this;
|
|
276
309
|
default:
|
|
277
310
|
if (as === "override" || !(name in target)) target[name] = value;
|
|
@@ -810,12 +843,18 @@ var Elysia = class Elysia {
|
|
|
810
843
|
* Keep the cold blocks in their own frames.
|
|
811
844
|
*/
|
|
812
845
|
#absorbExt(app) {
|
|
813
|
-
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, capability } = app["~ext"];
|
|
846
|
+
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, disposable, capability } = app["~ext"];
|
|
814
847
|
const ext = this["~ext"] ??= require_utils.nullObject();
|
|
815
|
-
if (decorator)
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
848
|
+
if (decorator) {
|
|
849
|
+
if (ext.decorator) require_utils.mergeDeep(ext.decorator, decorator, void 0, true, false, void 0, { map: void 0 });
|
|
850
|
+
else ext.decorator = require_utils.clonePlainDecorators(decorator);
|
|
851
|
+
markStoredSingletons(ext.decorator, decorator);
|
|
852
|
+
}
|
|
853
|
+
if (store) {
|
|
854
|
+
if (ext.store) require_utils.mergeDeep(ext.store, store);
|
|
855
|
+
else ext.store = Object.assign(require_utils.nullObject(), store);
|
|
856
|
+
markStoredSingletons(ext.store, store);
|
|
857
|
+
}
|
|
819
858
|
if (headers) if (ext.headers) Object.assign(ext.headers, headers);
|
|
820
859
|
else ext.headers = Object.assign(require_utils.nullObject(), headers);
|
|
821
860
|
if (models) if (ext.models) Object.assign(ext.models, models);
|
|
@@ -850,6 +889,8 @@ var Elysia = class Elysia {
|
|
|
850
889
|
else ext.setup = setup.slice();
|
|
851
890
|
if (cleanup) if (ext.cleanup) mergeExtCallbacks(ext.cleanup, cleanup);
|
|
852
891
|
else ext.cleanup = cleanup.slice();
|
|
892
|
+
if (disposable) if (ext.disposable) mergeExtCallbacks(ext.disposable, disposable);
|
|
893
|
+
else ext.disposable = disposable.slice();
|
|
853
894
|
if (capability) {
|
|
854
895
|
const target = ext.capability ??= require_utils.nullObject();
|
|
855
896
|
if (capability.trace) {
|
|
@@ -1069,28 +1110,27 @@ var Elysia = class Elysia {
|
|
|
1069
1110
|
}).then(() => {}, (err) => {
|
|
1070
1111
|
this._error ??= { error: err };
|
|
1071
1112
|
console.error(err);
|
|
1072
|
-
}).finally(() =>
|
|
1113
|
+
}).finally(() => {
|
|
1114
|
+
if (this._pending > 0) return;
|
|
1115
|
+
if (this.ready !== next) return;
|
|
1116
|
+
const previousCompiled = this.compiled;
|
|
1117
|
+
const previousJitColdRemaining = this.jitColdRemaining;
|
|
1118
|
+
this.ready = void 0;
|
|
1119
|
+
this.compiled = void 0;
|
|
1120
|
+
this.fetchFn = void 0;
|
|
1121
|
+
this.routerBuilt = false;
|
|
1122
|
+
require_context.clearContextCache(this);
|
|
1123
|
+
try {
|
|
1124
|
+
this.#buildRouter(false);
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
this.compiled = previousCompiled;
|
|
1127
|
+
this.jitColdRemaining = previousJitColdRemaining;
|
|
1128
|
+
this._error ??= { error };
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1073
1131
|
this.ready = next;
|
|
1074
1132
|
return this;
|
|
1075
1133
|
}
|
|
1076
|
-
#tryDrain(sentinel) {
|
|
1077
|
-
if (this._pending > 0) return;
|
|
1078
|
-
if (this.ready !== sentinel) return;
|
|
1079
|
-
const previousCompiled = this.compiled;
|
|
1080
|
-
const previousJitColdRemaining = this.jitColdRemaining;
|
|
1081
|
-
this.ready = void 0;
|
|
1082
|
-
this.compiled = void 0;
|
|
1083
|
-
this.fetchFn = void 0;
|
|
1084
|
-
this.routerBuilt = false;
|
|
1085
|
-
require_context.clearContextCache(this);
|
|
1086
|
-
try {
|
|
1087
|
-
this.#buildRouter(false);
|
|
1088
|
-
} catch (error) {
|
|
1089
|
-
this.compiled = previousCompiled;
|
|
1090
|
-
this.jitColdRemaining = previousJitColdRemaining;
|
|
1091
|
-
this._error ??= { error };
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
1134
|
#add(method, path, hookOrFn, fn, hasHook = fn !== void 0) {
|
|
1095
1135
|
if (this["~Prefix"]) path = require_utils.joinPath(this["~Prefix"], path);
|
|
1096
1136
|
else if (path && path.charCodeAt(0) !== 47) path = "/" + path;
|
|
@@ -1234,6 +1274,9 @@ var Elysia = class Elysia {
|
|
|
1234
1274
|
options(path, hookOrFn, fn) {
|
|
1235
1275
|
return this.#add("OPTIONS", path, hookOrFn, fn);
|
|
1236
1276
|
}
|
|
1277
|
+
query(path, hookOrFn, fn) {
|
|
1278
|
+
return this.#add("QUERY", path, hookOrFn, fn);
|
|
1279
|
+
}
|
|
1237
1280
|
head(path, hookOrFn, fn) {
|
|
1238
1281
|
return this.#add("HEAD", path, hookOrFn, fn);
|
|
1239
1282
|
}
|
|
@@ -1337,11 +1380,9 @@ var Elysia = class Elysia {
|
|
|
1337
1380
|
if (indexedTable) this.#satisfyJit(indexedTable, index);
|
|
1338
1381
|
return handler;
|
|
1339
1382
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
if (table !== void 0) this.jitTable = table;
|
|
1344
|
-
if (route !== void 0) (this.jitRoute ??= [])[index] = route;
|
|
1383
|
+
const jitRoute = route ?? (indexedTable ? void 0 : this["~routes"][index]);
|
|
1384
|
+
if (indexedTable !== void 0) this.jitTable = indexedTable;
|
|
1385
|
+
if (jitRoute !== void 0) (this.jitRoute ??= [])[index] = jitRoute;
|
|
1345
1386
|
if (precomputedStatic !== void 0) (this.jitStatic ??= [])[index] = precomputedStatic;
|
|
1346
1387
|
if (aliases !== void 0) (this.jitAliases ??= [])[index] = aliases;
|
|
1347
1388
|
return (context) => this.#jitDispatch(index, context);
|
|
@@ -1483,31 +1524,6 @@ var Elysia = class Elysia {
|
|
|
1483
1524
|
}
|
|
1484
1525
|
return false;
|
|
1485
1526
|
}
|
|
1486
|
-
/**
|
|
1487
|
-
* Scan each route and its inherited hooks for TypeBox schemas.
|
|
1488
|
-
* This may warm TypeBox after a closer schema overrides it, avoiding a full
|
|
1489
|
-
* hook merge during build.
|
|
1490
|
-
*/
|
|
1491
|
-
#hasTypeBoxSchema(table) {
|
|
1492
|
-
const models = this["~ext"]?.models;
|
|
1493
|
-
const resolve = require_compile_handler_index.chainResolver(this);
|
|
1494
|
-
const rootChain = this["~hookChain"];
|
|
1495
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1496
|
-
const { localHook, appHook, inheritedChain, owner } = table;
|
|
1497
|
-
for (let i = 0; i < table.length; i++) if (Elysia.#hookHasTypeBox(localHook[i], models) || Elysia.#chainHasTypeBox(appHook[i], models, seen, resolve) || Elysia.#chainHasTypeBox(inheritedChain[i], models, seen, resolve) || owner[i] !== this && Elysia.#chainHasTypeBox(rootChain, models, seen, resolve)) return true;
|
|
1498
|
-
return false;
|
|
1499
|
-
}
|
|
1500
|
-
#routeMayHaveModelRef(table, i) {
|
|
1501
|
-
const macroScope = table.macroScope?.get(i);
|
|
1502
|
-
const owner = table.owner[i];
|
|
1503
|
-
const candidate = macroScope ?? owner ?? this;
|
|
1504
|
-
if ((candidate === this ? this : require_compile_handler_index.localMacroRoot(candidate, this))["~ext"]?.macro) return true;
|
|
1505
|
-
if (Elysia.#hookHasString(table.localHook[i])) return true;
|
|
1506
|
-
const appHook = table.appHook[i];
|
|
1507
|
-
if (appHook !== void 0 && appHook.refs) return true;
|
|
1508
|
-
const inheritedChain = table.inheritedChain[i];
|
|
1509
|
-
return inheritedChain !== void 0 && inheritedChain.refs;
|
|
1510
|
-
}
|
|
1511
1527
|
#assertRouteModelRefs(route, method) {
|
|
1512
1528
|
const models = this["~ext"]?.models;
|
|
1513
1529
|
const path = route[1];
|
|
@@ -1649,8 +1665,37 @@ var Elysia = class Elysia {
|
|
|
1649
1665
|
const length = table.length;
|
|
1650
1666
|
const appChain = this["~hookChain"];
|
|
1651
1667
|
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]);
|
|
1652
|
-
else for (let i = 0; i < length; i++)
|
|
1653
|
-
|
|
1668
|
+
else for (let i = 0; i < length; i++) {
|
|
1669
|
+
const macroScope = table.macroScope?.get(i);
|
|
1670
|
+
const owner = table.owner[i];
|
|
1671
|
+
const candidate = macroScope ?? owner ?? this;
|
|
1672
|
+
const localRoot = candidate === this ? this : require_compile_handler_index.localMacroRoot(candidate, this);
|
|
1673
|
+
let hasModelRef;
|
|
1674
|
+
if (localRoot["~ext"]?.macro) hasModelRef = true;
|
|
1675
|
+
else if (Elysia.#hookHasString(table.localHook[i])) hasModelRef = true;
|
|
1676
|
+
else {
|
|
1677
|
+
const appHook = table.appHook[i];
|
|
1678
|
+
if (appHook !== void 0 && appHook.refs) hasModelRef = true;
|
|
1679
|
+
else {
|
|
1680
|
+
const inheritedChain = table.inheritedChain[i];
|
|
1681
|
+
hasModelRef = inheritedChain !== void 0 && inheritedChain.refs;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (hasModelRef) this.#assertRouteModelRefs(require_route_table.routeRow(table, i), method[i]);
|
|
1685
|
+
}
|
|
1686
|
+
let hasTypeBoxSchema = false;
|
|
1687
|
+
if (length) {
|
|
1688
|
+
const models = this["~ext"]?.models;
|
|
1689
|
+
const resolve = require_compile_handler_index.chainResolver(this);
|
|
1690
|
+
const rootChain = this["~hookChain"];
|
|
1691
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1692
|
+
const { localHook, appHook, inheritedChain, owner } = table;
|
|
1693
|
+
for (let i = 0; i < table.length; i++) if (Elysia.#hookHasTypeBox(localHook[i], models) || Elysia.#chainHasTypeBox(appHook[i], models, seen, resolve) || Elysia.#chainHasTypeBox(inheritedChain[i], models, seen, resolve) || owner[i] !== this && Elysia.#chainHasTypeBox(rootChain, models, seen, resolve)) {
|
|
1694
|
+
hasTypeBoxSchema = true;
|
|
1695
|
+
break;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
if (hasTypeBoxSchema) try {
|
|
1654
1699
|
require_type_bridge.warmTypebox();
|
|
1655
1700
|
} catch {}
|
|
1656
1701
|
let markDuplicates = false;
|
|
@@ -1816,7 +1861,7 @@ var Elysia = class Elysia {
|
|
|
1816
1861
|
this.server = void 0;
|
|
1817
1862
|
}
|
|
1818
1863
|
const handlers = this["~ext"]?.cleanup;
|
|
1819
|
-
if (!errors.length && !handlers?.length) return result && typeof result.then === "function" ? result : void 0;
|
|
1864
|
+
if (!errors.length && !handlers?.length && !this["~ext"]?.disposable?.length) return result && typeof result.then === "function" ? result : void 0;
|
|
1820
1865
|
return (async () => {
|
|
1821
1866
|
try {
|
|
1822
1867
|
await result;
|
|
@@ -1828,6 +1873,11 @@ var Elysia = class Elysia {
|
|
|
1828
1873
|
} catch (error) {
|
|
1829
1874
|
errors.push(error);
|
|
1830
1875
|
}
|
|
1876
|
+
try {
|
|
1877
|
+
await require_utils.disposeDecorators(this);
|
|
1878
|
+
} catch (error) {
|
|
1879
|
+
errors.push(error);
|
|
1880
|
+
}
|
|
1831
1881
|
require_utils.throwLifecycleErrors(errors);
|
|
1832
1882
|
})();
|
|
1833
1883
|
}
|
package/dist/base.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isBun } from "./universal/constants.mjs";
|
|
2
|
-
import { clonePlainDecorators, clonePlainDeep, coalesceSchemas, createErrorEventHandler, eventProperties, fnOrigin, fnv1a, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isEmpty, isNotEmpty, isRecordNumber, joinPath, macroOrigin, mapDeriveEntry, mergeDeep, mergeResponse, nullObject, pushField, schemaProperties, serializeMacroSeed, throwLifecycleErrors } from "./utils.mjs";
|
|
2
|
+
import { clonePlainDecorators, clonePlainDeep, coalesceSchemas, createErrorEventHandler, disposeDecorators, eventProperties, fnOrigin, fnv1a, getLoosePath, guardNonPlainLeaves, hookToGuard, invalidateMacroEpoch, isDisposable, isEmpty, isNotEmpty, isRecordNumber, joinPath, macroOrigin, mapDeriveEntry, markSingletons, mergeDeep, mergeResponse, nullObject, pushField, schemaProperties, serializeMacroSeed, throwLifecycleErrors } from "./utils.mjs";
|
|
3
3
|
import { Ref, warmTypebox } from "./type/bridge.mjs";
|
|
4
4
|
import { isProduction } from "./universal/is-production.mjs";
|
|
5
5
|
import { Capture, Compiled, beginCompilerSession, createAotFingerprint, endCompilerSession } from "./compile/aot.mjs";
|
|
@@ -41,6 +41,23 @@ const mergeExtCallbacks = (target, incoming) => {
|
|
|
41
41
|
}
|
|
42
42
|
index.indexedLength = target.length;
|
|
43
43
|
};
|
|
44
|
+
const recordDisposable = (ext, value) => {
|
|
45
|
+
if (!isDisposable(value)) return;
|
|
46
|
+
const disposable = ext.disposable ??= [];
|
|
47
|
+
if (!disposable.includes(value)) disposable.push(value);
|
|
48
|
+
};
|
|
49
|
+
const recordDisposables = (ext, source) => {
|
|
50
|
+
const stored = ext.decorator;
|
|
51
|
+
for (const key in source) {
|
|
52
|
+
const value = stored?.[key];
|
|
53
|
+
recordDisposable(ext, value);
|
|
54
|
+
if (!isDisposable(value)) recordDisposable(ext, source[key]);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const markStoredSingletons = (table, source) => {
|
|
58
|
+
if (!table) return;
|
|
59
|
+
for (const key in source) markSingletons(table[key]);
|
|
60
|
+
};
|
|
44
61
|
const canRegisterLoose = (path, isDynamic) => !isDynamic && (path.length === 0 || path.charCodeAt(path.length - 1) === 47);
|
|
45
62
|
const isSchemaValue = (value) => {
|
|
46
63
|
if (value == null || typeof value === "string") return true;
|
|
@@ -260,15 +277,31 @@ var Elysia = class Elysia {
|
|
|
260
277
|
const existing = target[name];
|
|
261
278
|
if (!fresh && name in target && !!existing && typeof existing === "object" && !Array.isArray(existing) && !Array.isArray(value)) target[name] = mergeDeep(target[name], value, void 0, as === "override");
|
|
262
279
|
else target[name] = value;
|
|
280
|
+
if (field === "decorator") {
|
|
281
|
+
const stored = target[name];
|
|
282
|
+
recordDisposable(ext, stored);
|
|
283
|
+
if (!isDisposable(stored)) recordDisposable(ext, value);
|
|
284
|
+
}
|
|
285
|
+
markSingletons(target[name]);
|
|
263
286
|
return this;
|
|
264
287
|
}
|
|
265
288
|
if (fresh) Object.assign(target, value);
|
|
266
289
|
else ext[field] = mergeDeep(target, value, void 0, as === "override");
|
|
290
|
+
if (field === "decorator") recordDisposables(ext, value);
|
|
291
|
+
markStoredSingletons(ext[field], value);
|
|
267
292
|
return this;
|
|
268
293
|
case "function":
|
|
269
294
|
if (name) {
|
|
270
|
-
if (as === "override" || !(name in target))
|
|
271
|
-
|
|
295
|
+
if (as === "override" || !(name in target)) {
|
|
296
|
+
target[name] = value;
|
|
297
|
+
if (field === "decorator") recordDisposable(ext, value);
|
|
298
|
+
markSingletons(value);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
ext[field] = value(target);
|
|
302
|
+
if (field === "decorator") recordDisposables(ext, ext[field]);
|
|
303
|
+
markStoredSingletons(ext[field], ext[field]);
|
|
304
|
+
}
|
|
272
305
|
return this;
|
|
273
306
|
default:
|
|
274
307
|
if (as === "override" || !(name in target)) target[name] = value;
|
|
@@ -807,12 +840,18 @@ var Elysia = class Elysia {
|
|
|
807
840
|
* Keep the cold blocks in their own frames.
|
|
808
841
|
*/
|
|
809
842
|
#absorbExt(app) {
|
|
810
|
-
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, capability } = app["~ext"];
|
|
843
|
+
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, disposable, capability } = app["~ext"];
|
|
811
844
|
const ext = this["~ext"] ??= nullObject();
|
|
812
|
-
if (decorator)
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
845
|
+
if (decorator) {
|
|
846
|
+
if (ext.decorator) mergeDeep(ext.decorator, decorator, void 0, true, false, void 0, { map: void 0 });
|
|
847
|
+
else ext.decorator = clonePlainDecorators(decorator);
|
|
848
|
+
markStoredSingletons(ext.decorator, decorator);
|
|
849
|
+
}
|
|
850
|
+
if (store) {
|
|
851
|
+
if (ext.store) mergeDeep(ext.store, store);
|
|
852
|
+
else ext.store = Object.assign(nullObject(), store);
|
|
853
|
+
markStoredSingletons(ext.store, store);
|
|
854
|
+
}
|
|
816
855
|
if (headers) if (ext.headers) Object.assign(ext.headers, headers);
|
|
817
856
|
else ext.headers = Object.assign(nullObject(), headers);
|
|
818
857
|
if (models) if (ext.models) Object.assign(ext.models, models);
|
|
@@ -847,6 +886,8 @@ var Elysia = class Elysia {
|
|
|
847
886
|
else ext.setup = setup.slice();
|
|
848
887
|
if (cleanup) if (ext.cleanup) mergeExtCallbacks(ext.cleanup, cleanup);
|
|
849
888
|
else ext.cleanup = cleanup.slice();
|
|
889
|
+
if (disposable) if (ext.disposable) mergeExtCallbacks(ext.disposable, disposable);
|
|
890
|
+
else ext.disposable = disposable.slice();
|
|
850
891
|
if (capability) {
|
|
851
892
|
const target = ext.capability ??= nullObject();
|
|
852
893
|
if (capability.trace) {
|
|
@@ -1066,28 +1107,27 @@ var Elysia = class Elysia {
|
|
|
1066
1107
|
}).then(() => {}, (err) => {
|
|
1067
1108
|
this._error ??= { error: err };
|
|
1068
1109
|
console.error(err);
|
|
1069
|
-
}).finally(() =>
|
|
1110
|
+
}).finally(() => {
|
|
1111
|
+
if (this._pending > 0) return;
|
|
1112
|
+
if (this.ready !== next) return;
|
|
1113
|
+
const previousCompiled = this.compiled;
|
|
1114
|
+
const previousJitColdRemaining = this.jitColdRemaining;
|
|
1115
|
+
this.ready = void 0;
|
|
1116
|
+
this.compiled = void 0;
|
|
1117
|
+
this.fetchFn = void 0;
|
|
1118
|
+
this.routerBuilt = false;
|
|
1119
|
+
clearContextCache(this);
|
|
1120
|
+
try {
|
|
1121
|
+
this.#buildRouter(false);
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
this.compiled = previousCompiled;
|
|
1124
|
+
this.jitColdRemaining = previousJitColdRemaining;
|
|
1125
|
+
this._error ??= { error };
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1070
1128
|
this.ready = next;
|
|
1071
1129
|
return this;
|
|
1072
1130
|
}
|
|
1073
|
-
#tryDrain(sentinel) {
|
|
1074
|
-
if (this._pending > 0) return;
|
|
1075
|
-
if (this.ready !== sentinel) return;
|
|
1076
|
-
const previousCompiled = this.compiled;
|
|
1077
|
-
const previousJitColdRemaining = this.jitColdRemaining;
|
|
1078
|
-
this.ready = void 0;
|
|
1079
|
-
this.compiled = void 0;
|
|
1080
|
-
this.fetchFn = void 0;
|
|
1081
|
-
this.routerBuilt = false;
|
|
1082
|
-
clearContextCache(this);
|
|
1083
|
-
try {
|
|
1084
|
-
this.#buildRouter(false);
|
|
1085
|
-
} catch (error) {
|
|
1086
|
-
this.compiled = previousCompiled;
|
|
1087
|
-
this.jitColdRemaining = previousJitColdRemaining;
|
|
1088
|
-
this._error ??= { error };
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
1131
|
#add(method, path, hookOrFn, fn, hasHook = fn !== void 0) {
|
|
1092
1132
|
if (this["~Prefix"]) path = joinPath(this["~Prefix"], path);
|
|
1093
1133
|
else if (path && path.charCodeAt(0) !== 47) path = "/" + path;
|
|
@@ -1231,6 +1271,9 @@ var Elysia = class Elysia {
|
|
|
1231
1271
|
options(path, hookOrFn, fn) {
|
|
1232
1272
|
return this.#add("OPTIONS", path, hookOrFn, fn);
|
|
1233
1273
|
}
|
|
1274
|
+
query(path, hookOrFn, fn) {
|
|
1275
|
+
return this.#add("QUERY", path, hookOrFn, fn);
|
|
1276
|
+
}
|
|
1234
1277
|
head(path, hookOrFn, fn) {
|
|
1235
1278
|
return this.#add("HEAD", path, hookOrFn, fn);
|
|
1236
1279
|
}
|
|
@@ -1334,11 +1377,9 @@ var Elysia = class Elysia {
|
|
|
1334
1377
|
if (indexedTable) this.#satisfyJit(indexedTable, index);
|
|
1335
1378
|
return handler;
|
|
1336
1379
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
if (table !== void 0) this.jitTable = table;
|
|
1341
|
-
if (route !== void 0) (this.jitRoute ??= [])[index] = route;
|
|
1380
|
+
const jitRoute = route ?? (indexedTable ? void 0 : this["~routes"][index]);
|
|
1381
|
+
if (indexedTable !== void 0) this.jitTable = indexedTable;
|
|
1382
|
+
if (jitRoute !== void 0) (this.jitRoute ??= [])[index] = jitRoute;
|
|
1342
1383
|
if (precomputedStatic !== void 0) (this.jitStatic ??= [])[index] = precomputedStatic;
|
|
1343
1384
|
if (aliases !== void 0) (this.jitAliases ??= [])[index] = aliases;
|
|
1344
1385
|
return (context) => this.#jitDispatch(index, context);
|
|
@@ -1480,31 +1521,6 @@ var Elysia = class Elysia {
|
|
|
1480
1521
|
}
|
|
1481
1522
|
return false;
|
|
1482
1523
|
}
|
|
1483
|
-
/**
|
|
1484
|
-
* Scan each route and its inherited hooks for TypeBox schemas.
|
|
1485
|
-
* This may warm TypeBox after a closer schema overrides it, avoiding a full
|
|
1486
|
-
* hook merge during build.
|
|
1487
|
-
*/
|
|
1488
|
-
#hasTypeBoxSchema(table) {
|
|
1489
|
-
const models = this["~ext"]?.models;
|
|
1490
|
-
const resolve = chainResolver(this);
|
|
1491
|
-
const rootChain = this["~hookChain"];
|
|
1492
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1493
|
-
const { localHook, appHook, inheritedChain, owner } = table;
|
|
1494
|
-
for (let i = 0; i < table.length; i++) if (Elysia.#hookHasTypeBox(localHook[i], models) || Elysia.#chainHasTypeBox(appHook[i], models, seen, resolve) || Elysia.#chainHasTypeBox(inheritedChain[i], models, seen, resolve) || owner[i] !== this && Elysia.#chainHasTypeBox(rootChain, models, seen, resolve)) return true;
|
|
1495
|
-
return false;
|
|
1496
|
-
}
|
|
1497
|
-
#routeMayHaveModelRef(table, i) {
|
|
1498
|
-
const macroScope = table.macroScope?.get(i);
|
|
1499
|
-
const owner = table.owner[i];
|
|
1500
|
-
const candidate = macroScope ?? owner ?? this;
|
|
1501
|
-
if ((candidate === this ? this : localMacroRoot(candidate, this))["~ext"]?.macro) return true;
|
|
1502
|
-
if (Elysia.#hookHasString(table.localHook[i])) return true;
|
|
1503
|
-
const appHook = table.appHook[i];
|
|
1504
|
-
if (appHook !== void 0 && appHook.refs) return true;
|
|
1505
|
-
const inheritedChain = table.inheritedChain[i];
|
|
1506
|
-
return inheritedChain !== void 0 && inheritedChain.refs;
|
|
1507
|
-
}
|
|
1508
1524
|
#assertRouteModelRefs(route, method) {
|
|
1509
1525
|
const models = this["~ext"]?.models;
|
|
1510
1526
|
const path = route[1];
|
|
@@ -1646,8 +1662,37 @@ var Elysia = class Elysia {
|
|
|
1646
1662
|
const length = table.length;
|
|
1647
1663
|
const appChain = this["~hookChain"];
|
|
1648
1664
|
if (this["~ext"]?.macro || this["~scopeChildren"] || appChain !== void 0 && appChain.refs) for (let i = 0; i < length; i++) this.#assertRouteModelRefs(routeRow(table, i), method[i]);
|
|
1649
|
-
else for (let i = 0; i < length; i++)
|
|
1650
|
-
|
|
1665
|
+
else for (let i = 0; i < length; i++) {
|
|
1666
|
+
const macroScope = table.macroScope?.get(i);
|
|
1667
|
+
const owner = table.owner[i];
|
|
1668
|
+
const candidate = macroScope ?? owner ?? this;
|
|
1669
|
+
const localRoot = candidate === this ? this : localMacroRoot(candidate, this);
|
|
1670
|
+
let hasModelRef;
|
|
1671
|
+
if (localRoot["~ext"]?.macro) hasModelRef = true;
|
|
1672
|
+
else if (Elysia.#hookHasString(table.localHook[i])) hasModelRef = true;
|
|
1673
|
+
else {
|
|
1674
|
+
const appHook = table.appHook[i];
|
|
1675
|
+
if (appHook !== void 0 && appHook.refs) hasModelRef = true;
|
|
1676
|
+
else {
|
|
1677
|
+
const inheritedChain = table.inheritedChain[i];
|
|
1678
|
+
hasModelRef = inheritedChain !== void 0 && inheritedChain.refs;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
if (hasModelRef) this.#assertRouteModelRefs(routeRow(table, i), method[i]);
|
|
1682
|
+
}
|
|
1683
|
+
let hasTypeBoxSchema = false;
|
|
1684
|
+
if (length) {
|
|
1685
|
+
const models = this["~ext"]?.models;
|
|
1686
|
+
const resolve = chainResolver(this);
|
|
1687
|
+
const rootChain = this["~hookChain"];
|
|
1688
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1689
|
+
const { localHook, appHook, inheritedChain, owner } = table;
|
|
1690
|
+
for (let i = 0; i < table.length; i++) if (Elysia.#hookHasTypeBox(localHook[i], models) || Elysia.#chainHasTypeBox(appHook[i], models, seen, resolve) || Elysia.#chainHasTypeBox(inheritedChain[i], models, seen, resolve) || owner[i] !== this && Elysia.#chainHasTypeBox(rootChain, models, seen, resolve)) {
|
|
1691
|
+
hasTypeBoxSchema = true;
|
|
1692
|
+
break;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
if (hasTypeBoxSchema) try {
|
|
1651
1696
|
warmTypebox();
|
|
1652
1697
|
} catch {}
|
|
1653
1698
|
let markDuplicates = false;
|
|
@@ -1813,7 +1858,7 @@ var Elysia = class Elysia {
|
|
|
1813
1858
|
this.server = void 0;
|
|
1814
1859
|
}
|
|
1815
1860
|
const handlers = this["~ext"]?.cleanup;
|
|
1816
|
-
if (!errors.length && !handlers?.length) return result && typeof result.then === "function" ? result : void 0;
|
|
1861
|
+
if (!errors.length && !handlers?.length && !this["~ext"]?.disposable?.length) return result && typeof result.then === "function" ? result : void 0;
|
|
1817
1862
|
return (async () => {
|
|
1818
1863
|
try {
|
|
1819
1864
|
await result;
|
|
@@ -1825,6 +1870,11 @@ var Elysia = class Elysia {
|
|
|
1825
1870
|
} catch (error) {
|
|
1826
1871
|
errors.push(error);
|
|
1827
1872
|
}
|
|
1873
|
+
try {
|
|
1874
|
+
await disposeDecorators(this);
|
|
1875
|
+
} catch (error) {
|
|
1876
|
+
errors.push(error);
|
|
1877
|
+
}
|
|
1828
1878
|
throwLifecycleErrors(errors);
|
|
1829
1879
|
})();
|
|
1830
1880
|
}
|
package/dist/compile/aot.js
CHANGED
|
@@ -46,13 +46,6 @@ let registered;
|
|
|
46
46
|
let claimed;
|
|
47
47
|
let programs = /* @__PURE__ */ new WeakMap();
|
|
48
48
|
const programFor = (id) => id ? programs.get(id) : void 0;
|
|
49
|
-
const fingerprintMismatch = (manifest, actual) => {
|
|
50
|
-
const differences = [];
|
|
51
|
-
const expected = manifest.fingerprint;
|
|
52
|
-
if (manifest.bf !== 1) differences.push(`bf (manifest ${manifest.bf}, app 1)`);
|
|
53
|
-
if (expected.abi !== actual.abi) differences.push(`abi (manifest ${expected.abi}, app ${actual.abi})`);
|
|
54
|
-
return differences;
|
|
55
|
-
};
|
|
56
49
|
var Compiled = class {
|
|
57
50
|
static register(manifest) {
|
|
58
51
|
registered = manifest;
|
|
@@ -61,7 +54,10 @@ var Compiled = class {
|
|
|
61
54
|
static claim(id, fingerprint) {
|
|
62
55
|
if (!registered || claimed) return false;
|
|
63
56
|
const manifest = registered;
|
|
64
|
-
const differences =
|
|
57
|
+
const differences = [];
|
|
58
|
+
const expected = manifest.fingerprint;
|
|
59
|
+
if (manifest.bf !== 1) differences.push(`bf (manifest ${manifest.bf}, app 1)`);
|
|
60
|
+
if (expected.abi !== fingerprint.abi) differences.push(`abi (manifest ${expected.abi}, app ${fingerprint.abi})`);
|
|
65
61
|
if (differences.length) throw new Error(`[elysia-aot] Registered manifest fingerprint mismatch: ${differences.join("; ")}.`);
|
|
66
62
|
claimed = new WeakRef(id);
|
|
67
63
|
registered = void 0;
|
|
@@ -155,7 +151,16 @@ const CompilerState = {
|
|
|
155
151
|
}
|
|
156
152
|
};
|
|
157
153
|
const EMPTY_EXTERNALS = Object.freeze([]);
|
|
158
|
-
|
|
154
|
+
/** @internal shared with `aot-capture.ts` (`beginValidatorCapture`). */
|
|
155
|
+
const aotActivationError = () => /* @__PURE__ */ new Error("Elysia AOT capture module is not activated.");
|
|
156
|
+
function captureHandler(v) {
|
|
157
|
+
if (!isValidatorCapturing()) return;
|
|
158
|
+
const session = activeSession;
|
|
159
|
+
if (!session) return;
|
|
160
|
+
(session.handlerCapture ??= /* @__PURE__ */ new Map()).set(`${v.method}\0${v.path}`, v);
|
|
161
|
+
}
|
|
162
|
+
function captureSet(loc, partial) {
|
|
163
|
+
const { method, path, slot } = loc;
|
|
159
164
|
if (!isValidatorCapturing()) return;
|
|
160
165
|
const capture = activeSession?.capture;
|
|
161
166
|
if (!capture) return;
|
|
@@ -166,18 +171,6 @@ function captureEntry({ method, path, slot }) {
|
|
|
166
171
|
path,
|
|
167
172
|
slot
|
|
168
173
|
});
|
|
169
|
-
return e;
|
|
170
|
-
}
|
|
171
|
-
/** @internal shared with `aot-capture.ts` (`beginValidatorCapture`). */
|
|
172
|
-
const aotActivationError = () => /* @__PURE__ */ new Error("Elysia AOT capture module is not activated.");
|
|
173
|
-
function captureHandler(v) {
|
|
174
|
-
if (!isValidatorCapturing()) return;
|
|
175
|
-
const session = activeSession;
|
|
176
|
-
if (!session) return;
|
|
177
|
-
(session.handlerCapture ??= /* @__PURE__ */ new Map()).set(`${v.method}\0${v.path}`, v);
|
|
178
|
-
}
|
|
179
|
-
function captureSet(loc, partial) {
|
|
180
|
-
const e = captureEntry(loc);
|
|
181
174
|
if (e) Object.assign(e, partial);
|
|
182
175
|
}
|
|
183
176
|
const captureGet = (loc) => activeSession?.capture?.get(`${loc.method}_${loc.path}_${loc.slot}`);
|
package/dist/compile/aot.mjs
CHANGED
|
@@ -45,13 +45,6 @@ let registered;
|
|
|
45
45
|
let claimed;
|
|
46
46
|
let programs = /* @__PURE__ */ new WeakMap();
|
|
47
47
|
const programFor = (id) => id ? programs.get(id) : void 0;
|
|
48
|
-
const fingerprintMismatch = (manifest, actual) => {
|
|
49
|
-
const differences = [];
|
|
50
|
-
const expected = manifest.fingerprint;
|
|
51
|
-
if (manifest.bf !== 1) differences.push(`bf (manifest ${manifest.bf}, app 1)`);
|
|
52
|
-
if (expected.abi !== actual.abi) differences.push(`abi (manifest ${expected.abi}, app ${actual.abi})`);
|
|
53
|
-
return differences;
|
|
54
|
-
};
|
|
55
48
|
var Compiled = class {
|
|
56
49
|
static register(manifest) {
|
|
57
50
|
registered = manifest;
|
|
@@ -60,7 +53,10 @@ var Compiled = class {
|
|
|
60
53
|
static claim(id, fingerprint) {
|
|
61
54
|
if (!registered || claimed) return false;
|
|
62
55
|
const manifest = registered;
|
|
63
|
-
const differences =
|
|
56
|
+
const differences = [];
|
|
57
|
+
const expected = manifest.fingerprint;
|
|
58
|
+
if (manifest.bf !== 1) differences.push(`bf (manifest ${manifest.bf}, app 1)`);
|
|
59
|
+
if (expected.abi !== fingerprint.abi) differences.push(`abi (manifest ${expected.abi}, app ${fingerprint.abi})`);
|
|
64
60
|
if (differences.length) throw new Error(`[elysia-aot] Registered manifest fingerprint mismatch: ${differences.join("; ")}.`);
|
|
65
61
|
claimed = new WeakRef(id);
|
|
66
62
|
registered = void 0;
|
|
@@ -154,7 +150,16 @@ const CompilerState = {
|
|
|
154
150
|
}
|
|
155
151
|
};
|
|
156
152
|
const EMPTY_EXTERNALS = Object.freeze([]);
|
|
157
|
-
|
|
153
|
+
/** @internal shared with `aot-capture.ts` (`beginValidatorCapture`). */
|
|
154
|
+
const aotActivationError = () => /* @__PURE__ */ new Error("Elysia AOT capture module is not activated.");
|
|
155
|
+
function captureHandler(v) {
|
|
156
|
+
if (!isValidatorCapturing()) return;
|
|
157
|
+
const session = activeSession;
|
|
158
|
+
if (!session) return;
|
|
159
|
+
(session.handlerCapture ??= /* @__PURE__ */ new Map()).set(`${v.method}\0${v.path}`, v);
|
|
160
|
+
}
|
|
161
|
+
function captureSet(loc, partial) {
|
|
162
|
+
const { method, path, slot } = loc;
|
|
158
163
|
if (!isValidatorCapturing()) return;
|
|
159
164
|
const capture = activeSession?.capture;
|
|
160
165
|
if (!capture) return;
|
|
@@ -165,18 +170,6 @@ function captureEntry({ method, path, slot }) {
|
|
|
165
170
|
path,
|
|
166
171
|
slot
|
|
167
172
|
});
|
|
168
|
-
return e;
|
|
169
|
-
}
|
|
170
|
-
/** @internal shared with `aot-capture.ts` (`beginValidatorCapture`). */
|
|
171
|
-
const aotActivationError = () => /* @__PURE__ */ new Error("Elysia AOT capture module is not activated.");
|
|
172
|
-
function captureHandler(v) {
|
|
173
|
-
if (!isValidatorCapturing()) return;
|
|
174
|
-
const session = activeSession;
|
|
175
|
-
if (!session) return;
|
|
176
|
-
(session.handlerCapture ??= /* @__PURE__ */ new Map()).set(`${v.method}\0${v.path}`, v);
|
|
177
|
-
}
|
|
178
|
-
function captureSet(loc, partial) {
|
|
179
|
-
const e = captureEntry(loc);
|
|
180
173
|
if (e) Object.assign(e, partial);
|
|
181
174
|
}
|
|
182
175
|
const captureGet = (loc) => activeSession?.capture?.get(`${loc.method}_${loc.path}_${loc.slot}`);
|