elysia 2.0.0-exp.47 → 2.0.0-exp.49
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.js +16 -5
- package/dist/adapter/bun/index.mjs +17 -6
- package/dist/base.d.ts +27 -2
- package/dist/base.js +101 -41
- package/dist/base.mjs +101 -41
- package/dist/compile/aot-capture.js +11 -1
- package/dist/compile/aot-capture.mjs +11 -1
- package/dist/compile/aot.js +1 -0
- package/dist/compile/aot.mjs +1 -0
- package/dist/compile/handler/descriptor.js +4 -3
- package/dist/compile/handler/descriptor.mjs +5 -4
- package/dist/compile/handler/index.js +2 -1
- package/dist/compile/handler/index.mjs +2 -1
- package/dist/compile/handler/jit.js +4 -2
- package/dist/compile/handler/jit.mjs +4 -2
- package/dist/compile/handler/reconstruct.d.ts +1 -1
- package/dist/compile/handler/reconstruct.js +12 -3
- package/dist/compile/handler/reconstruct.mjs +13 -4
- package/dist/compile/lexer.d.ts +1 -1
- package/dist/generation.d.ts +11 -1
- package/dist/generation.js +17 -1
- package/dist/generation.mjs +13 -1
- package/dist/handler/fetch.js +4 -4
- package/dist/handler/fetch.mjs +4 -4
- package/dist/package.js +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugin/aot/core.d.ts +13 -0
- package/dist/plugin/aot/source.js +28 -10
- package/dist/plugin/aot/source.mjs +28 -10
- package/dist/plugin/trace.d.ts +10 -0
- package/dist/plugin/trace.js +39 -0
- package/dist/plugin/trace.mjs +36 -0
- package/dist/plugin/websocket.d.ts +6 -0
- package/dist/plugin/websocket.js +61 -0
- package/dist/plugin/websocket.mjs +60 -0
- package/dist/trace.d.ts +6 -1
- package/dist/type/bridge-live.d.ts +2 -1
- package/dist/type/bridge-live.js +2 -0
- package/dist/type/bridge-live.mjs +2 -1
- package/dist/type/bridge.d.ts +2 -1
- package/dist/type/bridge.js +2 -0
- package/dist/type/bridge.mjs +2 -1
- package/dist/type/constants.d.ts +1 -1
- package/dist/types.d.ts +1 -14
- package/dist/ws/context.d.ts +1 -1
- package/dist/ws/route.d.ts +4 -2
- package/dist/ws/route.js +37 -3
- package/dist/ws/route.mjs +36 -4
- package/dist/ws/types.d.ts +46 -2
- package/package.json +9 -4
|
@@ -6,7 +6,6 @@ const require_adapter_web_standard_index = require('../web-standard/index.js');
|
|
|
6
6
|
const require_generation = require('../../generation.js');
|
|
7
7
|
const require_compile_handler_index = require('../../compile/handler/index.js');
|
|
8
8
|
const require_route_table = require('../../route-table.js');
|
|
9
|
-
const require_ws_route = require('../../ws/route.js');
|
|
10
9
|
|
|
11
10
|
//#region src/adapter/bun/index.ts
|
|
12
11
|
const nativeStaticMethods = new Set([
|
|
@@ -29,6 +28,16 @@ function collectStaticRoutes(app) {
|
|
|
29
28
|
if (!table || !length) return;
|
|
30
29
|
const methods = table.method;
|
|
31
30
|
const paths = table.path;
|
|
31
|
+
const handlers = table.handler;
|
|
32
|
+
let hasCandidate = false;
|
|
33
|
+
for (let i = 0; i < length; i++) {
|
|
34
|
+
const h = handlers[i];
|
|
35
|
+
if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
|
|
36
|
+
if (!nativeStaticMethods.has(methods[i])) continue;
|
|
37
|
+
hasCandidate = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
if (!hasCandidate) return;
|
|
32
41
|
const ready = require_utils.nullObject();
|
|
33
42
|
const strictPath = frozenRoot["~config"]?.strictPath === true;
|
|
34
43
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -58,6 +67,8 @@ function collectStaticRoutes(app) {
|
|
|
58
67
|
const path = paths[i];
|
|
59
68
|
if (seen.get(method + " " + path) !== i) continue;
|
|
60
69
|
if (!nativeStaticMethods.has(method)) continue;
|
|
70
|
+
const h = handlers[i];
|
|
71
|
+
if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
|
|
61
72
|
const value = require_compile_handler_index.buildNativeStaticResponse(require_route_table.routeRow(table, i), app);
|
|
62
73
|
if (!value) continue;
|
|
63
74
|
add(method, path, value);
|
|
@@ -98,11 +109,11 @@ const BunAdapter = require_adapter_index.createAdapter({
|
|
|
98
109
|
} catch (error) {
|
|
99
110
|
console.warn("[Elysia] Native static promotion was skipped:", error);
|
|
100
111
|
}
|
|
101
|
-
const hasWs = app["~hasWS"];
|
|
102
112
|
let websocket;
|
|
103
|
-
if (
|
|
104
|
-
const
|
|
105
|
-
|
|
113
|
+
if (app["~hasWS"]) {
|
|
114
|
+
const resolved = require_generation.resolvedWsOf(app);
|
|
115
|
+
if (!resolved) throw new Error("[Elysia] internal: WebSocket routes are present but no capability provider was resolved.");
|
|
116
|
+
websocket = resolved.config ? Object.assign(resolved.provider.buildGlobalWSHandler(), resolved.config) : resolved.provider.buildGlobalWSHandler();
|
|
106
117
|
}
|
|
107
118
|
return {
|
|
108
119
|
fetch,
|
|
@@ -2,10 +2,9 @@ import { createAdapter } from "../index.mjs";
|
|
|
2
2
|
import { isDynamicRegex, needEncodeRegex } from "../../constants.mjs";
|
|
3
3
|
import { flattenChain, getLoosePath, nullObject } from "../../utils.mjs";
|
|
4
4
|
import { WebStandardAdapter } from "../web-standard/index.mjs";
|
|
5
|
-
import { frozenRootOf } from "../../generation.mjs";
|
|
5
|
+
import { frozenRootOf, resolvedWsOf } from "../../generation.mjs";
|
|
6
6
|
import { buildNativeStaticResponse } from "../../compile/handler/index.mjs";
|
|
7
7
|
import { routeRow } from "../../route-table.mjs";
|
|
8
|
-
import { buildGlobalWSHandler } from "../../ws/route.mjs";
|
|
9
8
|
|
|
10
9
|
//#region src/adapter/bun/index.ts
|
|
11
10
|
const nativeStaticMethods = new Set([
|
|
@@ -28,6 +27,16 @@ function collectStaticRoutes(app) {
|
|
|
28
27
|
if (!table || !length) return;
|
|
29
28
|
const methods = table.method;
|
|
30
29
|
const paths = table.path;
|
|
30
|
+
const handlers = table.handler;
|
|
31
|
+
let hasCandidate = false;
|
|
32
|
+
for (let i = 0; i < length; i++) {
|
|
33
|
+
const h = handlers[i];
|
|
34
|
+
if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
|
|
35
|
+
if (!nativeStaticMethods.has(methods[i])) continue;
|
|
36
|
+
hasCandidate = true;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
if (!hasCandidate) return;
|
|
31
40
|
const ready = nullObject();
|
|
32
41
|
const strictPath = frozenRoot["~config"]?.strictPath === true;
|
|
33
42
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -57,6 +66,8 @@ function collectStaticRoutes(app) {
|
|
|
57
66
|
const path = paths[i];
|
|
58
67
|
if (seen.get(method + " " + path) !== i) continue;
|
|
59
68
|
if (!nativeStaticMethods.has(method)) continue;
|
|
69
|
+
const h = handlers[i];
|
|
70
|
+
if (typeof h === "function" || h instanceof Error || h instanceof Promise) continue;
|
|
60
71
|
const value = buildNativeStaticResponse(routeRow(table, i), app);
|
|
61
72
|
if (!value) continue;
|
|
62
73
|
add(method, path, value);
|
|
@@ -97,11 +108,11 @@ const BunAdapter = createAdapter({
|
|
|
97
108
|
} catch (error) {
|
|
98
109
|
console.warn("[Elysia] Native static promotion was skipped:", error);
|
|
99
110
|
}
|
|
100
|
-
const hasWs = app["~hasWS"];
|
|
101
111
|
let websocket;
|
|
102
|
-
if (
|
|
103
|
-
const
|
|
104
|
-
|
|
112
|
+
if (app["~hasWS"]) {
|
|
113
|
+
const resolved = resolvedWsOf(app);
|
|
114
|
+
if (!resolved) throw new Error("[Elysia] internal: WebSocket routes are present but no capability provider was resolved.");
|
|
115
|
+
websocket = resolved.config ? Object.assign(resolved.provider.buildGlobalWSHandler(), resolved.config) : resolved.provider.buildGlobalWSHandler();
|
|
105
116
|
}
|
|
106
117
|
return {
|
|
107
118
|
fetch,
|
package/dist/base.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ElysiaStatus } from "./error.js";
|
|
2
|
-
import {
|
|
3
|
-
import { TraceHandler } from "./trace.js";
|
|
2
|
+
import { TraceCapability, TraceHandler } from "./trace.js";
|
|
4
3
|
import { ListenCallback, Serve, Server } from "./universal/server.js";
|
|
5
4
|
import { AddRoute, AddWSRoute, AfterHandler, AfterResponseHandler, AnyErrorConstructor, AnyLocalHook, BodyHandler, CompiledHandler, CreateEden, DefaultEphemeral, DefaultMetadata, DefaultSingleton, DefinitionBase, DocumentDecoration, ElysiaConfig, ElysiaHandlerToResponseSchemaAmbiguous, EphemeralType, ErrorDefinitionEntry, ErrorHandler, EventScope, ExcludeElysiaResponse, ExtractErrorFromHandle, GlobalHookReturn, GracefulHandler, GuardHookSingleton, GuardLocalHook, HTTPMethod, HistoryEntry, HookContextSchema, HookContextSingleton, InlineHandler, InlineHandlerNonMacro, InputSchema, InputSchemaKey, InternalRoute, IntersectIfObjectSchema, JoinPath, LocalHook, LocalHookReturn, Macro, MacroSchemaChannel, MacroToContext, MacroToProperty, MapResponse, MaybeArray, MaybePromise, MergeElysiaInstances, MergeSchema, MergeScopedSchemas, MetadataBase, NonResolvableMacroKey, ObjectMacroDefs, OptionalHandler, PluginHookReturn, PreHandler, Prettify, PublicRoute, ResolveRouteErrors, RouteBase, ScopedHookReturn, ScopedMapDeriveReturn, SingletonBase, StaticMapAliases, TransformHandler, UnionResponseStatus, UnwrapRoute, WrapFn } from "./types.js";
|
|
6
5
|
import { ChainNode } from "./utils.js";
|
|
7
6
|
import { Context, ErrorContext, LifecycleContext } from "./context.js";
|
|
8
7
|
import { AnySchema } from "./type/types.js";
|
|
9
8
|
import { AotFingerprint, CompilerSession, ProgramId } from "./compile/aot.js";
|
|
9
|
+
import { WSCapability, WSHandlerResponse, WSLocalHook, WSMessageHandler, WSOptions, WSOptionsEntry } from "./ws/types.js";
|
|
10
10
|
import { RouteTable } from "./route-table.js";
|
|
11
11
|
import { Generation } from "./generation.js";
|
|
12
12
|
import Memoirist from "memoirist";
|
|
@@ -39,8 +39,18 @@ 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
|
+
capability?: {
|
|
43
|
+
trace?: {
|
|
44
|
+
provider: TraceCapability;
|
|
45
|
+
};
|
|
46
|
+
ws?: {
|
|
47
|
+
provider: WSCapability;
|
|
48
|
+
options?: WSOptionsEntry[];
|
|
49
|
+
};
|
|
50
|
+
};
|
|
42
51
|
};
|
|
43
52
|
'~hookChain'?: ChainNode;
|
|
53
|
+
'~wsConfig'?: WSOptions;
|
|
44
54
|
server?: Server;
|
|
45
55
|
get history(): readonly HistoryEntry[];
|
|
46
56
|
get ['~routes'](): readonly InternalRoute[];
|
|
@@ -514,6 +524,21 @@ declare class Elysia<const in out BasePath extends string = '', const in out Sco
|
|
|
514
524
|
parser: Metadata['parser'];
|
|
515
525
|
response: Metadata['response'] & MacroContext['response'] & ElysiaHandlerToResponseSchemaAmbiguous<BeforeHandle> & ElysiaHandlerToResponseSchemaAmbiguous<AfterHandle> & ElysiaHandlerToResponseSchemaAmbiguous<ErrorHandle>;
|
|
516
526
|
}, {}, Ephemeral, Volatile>) => NewElysia): Elysia<BasePath, Scope, Singleton, Definitions, Metadata, Routes & NewElysia['~Routes'], Ephemeral, Volatile>;
|
|
527
|
+
/**
|
|
528
|
+
* Single idempotent capability resolver-accessor (README rev 2.1). Reads
|
|
529
|
+
* the merged `~ext.capability` channel — never mutated during a build — and
|
|
530
|
+
* throws when a capability is used but its provider was never registered.
|
|
531
|
+
* For `trace` the resolved view IS the nearest-root provider (merge already
|
|
532
|
+
* keeps it); for `ws` it additionally resolves the depth-precedence base
|
|
533
|
+
* options. Called at the start of every router build and by `compileHandler`
|
|
534
|
+
* before it reads the frozen root, so direct-compiler paths resolve without
|
|
535
|
+
* a prior seal.
|
|
536
|
+
*/
|
|
537
|
+
['~resolvedCapability'](kind: 'trace'): TraceCapability | undefined;
|
|
538
|
+
['~resolvedCapability'](kind: 'ws'): {
|
|
539
|
+
provider: WSCapability;
|
|
540
|
+
options: WSOptions | undefined;
|
|
541
|
+
} | undefined;
|
|
517
542
|
/**
|
|
518
543
|
* ### macro
|
|
519
544
|
* Declare a custom route property: applying it on a route or guard folds
|
package/dist/base.js
CHANGED
|
@@ -6,9 +6,9 @@ const require_utils = require('./utils.js');
|
|
|
6
6
|
const require_type_bridge = require('./type/bridge.js');
|
|
7
7
|
const require_universal_is_production = require('./universal/is-production.js');
|
|
8
8
|
const require_compile_aot = require('./compile/aot.js');
|
|
9
|
+
const require_generation = require('./generation.js');
|
|
9
10
|
const require_compile_handler_index = require('./compile/handler/index.js');
|
|
10
11
|
const require_route_table = require('./route-table.js');
|
|
11
|
-
const require_ws_route = require('./ws/route.js');
|
|
12
12
|
const require_adapter_bun_index = require('./adapter/bun/index.js');
|
|
13
13
|
const require_handler_fetch = require('./handler/fetch.js');
|
|
14
14
|
const require_compile_analysis_cache = require('./compile/analysis-cache.js');
|
|
@@ -57,20 +57,20 @@ var Elysia = class Elysia {
|
|
|
57
57
|
if (!this.#declaredRoutes?.length) return [];
|
|
58
58
|
const routes = this.#declaredRoutes;
|
|
59
59
|
if (!this["~ext"]?.macro && !this["~scopeChildren"]) return routes;
|
|
60
|
-
return routes.map((
|
|
61
|
-
const localHook =
|
|
62
|
-
if (!localHook) return
|
|
63
|
-
const resolved = require_compile_handler_index.resolveLocalHook(require_compile_handler_index.localMacroRoot(
|
|
64
|
-
if (resolved === localHook) return
|
|
60
|
+
return routes.map((r) => {
|
|
61
|
+
const localHook = r[4];
|
|
62
|
+
if (!localHook) return r;
|
|
63
|
+
const resolved = require_compile_handler_index.resolveLocalHook(require_compile_handler_index.localMacroRoot(r[7] ?? r[3] ?? this, this), localHook, this);
|
|
64
|
+
if (resolved === localHook) return r;
|
|
65
65
|
return [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
r[0],
|
|
67
|
+
r[1],
|
|
68
|
+
r[2],
|
|
69
|
+
r[3],
|
|
70
70
|
resolved,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
r[5],
|
|
72
|
+
r[6],
|
|
73
|
+
r[7]
|
|
74
74
|
];
|
|
75
75
|
});
|
|
76
76
|
}
|
|
@@ -385,6 +385,11 @@ var Elysia = class Elysia {
|
|
|
385
385
|
if (src.models) ext.models = Object.assign(require_utils.nullObject(), src.models);
|
|
386
386
|
if (src.macro) ext.macro = Object.create(src.macro);
|
|
387
387
|
if (src.parser) ext.parser = Object.assign(require_utils.nullObject(), src.parser);
|
|
388
|
+
if (src.capability) {
|
|
389
|
+
const cap = ext.capability = require_utils.nullObject();
|
|
390
|
+
if (src.capability.trace) cap.trace = src.capability.trace;
|
|
391
|
+
if (src.capability.ws) cap.ws = src.capability.ws;
|
|
392
|
+
}
|
|
388
393
|
}
|
|
389
394
|
if (isSchema) child.guard({ ...schemaOrRun });
|
|
390
395
|
callback(child);
|
|
@@ -395,6 +400,21 @@ var Elysia = class Elysia {
|
|
|
395
400
|
get #ext() {
|
|
396
401
|
return this["~ext"] ??= require_utils.nullObject();
|
|
397
402
|
}
|
|
403
|
+
["~resolvedCapability"](kind) {
|
|
404
|
+
if (kind === "ws") {
|
|
405
|
+
const ws = this["~ext"]?.capability?.ws;
|
|
406
|
+
const provider = ws?.provider;
|
|
407
|
+
if (this["~hasWS"] && !provider) throw new Error(require_generation.wsCapabilityRequired);
|
|
408
|
+
if (!provider) return;
|
|
409
|
+
return {
|
|
410
|
+
provider,
|
|
411
|
+
options: this["~hasWS"] && ws.options?.length ? provider.resolveOptions(ws.options) : void 0
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const provider = this["~ext"]?.capability?.trace?.provider;
|
|
415
|
+
if (this["~hasTrace"] && !provider) throw new Error(require_generation.traceCapabilityRequired);
|
|
416
|
+
return provider;
|
|
417
|
+
}
|
|
398
418
|
#ensureMacroTable() {
|
|
399
419
|
const ext = this.#ext;
|
|
400
420
|
if (ext.macro) return ext.macro;
|
|
@@ -620,7 +640,7 @@ var Elysia = class Elysia {
|
|
|
620
640
|
}
|
|
621
641
|
const hookChain = app["~hookChain"];
|
|
622
642
|
if (app["~ext"]) {
|
|
623
|
-
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup } = app["~ext"];
|
|
643
|
+
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, capability } = app["~ext"];
|
|
624
644
|
const ext = this["~ext"] ??= require_utils.nullObject();
|
|
625
645
|
if (decorator) {
|
|
626
646
|
const cloned = require_utils.clonePlainDecorators(decorator);
|
|
@@ -678,6 +698,48 @@ var Elysia = class Elysia {
|
|
|
678
698
|
ext.cleanup.push(fn);
|
|
679
699
|
}
|
|
680
700
|
} else ext.cleanup = cleanup.slice();
|
|
701
|
+
if (capability) {
|
|
702
|
+
const target = ext.capability ??= require_utils.nullObject();
|
|
703
|
+
if (capability.trace) {
|
|
704
|
+
const incoming = capability.trace.provider;
|
|
705
|
+
if (!target.trace) target.trace = { provider: incoming };
|
|
706
|
+
else if (target.trace.provider !== incoming) console.warn(`[Elysia] Duplicate trace capability providers detected:\n ${target.trace.provider.id}\n ${incoming.id}\nUsing the first; ensure a single copy of 'elysia/trace' is installed.`);
|
|
707
|
+
}
|
|
708
|
+
if (capability.ws) {
|
|
709
|
+
const incoming = capability.ws.provider;
|
|
710
|
+
const existing = target.ws;
|
|
711
|
+
const incomingOptions = capability.ws.options;
|
|
712
|
+
if (!existing) target.ws = {
|
|
713
|
+
provider: incoming,
|
|
714
|
+
options: incomingOptions?.length ? incomingOptions.map((entry) => ({
|
|
715
|
+
depth: entry.depth + 1,
|
|
716
|
+
value: entry.value,
|
|
717
|
+
origin: entry.origin
|
|
718
|
+
})) : void 0
|
|
719
|
+
};
|
|
720
|
+
else {
|
|
721
|
+
if (existing.provider !== incoming) console.warn(`[Elysia] Duplicate WebSocket capability providers detected:\n ${existing.provider.id}\n ${incoming.id}\nUsing the first; ensure a single copy of 'elysia/websocket' is installed.`);
|
|
722
|
+
if (incomingOptions?.length) {
|
|
723
|
+
const base = existing.options ?? [];
|
|
724
|
+
const seen = new Set(base.map((e) => e.origin));
|
|
725
|
+
let next;
|
|
726
|
+
for (const entry of incomingOptions) {
|
|
727
|
+
if (seen.has(entry.origin)) continue;
|
|
728
|
+
seen.add(entry.origin);
|
|
729
|
+
(next ??= base.slice()).push({
|
|
730
|
+
depth: entry.depth + 1,
|
|
731
|
+
value: entry.value,
|
|
732
|
+
origin: entry.origin
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
if (next) target.ws = {
|
|
736
|
+
provider: existing.provider,
|
|
737
|
+
options: next
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
681
743
|
}
|
|
682
744
|
if (app.#hasPlugin || app.#hasGlobal || hookChain) {
|
|
683
745
|
let pluginEvents;
|
|
@@ -1088,9 +1150,11 @@ var Elysia = class Elysia {
|
|
|
1088
1150
|
throw routeError;
|
|
1089
1151
|
}
|
|
1090
1152
|
this.#compiled[index] = handler;
|
|
1153
|
+
let releasedNow = false;
|
|
1091
1154
|
if (this.#jitColdRemaining !== void 0 && --this.#jitColdRemaining === 0) {
|
|
1092
1155
|
require_compile_aot.Compiled.release(this["~programId"]);
|
|
1093
1156
|
this.#jitColdRemaining = void 0;
|
|
1157
|
+
releasedNow = true;
|
|
1094
1158
|
}
|
|
1095
1159
|
const aliases = this.#jitAliases?.[index];
|
|
1096
1160
|
if (aliases) {
|
|
@@ -1098,9 +1162,16 @@ var Elysia = class Elysia {
|
|
|
1098
1162
|
const map = this["~map"][aliases.method] ??= require_utils.nullObject();
|
|
1099
1163
|
for (let p = 0; p < aliases.paths.length; p++) map[aliases.paths[p]] = handler;
|
|
1100
1164
|
} else this.#saveHandler(materialized[0], materialized[1], handler);
|
|
1101
|
-
if (
|
|
1102
|
-
|
|
1103
|
-
|
|
1165
|
+
if (releasedNow) {
|
|
1166
|
+
this.#jitRoute = void 0;
|
|
1167
|
+
this.#jitStatic = void 0;
|
|
1168
|
+
this.#jitAliases = void 0;
|
|
1169
|
+
this.#jitTable = void 0;
|
|
1170
|
+
} else {
|
|
1171
|
+
if (this.#jitRoute) this.#jitRoute[index] = void 0;
|
|
1172
|
+
if (this.#jitStatic) this.#jitStatic[index] = void 0;
|
|
1173
|
+
if (this.#jitAliases) this.#jitAliases[index] = void 0;
|
|
1174
|
+
}
|
|
1104
1175
|
return handler(context);
|
|
1105
1176
|
}
|
|
1106
1177
|
#saveHandler(method, path, handler) {
|
|
@@ -1216,10 +1287,6 @@ var Elysia = class Elysia {
|
|
|
1216
1287
|
const previousJitStatic = this.#jitStatic;
|
|
1217
1288
|
const previousJitAliases = this.#jitAliases;
|
|
1218
1289
|
const previousHasDynamicWS = this["~hasDynamicWS"];
|
|
1219
|
-
const config = this["~config"];
|
|
1220
|
-
const hadWebsocket = !!config && Object.hasOwn(config, "websocket");
|
|
1221
|
-
const previousWebsocket = config?.websocket;
|
|
1222
|
-
const websocketSnapshot = previousWebsocket && typeof previousWebsocket === "object" ? { ...previousWebsocket } : previousWebsocket;
|
|
1223
1290
|
const previousGeneration = this["~generation"];
|
|
1224
1291
|
this["~map"] = void 0;
|
|
1225
1292
|
this["~router"] = void 0;
|
|
@@ -1258,11 +1325,6 @@ var Elysia = class Elysia {
|
|
|
1258
1325
|
this.#jitAliases = previousJitAliases;
|
|
1259
1326
|
this["~hasDynamicWS"] = previousHasDynamicWS;
|
|
1260
1327
|
this["~generation"] = previousGeneration;
|
|
1261
|
-
if (config) {
|
|
1262
|
-
this["~config"] = config;
|
|
1263
|
-
if (hadWebsocket) config.websocket = websocketSnapshot;
|
|
1264
|
-
else delete config.websocket;
|
|
1265
|
-
} else this["~config"] = void 0;
|
|
1266
1328
|
throw error;
|
|
1267
1329
|
} finally {
|
|
1268
1330
|
require_compile_aot.endCompilerSession(this, compilerSession, !buildSucceeded);
|
|
@@ -1278,17 +1340,17 @@ var Elysia = class Elysia {
|
|
|
1278
1340
|
"~hookChain": this["~hookChain"],
|
|
1279
1341
|
"~scopeChildren": this["~scopeChildren"],
|
|
1280
1342
|
"~applyMacro": this["~applyMacro"].bind(this),
|
|
1281
|
-
"~programId": this["~programId"]
|
|
1343
|
+
"~programId": this["~programId"],
|
|
1344
|
+
"~wsConfig": this["~wsConfig"]
|
|
1282
1345
|
};
|
|
1283
1346
|
if (require_universal_is_production.isProduction() && !require_compile_aot.Capture.isAotBuildEnv()) {
|
|
1284
1347
|
if (this["~config"]?.precompile) require_compile_aot.Compiled.release(this["~programId"]);
|
|
1285
1348
|
else {
|
|
1286
|
-
const
|
|
1349
|
+
const table = this["~routeTable"];
|
|
1350
|
+
const routeCount = table?.length ?? this["~routes"].length;
|
|
1287
1351
|
let cold = routeCount;
|
|
1288
1352
|
const compiled = this.#compiled;
|
|
1289
|
-
if (compiled)
|
|
1290
|
-
for (let i = 0; i < routeCount; i++) if (compiled[i] !== void 0) cold--;
|
|
1291
|
-
}
|
|
1353
|
+
for (let i = 0; i < routeCount; i++) if (table !== void 0 && (table.flags[i] & require_route_table.RouteFlag.WS) !== 0 || compiled?.[i] !== void 0) cold--;
|
|
1292
1354
|
if (cold <= 0) require_compile_aot.Compiled.release(this["~programId"]);
|
|
1293
1355
|
else this.#jitColdRemaining = cold;
|
|
1294
1356
|
}
|
|
@@ -1305,6 +1367,9 @@ var Elysia = class Elysia {
|
|
|
1305
1367
|
}
|
|
1306
1368
|
#buildRouterUnsafe() {
|
|
1307
1369
|
const precompile = this["~config"]?.precompile;
|
|
1370
|
+
this["~resolvedCapability"]("trace");
|
|
1371
|
+
const wsCap = this["~resolvedCapability"]("ws");
|
|
1372
|
+
let wsConfig;
|
|
1308
1373
|
this.#initMap();
|
|
1309
1374
|
const methods = this["~map"];
|
|
1310
1375
|
const table = this["~routeTable"] = require_route_table.buildRouteTable(this["~routes"]);
|
|
@@ -1341,9 +1406,10 @@ var Elysia = class Elysia {
|
|
|
1341
1406
|
const routePath = path[i];
|
|
1342
1407
|
const routeFlags = flags[i];
|
|
1343
1408
|
if ((routeFlags & require_route_table.RouteFlag.WS) !== 0) {
|
|
1344
|
-
const ws =
|
|
1409
|
+
const ws = wsCap.provider.buildWSRoute(require_route_table.routeRow(table, i), this);
|
|
1345
1410
|
const handler = ws[0];
|
|
1346
1411
|
const options = ws[1];
|
|
1412
|
+
if (wsConfig === void 0 && wsCap.options) wsConfig = wsCap.options;
|
|
1347
1413
|
if ((routeFlags & require_route_table.RouteFlag.Dynamic) !== 0) {
|
|
1348
1414
|
(this["~router"] ??= new memoirist.default({ loosePath: isLoose })).add("WS", routePath, handler);
|
|
1349
1415
|
this["~hasDynamicWS"] = true;
|
|
@@ -1357,15 +1423,8 @@ var Elysia = class Elysia {
|
|
|
1357
1423
|
}
|
|
1358
1424
|
}
|
|
1359
1425
|
if (options && require_utils.isNotEmpty(options)) {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
if (existing && require_universal_constants.isBun) {
|
|
1363
|
-
for (const key in options) if (key in existing && existing[key] !== options[key]) {
|
|
1364
|
-
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).`);
|
|
1365
|
-
console.warn((/* @__PURE__ */ new Error()).stack);
|
|
1366
|
-
}
|
|
1367
|
-
Object.assign(existing, options);
|
|
1368
|
-
} else this["~config"].websocket = options;
|
|
1426
|
+
wsConfig ??= require_utils.nullObject();
|
|
1427
|
+
wsCap.provider.accumulateOptions(wsConfig, options, routePath);
|
|
1369
1428
|
}
|
|
1370
1429
|
continue;
|
|
1371
1430
|
}
|
|
@@ -1405,6 +1464,7 @@ var Elysia = class Elysia {
|
|
|
1405
1464
|
for (let p = 0; p < paths.length; p++) map[paths[p]] = handler;
|
|
1406
1465
|
}
|
|
1407
1466
|
}
|
|
1467
|
+
this["~wsConfig"] = wsConfig;
|
|
1408
1468
|
}
|
|
1409
1469
|
#fetchFn;
|
|
1410
1470
|
get fetch() {
|
package/dist/base.mjs
CHANGED
|
@@ -4,9 +4,9 @@ import { clonePlainDecorators, clonePlainDeep, coalesceStandaloneSchemas, create
|
|
|
4
4
|
import { Ref } from "./type/bridge.mjs";
|
|
5
5
|
import { isProduction } from "./universal/is-production.mjs";
|
|
6
6
|
import { Capture, Compiled, beginCompilerSession, createAotFingerprint, createProgramId, endCompilerSession } from "./compile/aot.mjs";
|
|
7
|
+
import { traceCapabilityRequired, wsCapabilityRequired } from "./generation.mjs";
|
|
7
8
|
import { compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook } from "./compile/handler/index.mjs";
|
|
8
9
|
import { RouteFlag, buildRouteTable, routeRow } from "./route-table.mjs";
|
|
9
|
-
import { buildWSRoute } from "./ws/route.mjs";
|
|
10
10
|
import { BunAdapter } from "./adapter/bun/index.mjs";
|
|
11
11
|
import { applyHoc, createFetchHandler } from "./handler/fetch.mjs";
|
|
12
12
|
import { clearAuthoringAnalysisCaches } from "./compile/analysis-cache.mjs";
|
|
@@ -54,20 +54,20 @@ var Elysia = class Elysia {
|
|
|
54
54
|
if (!this.#declaredRoutes?.length) return [];
|
|
55
55
|
const routes = this.#declaredRoutes;
|
|
56
56
|
if (!this["~ext"]?.macro && !this["~scopeChildren"]) return routes;
|
|
57
|
-
return routes.map((
|
|
58
|
-
const localHook =
|
|
59
|
-
if (!localHook) return
|
|
60
|
-
const resolved = resolveLocalHook(localMacroRoot(
|
|
61
|
-
if (resolved === localHook) return
|
|
57
|
+
return routes.map((r) => {
|
|
58
|
+
const localHook = r[4];
|
|
59
|
+
if (!localHook) return r;
|
|
60
|
+
const resolved = resolveLocalHook(localMacroRoot(r[7] ?? r[3] ?? this, this), localHook, this);
|
|
61
|
+
if (resolved === localHook) return r;
|
|
62
62
|
return [
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
r[0],
|
|
64
|
+
r[1],
|
|
65
|
+
r[2],
|
|
66
|
+
r[3],
|
|
67
67
|
resolved,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
r[5],
|
|
69
|
+
r[6],
|
|
70
|
+
r[7]
|
|
71
71
|
];
|
|
72
72
|
});
|
|
73
73
|
}
|
|
@@ -382,6 +382,11 @@ var Elysia = class Elysia {
|
|
|
382
382
|
if (src.models) ext.models = Object.assign(nullObject(), src.models);
|
|
383
383
|
if (src.macro) ext.macro = Object.create(src.macro);
|
|
384
384
|
if (src.parser) ext.parser = Object.assign(nullObject(), src.parser);
|
|
385
|
+
if (src.capability) {
|
|
386
|
+
const cap = ext.capability = nullObject();
|
|
387
|
+
if (src.capability.trace) cap.trace = src.capability.trace;
|
|
388
|
+
if (src.capability.ws) cap.ws = src.capability.ws;
|
|
389
|
+
}
|
|
385
390
|
}
|
|
386
391
|
if (isSchema) child.guard({ ...schemaOrRun });
|
|
387
392
|
callback(child);
|
|
@@ -392,6 +397,21 @@ var Elysia = class Elysia {
|
|
|
392
397
|
get #ext() {
|
|
393
398
|
return this["~ext"] ??= nullObject();
|
|
394
399
|
}
|
|
400
|
+
["~resolvedCapability"](kind) {
|
|
401
|
+
if (kind === "ws") {
|
|
402
|
+
const ws = this["~ext"]?.capability?.ws;
|
|
403
|
+
const provider = ws?.provider;
|
|
404
|
+
if (this["~hasWS"] && !provider) throw new Error(wsCapabilityRequired);
|
|
405
|
+
if (!provider) return;
|
|
406
|
+
return {
|
|
407
|
+
provider,
|
|
408
|
+
options: this["~hasWS"] && ws.options?.length ? provider.resolveOptions(ws.options) : void 0
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
const provider = this["~ext"]?.capability?.trace?.provider;
|
|
412
|
+
if (this["~hasTrace"] && !provider) throw new Error(traceCapabilityRequired);
|
|
413
|
+
return provider;
|
|
414
|
+
}
|
|
395
415
|
#ensureMacroTable() {
|
|
396
416
|
const ext = this.#ext;
|
|
397
417
|
if (ext.macro) return ext.macro;
|
|
@@ -617,7 +637,7 @@ var Elysia = class Elysia {
|
|
|
617
637
|
}
|
|
618
638
|
const hookChain = app["~hookChain"];
|
|
619
639
|
if (app["~ext"]) {
|
|
620
|
-
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup } = app["~ext"];
|
|
640
|
+
const { decorator, store, headers, models, parser, macro, error, hoc, setup, cleanup, capability } = app["~ext"];
|
|
621
641
|
const ext = this["~ext"] ??= nullObject();
|
|
622
642
|
if (decorator) {
|
|
623
643
|
const cloned = clonePlainDecorators(decorator);
|
|
@@ -675,6 +695,48 @@ var Elysia = class Elysia {
|
|
|
675
695
|
ext.cleanup.push(fn);
|
|
676
696
|
}
|
|
677
697
|
} else ext.cleanup = cleanup.slice();
|
|
698
|
+
if (capability) {
|
|
699
|
+
const target = ext.capability ??= nullObject();
|
|
700
|
+
if (capability.trace) {
|
|
701
|
+
const incoming = capability.trace.provider;
|
|
702
|
+
if (!target.trace) target.trace = { provider: incoming };
|
|
703
|
+
else if (target.trace.provider !== incoming) console.warn(`[Elysia] Duplicate trace capability providers detected:\n ${target.trace.provider.id}\n ${incoming.id}\nUsing the first; ensure a single copy of 'elysia/trace' is installed.`);
|
|
704
|
+
}
|
|
705
|
+
if (capability.ws) {
|
|
706
|
+
const incoming = capability.ws.provider;
|
|
707
|
+
const existing = target.ws;
|
|
708
|
+
const incomingOptions = capability.ws.options;
|
|
709
|
+
if (!existing) target.ws = {
|
|
710
|
+
provider: incoming,
|
|
711
|
+
options: incomingOptions?.length ? incomingOptions.map((entry) => ({
|
|
712
|
+
depth: entry.depth + 1,
|
|
713
|
+
value: entry.value,
|
|
714
|
+
origin: entry.origin
|
|
715
|
+
})) : void 0
|
|
716
|
+
};
|
|
717
|
+
else {
|
|
718
|
+
if (existing.provider !== incoming) console.warn(`[Elysia] Duplicate WebSocket capability providers detected:\n ${existing.provider.id}\n ${incoming.id}\nUsing the first; ensure a single copy of 'elysia/websocket' is installed.`);
|
|
719
|
+
if (incomingOptions?.length) {
|
|
720
|
+
const base = existing.options ?? [];
|
|
721
|
+
const seen = new Set(base.map((e) => e.origin));
|
|
722
|
+
let next;
|
|
723
|
+
for (const entry of incomingOptions) {
|
|
724
|
+
if (seen.has(entry.origin)) continue;
|
|
725
|
+
seen.add(entry.origin);
|
|
726
|
+
(next ??= base.slice()).push({
|
|
727
|
+
depth: entry.depth + 1,
|
|
728
|
+
value: entry.value,
|
|
729
|
+
origin: entry.origin
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
if (next) target.ws = {
|
|
733
|
+
provider: existing.provider,
|
|
734
|
+
options: next
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
678
740
|
}
|
|
679
741
|
if (app.#hasPlugin || app.#hasGlobal || hookChain) {
|
|
680
742
|
let pluginEvents;
|
|
@@ -1085,9 +1147,11 @@ var Elysia = class Elysia {
|
|
|
1085
1147
|
throw routeError;
|
|
1086
1148
|
}
|
|
1087
1149
|
this.#compiled[index] = handler;
|
|
1150
|
+
let releasedNow = false;
|
|
1088
1151
|
if (this.#jitColdRemaining !== void 0 && --this.#jitColdRemaining === 0) {
|
|
1089
1152
|
Compiled.release(this["~programId"]);
|
|
1090
1153
|
this.#jitColdRemaining = void 0;
|
|
1154
|
+
releasedNow = true;
|
|
1091
1155
|
}
|
|
1092
1156
|
const aliases = this.#jitAliases?.[index];
|
|
1093
1157
|
if (aliases) {
|
|
@@ -1095,9 +1159,16 @@ var Elysia = class Elysia {
|
|
|
1095
1159
|
const map = this["~map"][aliases.method] ??= nullObject();
|
|
1096
1160
|
for (let p = 0; p < aliases.paths.length; p++) map[aliases.paths[p]] = handler;
|
|
1097
1161
|
} else this.#saveHandler(materialized[0], materialized[1], handler);
|
|
1098
|
-
if (
|
|
1099
|
-
|
|
1100
|
-
|
|
1162
|
+
if (releasedNow) {
|
|
1163
|
+
this.#jitRoute = void 0;
|
|
1164
|
+
this.#jitStatic = void 0;
|
|
1165
|
+
this.#jitAliases = void 0;
|
|
1166
|
+
this.#jitTable = void 0;
|
|
1167
|
+
} else {
|
|
1168
|
+
if (this.#jitRoute) this.#jitRoute[index] = void 0;
|
|
1169
|
+
if (this.#jitStatic) this.#jitStatic[index] = void 0;
|
|
1170
|
+
if (this.#jitAliases) this.#jitAliases[index] = void 0;
|
|
1171
|
+
}
|
|
1101
1172
|
return handler(context);
|
|
1102
1173
|
}
|
|
1103
1174
|
#saveHandler(method, path, handler) {
|
|
@@ -1213,10 +1284,6 @@ var Elysia = class Elysia {
|
|
|
1213
1284
|
const previousJitStatic = this.#jitStatic;
|
|
1214
1285
|
const previousJitAliases = this.#jitAliases;
|
|
1215
1286
|
const previousHasDynamicWS = this["~hasDynamicWS"];
|
|
1216
|
-
const config = this["~config"];
|
|
1217
|
-
const hadWebsocket = !!config && Object.hasOwn(config, "websocket");
|
|
1218
|
-
const previousWebsocket = config?.websocket;
|
|
1219
|
-
const websocketSnapshot = previousWebsocket && typeof previousWebsocket === "object" ? { ...previousWebsocket } : previousWebsocket;
|
|
1220
1287
|
const previousGeneration = this["~generation"];
|
|
1221
1288
|
this["~map"] = void 0;
|
|
1222
1289
|
this["~router"] = void 0;
|
|
@@ -1255,11 +1322,6 @@ var Elysia = class Elysia {
|
|
|
1255
1322
|
this.#jitAliases = previousJitAliases;
|
|
1256
1323
|
this["~hasDynamicWS"] = previousHasDynamicWS;
|
|
1257
1324
|
this["~generation"] = previousGeneration;
|
|
1258
|
-
if (config) {
|
|
1259
|
-
this["~config"] = config;
|
|
1260
|
-
if (hadWebsocket) config.websocket = websocketSnapshot;
|
|
1261
|
-
else delete config.websocket;
|
|
1262
|
-
} else this["~config"] = void 0;
|
|
1263
1325
|
throw error;
|
|
1264
1326
|
} finally {
|
|
1265
1327
|
endCompilerSession(this, compilerSession, !buildSucceeded);
|
|
@@ -1275,17 +1337,17 @@ var Elysia = class Elysia {
|
|
|
1275
1337
|
"~hookChain": this["~hookChain"],
|
|
1276
1338
|
"~scopeChildren": this["~scopeChildren"],
|
|
1277
1339
|
"~applyMacro": this["~applyMacro"].bind(this),
|
|
1278
|
-
"~programId": this["~programId"]
|
|
1340
|
+
"~programId": this["~programId"],
|
|
1341
|
+
"~wsConfig": this["~wsConfig"]
|
|
1279
1342
|
};
|
|
1280
1343
|
if (isProduction() && !Capture.isAotBuildEnv()) {
|
|
1281
1344
|
if (this["~config"]?.precompile) Compiled.release(this["~programId"]);
|
|
1282
1345
|
else {
|
|
1283
|
-
const
|
|
1346
|
+
const table = this["~routeTable"];
|
|
1347
|
+
const routeCount = table?.length ?? this["~routes"].length;
|
|
1284
1348
|
let cold = routeCount;
|
|
1285
1349
|
const compiled = this.#compiled;
|
|
1286
|
-
if (compiled)
|
|
1287
|
-
for (let i = 0; i < routeCount; i++) if (compiled[i] !== void 0) cold--;
|
|
1288
|
-
}
|
|
1350
|
+
for (let i = 0; i < routeCount; i++) if (table !== void 0 && (table.flags[i] & RouteFlag.WS) !== 0 || compiled?.[i] !== void 0) cold--;
|
|
1289
1351
|
if (cold <= 0) Compiled.release(this["~programId"]);
|
|
1290
1352
|
else this.#jitColdRemaining = cold;
|
|
1291
1353
|
}
|
|
@@ -1302,6 +1364,9 @@ var Elysia = class Elysia {
|
|
|
1302
1364
|
}
|
|
1303
1365
|
#buildRouterUnsafe() {
|
|
1304
1366
|
const precompile = this["~config"]?.precompile;
|
|
1367
|
+
this["~resolvedCapability"]("trace");
|
|
1368
|
+
const wsCap = this["~resolvedCapability"]("ws");
|
|
1369
|
+
let wsConfig;
|
|
1305
1370
|
this.#initMap();
|
|
1306
1371
|
const methods = this["~map"];
|
|
1307
1372
|
const table = this["~routeTable"] = buildRouteTable(this["~routes"]);
|
|
@@ -1338,9 +1403,10 @@ var Elysia = class Elysia {
|
|
|
1338
1403
|
const routePath = path[i];
|
|
1339
1404
|
const routeFlags = flags[i];
|
|
1340
1405
|
if ((routeFlags & RouteFlag.WS) !== 0) {
|
|
1341
|
-
const ws = buildWSRoute(routeRow(table, i), this);
|
|
1406
|
+
const ws = wsCap.provider.buildWSRoute(routeRow(table, i), this);
|
|
1342
1407
|
const handler = ws[0];
|
|
1343
1408
|
const options = ws[1];
|
|
1409
|
+
if (wsConfig === void 0 && wsCap.options) wsConfig = wsCap.options;
|
|
1344
1410
|
if ((routeFlags & RouteFlag.Dynamic) !== 0) {
|
|
1345
1411
|
(this["~router"] ??= new Memoirist({ loosePath: isLoose })).add("WS", routePath, handler);
|
|
1346
1412
|
this["~hasDynamicWS"] = true;
|
|
@@ -1354,15 +1420,8 @@ var Elysia = class Elysia {
|
|
|
1354
1420
|
}
|
|
1355
1421
|
}
|
|
1356
1422
|
if (options && isNotEmpty(options)) {
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
if (existing && isBun) {
|
|
1360
|
-
for (const key in options) if (key in existing && existing[key] !== options[key]) {
|
|
1361
|
-
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).`);
|
|
1362
|
-
console.warn((/* @__PURE__ */ new Error()).stack);
|
|
1363
|
-
}
|
|
1364
|
-
Object.assign(existing, options);
|
|
1365
|
-
} else this["~config"].websocket = options;
|
|
1423
|
+
wsConfig ??= nullObject();
|
|
1424
|
+
wsCap.provider.accumulateOptions(wsConfig, options, routePath);
|
|
1366
1425
|
}
|
|
1367
1426
|
continue;
|
|
1368
1427
|
}
|
|
@@ -1402,6 +1461,7 @@ var Elysia = class Elysia {
|
|
|
1402
1461
|
for (let p = 0; p < paths.length; p++) map[paths[p]] = handler;
|
|
1403
1462
|
}
|
|
1404
1463
|
}
|
|
1464
|
+
this["~wsConfig"] = wsConfig;
|
|
1405
1465
|
}
|
|
1406
1466
|
#fetchFn;
|
|
1407
1467
|
get fetch() {
|