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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//#region src/compile/jit-probe.d.ts
|
|
2
2
|
/** A handler-JIT entry point the frozen replay can trip over. */
|
|
3
|
-
type JITProbeReason = 'sucrose' | 'handler:new-function';
|
|
3
|
+
type JITProbeReason = 'sucrose' | 'handler:new-function' | 'handler:indexed-duplicate';
|
|
4
4
|
interface JITProbeResult {
|
|
5
|
-
/**
|
|
5
|
+
/** No route needs sucrose, handler codegen, or indexed duplicate replay. */
|
|
6
6
|
jit: boolean;
|
|
7
7
|
reasons: JITProbeReason[];
|
|
8
8
|
}
|
package/dist/context.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { AnyElysia } from "./base.js";
|
|
|
9
9
|
|
|
10
10
|
//#region src/context.d.ts
|
|
11
11
|
declare function createBaseContext(app: AnyElysia): any;
|
|
12
|
-
declare function clearContextCache(): void;
|
|
12
|
+
declare function clearContextCache(app?: AnyElysia): void;
|
|
13
13
|
declare function createContext(app: AnyElysia): new (request: Request) => Context;
|
|
14
14
|
interface ContextBase<in out Route extends RouteSchema, in out Singleton extends SingletonBase> {
|
|
15
15
|
server: Server | null;
|
package/dist/context.js
CHANGED
|
@@ -41,7 +41,11 @@ function createBaseContext(app) {
|
|
|
41
41
|
Object.defineProperty(Decorator.prototype, "defer", defer);
|
|
42
42
|
return Decorator;
|
|
43
43
|
}
|
|
44
|
-
function clearContextCache() {
|
|
44
|
+
function clearContextCache(app) {
|
|
45
|
+
if (app !== void 0) {
|
|
46
|
+
contextCache.delete(app);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
45
49
|
contextCache = /* @__PURE__ */ new WeakMap();
|
|
46
50
|
sharedEmptyDecorator = null;
|
|
47
51
|
sharedEmptyContext = null;
|
package/dist/context.mjs
CHANGED
|
@@ -40,7 +40,11 @@ function createBaseContext(app) {
|
|
|
40
40
|
Object.defineProperty(Decorator.prototype, "defer", defer);
|
|
41
41
|
return Decorator;
|
|
42
42
|
}
|
|
43
|
-
function clearContextCache() {
|
|
43
|
+
function clearContextCache(app) {
|
|
44
|
+
if (app !== void 0) {
|
|
45
|
+
contextCache.delete(app);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
44
48
|
contextCache = /* @__PURE__ */ new WeakMap();
|
|
45
49
|
sharedEmptyDecorator = null;
|
|
46
50
|
sharedEmptyContext = null;
|
package/dist/package.js
CHANGED
package/dist/package.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { CapturedValidator } from "../../compile/aot.js";
|
|
1
2
|
import { JITProbeResult } from "../../compile/jit-probe.js";
|
|
2
|
-
import { AotTarget } from "./source.js";
|
|
3
|
+
import { AotModuleCondition, AotTarget } from "./source.js";
|
|
3
4
|
|
|
4
5
|
//#region src/plugin/aot/core.d.ts
|
|
5
6
|
interface ElysiaAotOptions {
|
|
@@ -93,6 +94,8 @@ interface ElysiaAotOptions {
|
|
|
93
94
|
verbose?: boolean;
|
|
94
95
|
}
|
|
95
96
|
declare const resolveEntry: (entry: string) => string;
|
|
97
|
+
/** @internal Resolve the package condition used to evaluate an AOT entry. */
|
|
98
|
+
declare const resolveEntryModuleKind: (entry: string) => "cjs" | "esm";
|
|
96
99
|
/** Runtime handler-JIT module a strip build can replace with a throwing stub. */
|
|
97
100
|
interface StubPlan {
|
|
98
101
|
/** Stub the internal handler codegen module. */
|
|
@@ -279,7 +282,7 @@ declare const OVERRIDE_MAP: Record<string, {
|
|
|
279
282
|
leaf: string;
|
|
280
283
|
export: string;
|
|
281
284
|
}>;
|
|
282
|
-
declare function generateVirtualType(typeSpecifier?: string): Promise<string>;
|
|
285
|
+
declare function generateVirtualType(typeSpecifier?: string, moduleCondition?: AotModuleCondition): Promise<string>;
|
|
283
286
|
interface CompiledArtifacts {
|
|
284
287
|
source: string;
|
|
285
288
|
/** Handler-JIT modules detection proved safe to stub for this app. */
|
|
@@ -305,9 +308,12 @@ declare const getAotWorkerDiagnostics: () => {
|
|
|
305
308
|
*/
|
|
306
309
|
declare function siblingModuleExt(moduleUrl: string): '.mjs' | '.js' | '.ts';
|
|
307
310
|
/** @internal Re-evaluate an entry in a disposable worker for watch rebuilds. */
|
|
308
|
-
declare function generateCompiledArtifactsIsolated(file: string, options?: ElysiaAotOptions): Promise<CompiledArtifacts>;
|
|
309
|
-
|
|
311
|
+
declare function generateCompiledArtifactsIsolated(file: string, options?: ElysiaAotOptions, moduleCondition?: string): Promise<CompiledArtifacts>;
|
|
312
|
+
type ValidatorSlotIdentity = Pick<CapturedValidator, 'method' | 'path' | 'slot'>;
|
|
313
|
+
/** @internal Exact logical-slot gate used by AOT mode selection. */
|
|
314
|
+
declare function validatorSlotSetsMatch(expected: readonly ValidatorSlotIdentity[], captured: readonly ValidatorSlotIdentity[]): boolean;
|
|
315
|
+
declare function generateCompiledArtifacts(file: string, options?: ElysiaAotOptions, moduleCondition?: string): Promise<CompiledArtifacts>;
|
|
310
316
|
declare const SOURCE_REGEX: RegExp;
|
|
311
317
|
declare const realPath: (path: string) => string;
|
|
312
318
|
//#endregion
|
|
313
|
-
export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, BridgeMode, CompiledArtifacts, ELYSIA_MODULE_FILTER, ElysiaAotOptions, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, StubPlan, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, getAotWorkerDiagnostics, makeElysiaModuleFilterRegex, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, rewriteIsProductionCalls, siblingModuleExt };
|
|
319
|
+
export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, BridgeMode, CompiledArtifacts, ELYSIA_MODULE_FILTER, ElysiaAotOptions, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, StubPlan, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, getAotWorkerDiagnostics, makeElysiaModuleFilterRegex, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, resolveEntryModuleKind, rewriteIsProductionCalls, siblingModuleExt, validatorSlotSetsMatch };
|
package/dist/plugin/aot/core.js
CHANGED
|
@@ -20,6 +20,28 @@ function findPackageRoot(from = process.cwd()) {
|
|
|
20
20
|
return dir;
|
|
21
21
|
}
|
|
22
22
|
const resolveEntry = (entry) => (0, node_path.resolve)(findPackageRoot(), entry);
|
|
23
|
+
/** @internal Resolve the package condition used to evaluate an AOT entry. */
|
|
24
|
+
const resolveEntryModuleKind = (entry) => {
|
|
25
|
+
const entryPath = resolveEntry(entry);
|
|
26
|
+
switch ((0, node_path.extname)(entryPath)) {
|
|
27
|
+
case ".cjs":
|
|
28
|
+
case ".cts": return "cjs";
|
|
29
|
+
case ".mjs":
|
|
30
|
+
case ".mts":
|
|
31
|
+
case ".ts":
|
|
32
|
+
case ".tsx": return "esm";
|
|
33
|
+
case ".js":
|
|
34
|
+
case ".jsx": {
|
|
35
|
+
const packagePath = (0, node_path.join)(findPackageRoot((0, node_path.dirname)(entryPath)), "package.json");
|
|
36
|
+
if (!(0, node_fs.existsSync)(packagePath)) return "cjs";
|
|
37
|
+
const pkg = JSON.parse((0, node_fs.readFileSync)(packagePath, "utf8"));
|
|
38
|
+
if (pkg.type === "module") return "esm";
|
|
39
|
+
if (pkg.type === void 0 || pkg.type === "commonjs") return "cjs";
|
|
40
|
+
throw new Error(`[elysia-aot] package.json has unsupported "type" ${JSON.stringify(pkg.type)} for JavaScript entry ${JSON.stringify(entryPath)}.`);
|
|
41
|
+
}
|
|
42
|
+
default: throw new Error(`[elysia-aot] entry ${JSON.stringify(entryPath)} has an ambiguous module condition. Use a .cjs/.cts CommonJS entry or a .mjs/.mts/.ts/.tsx ESM entry; .js/.jsx follows the nearest package.json "type".`);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
23
45
|
const NO_STUB = {
|
|
24
46
|
jit: false,
|
|
25
47
|
ws: false,
|
|
@@ -302,17 +324,20 @@ const OVERRIDE_MAP = {
|
|
|
302
324
|
}
|
|
303
325
|
};
|
|
304
326
|
const requireFromHere = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
327
|
+
const moduleMeta = {};
|
|
328
|
+
const loadedModuleCondition = require("url").pathToFileURL(__filename).href.endsWith(".js") ? "cjs" : "esm";
|
|
329
|
+
const resolveSpecifier = (specifier, moduleCondition) => {
|
|
330
|
+
if (moduleCondition === "cjs") return requireFromHere.resolve(specifier);
|
|
331
|
+
if (moduleMeta.resolve) {
|
|
332
|
+
const url = moduleMeta.resolve(specifier);
|
|
309
333
|
return url.startsWith("file://") ? new URL(url).pathname : url;
|
|
310
334
|
}
|
|
335
|
+
if (moduleCondition === "esm") throw new Error("[elysia-aot] CommonJS-loaded build plugin cannot resolve the ESM package condition. Load the build plugin through import for an ESM entry.");
|
|
311
336
|
return requireFromHere.resolve(specifier);
|
|
312
337
|
};
|
|
313
|
-
async function generateVirtualType(typeSpecifier = "elysia/type") {
|
|
314
|
-
const typePath = resolveSpecifier(typeSpecifier);
|
|
315
|
-
const typeboxPath = resolveSpecifier("typebox/type");
|
|
338
|
+
async function generateVirtualType(typeSpecifier = "elysia/type", moduleCondition) {
|
|
339
|
+
const typePath = resolveSpecifier(typeSpecifier, moduleCondition);
|
|
340
|
+
const typeboxPath = resolveSpecifier("typebox/type", moduleCondition);
|
|
316
341
|
const ext = typePath.slice(typePath.lastIndexOf("."));
|
|
317
342
|
const leafDir = (0, node_path.join)((0, node_path.dirname)(typePath), "elysia");
|
|
318
343
|
const typebox = await import((0, node_url.pathToFileURL)(typeboxPath).href);
|
|
@@ -348,12 +373,13 @@ const workerUrl = () => {
|
|
|
348
373
|
return new URL("./worker" + siblingModuleExt(moduleUrl), moduleUrl);
|
|
349
374
|
};
|
|
350
375
|
/** @internal Re-evaluate an entry in a disposable worker for watch rebuilds. */
|
|
351
|
-
async function generateCompiledArtifactsIsolated(file, options) {
|
|
376
|
+
async function generateCompiledArtifactsIsolated(file, options, moduleCondition = resolveEntryModuleKind(file)) {
|
|
352
377
|
const entry = resolveEntry(file);
|
|
353
378
|
console.warn("[elysia-aot] re-evaluating \"" + entry + "\" in an isolated worker for rebuild. Top-level side effects run only inside the worker.");
|
|
354
379
|
const worker = new node_worker_threads.Worker(workerUrl(), { workerData: {
|
|
355
380
|
file: entry,
|
|
356
|
-
options
|
|
381
|
+
options,
|
|
382
|
+
moduleCondition
|
|
357
383
|
} });
|
|
358
384
|
activeGenerationWorkers++;
|
|
359
385
|
const exit = new Promise((resolve) => worker.once("exit", resolve));
|
|
@@ -383,13 +409,14 @@ async function generateCompiledArtifactsIsolated(file, options) {
|
|
|
383
409
|
}
|
|
384
410
|
}
|
|
385
411
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
if (
|
|
392
|
-
|
|
412
|
+
const validatorSlotKey = ({ method, path, slot }) => `${method}\0${path}\0${slot}`;
|
|
413
|
+
/** @internal Exact logical-slot gate used by AOT mode selection. */
|
|
414
|
+
function validatorSlotSetsMatch(expected, captured) {
|
|
415
|
+
const expectedKeys = new Set(expected.map(validatorSlotKey));
|
|
416
|
+
const capturedKeys = new Set(captured.map(validatorSlotKey));
|
|
417
|
+
if (expectedKeys.size !== capturedKeys.size) return false;
|
|
418
|
+
for (const key of expectedKeys) if (!capturedKeys.has(key)) return false;
|
|
419
|
+
return true;
|
|
393
420
|
}
|
|
394
421
|
/**
|
|
395
422
|
* The manifest is one flat `method -> path` table with no per-app namespace,
|
|
@@ -406,7 +433,8 @@ const assertNoMount = (app, entry) => {
|
|
|
406
433
|
if (!mounted.length) return;
|
|
407
434
|
throw new Error(`[elysia-aot] "${entry}" mounts a sub-app (${mounted.join(", ")}). AOT cannot compile a mounted sub-app. Compose with .use() instead of .mount(), or disable AOT plugin`);
|
|
408
435
|
};
|
|
409
|
-
async function generateCompiledArtifacts(file, options) {
|
|
436
|
+
async function generateCompiledArtifacts(file, options, moduleCondition = resolveEntryModuleKind(file)) {
|
|
437
|
+
if (moduleCondition !== loadedModuleCondition) throw new Error(`[elysia-aot] entry uses the ${moduleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""} package condition, but the AOT build plugin was loaded through ${loadedModuleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""}; entry: ${JSON.stringify(resolveEntry(file))}. Load the plugin through ${moduleCondition === "cjs" ? "require()" : "import"} so capture and generated registration share one Elysia module instance.`);
|
|
410
438
|
const previousAotBuild = process.env.ELYSIA_AOT_BUILD;
|
|
411
439
|
process.env.ELYSIA_AOT_BUILD = "1";
|
|
412
440
|
const previousAotVerbose = process.env.ELYSIA_AOT_VERBOSE;
|
|
@@ -415,7 +443,7 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
415
443
|
try {
|
|
416
444
|
const entry = resolveEntry(file);
|
|
417
445
|
const entryReal = realPath(entry);
|
|
418
|
-
if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options);
|
|
446
|
+
if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options, moduleCondition);
|
|
419
447
|
_importedEntries.add(entryReal);
|
|
420
448
|
const mod = await import(entry);
|
|
421
449
|
const app = mod.app ?? mod.default;
|
|
@@ -424,6 +452,7 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
424
452
|
assertNoMount(typedApp, entry);
|
|
425
453
|
const sourceOptions = {
|
|
426
454
|
register: true,
|
|
455
|
+
moduleCondition,
|
|
427
456
|
registerFrom: options?.registerFrom,
|
|
428
457
|
reconstructFrom: options?.reconstructFrom,
|
|
429
458
|
lazy: options?.lazy,
|
|
@@ -450,31 +479,48 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
450
479
|
const hasWS = !!typedApp["~hasWS"] || !!typedApp["~routes"]?.some((route) => route?.[0] === "WS");
|
|
451
480
|
const history = typedApp["~routes"] ?? [];
|
|
452
481
|
const mayTrace = !!typedApp["~hasTrace"] || history.some((route) => (route?.[4])?.trace?.length || route?.[2]?.["~mount"]);
|
|
453
|
-
|
|
482
|
+
const expectedSlots = [];
|
|
483
|
+
const declaredTypeBoxSlots = /* @__PURE__ */ new Set();
|
|
454
484
|
let routesForbidSeal = false;
|
|
455
485
|
let wsCookie = false;
|
|
456
486
|
for (const route of history) {
|
|
487
|
+
const method = route[0];
|
|
488
|
+
const path = route[1];
|
|
489
|
+
const expectTypeBoxSlot = (slot) => {
|
|
490
|
+
const identity = {
|
|
491
|
+
method,
|
|
492
|
+
path,
|
|
493
|
+
slot
|
|
494
|
+
};
|
|
495
|
+
const key = validatorSlotKey(identity);
|
|
496
|
+
if (declaredTypeBoxSlots.has(key)) routesForbidSeal = true;
|
|
497
|
+
else {
|
|
498
|
+
declaredTypeBoxSlots.add(key);
|
|
499
|
+
expectedSlots.push(identity);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
457
502
|
const [, , , instance, hook, appHook, inheritedChain, macroScope] = route;
|
|
458
503
|
const hooks = require_compile_handler_index.composeRouteHook(instance, hook, appHook, inheritedChain, typedApp, macroScope);
|
|
459
504
|
if (route[0] === "WS" && (hook?.cookie !== void 0 || hooks?.cookie !== void 0)) wsCookie = true;
|
|
460
505
|
if (!hooks) continue;
|
|
461
506
|
let routeHasTypeBoxDirectSlot = false;
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
]) {
|
|
469
|
-
const value = hooks[slot];
|
|
470
|
-
if (value === void 0) continue;
|
|
471
|
-
if (require_compile_handler_frozen_validator.isStandardSchema(value)) continue;
|
|
507
|
+
const classify = (schema, slot) => {
|
|
508
|
+
if (schema === void 0) {
|
|
509
|
+
routesForbidSeal = true;
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
if (require_compile_handler_frozen_validator.isStandardSchema(schema)) return;
|
|
472
513
|
routeHasTypeBoxDirectSlot = true;
|
|
473
|
-
|
|
514
|
+
expectTypeBoxSlot(slot);
|
|
515
|
+
};
|
|
516
|
+
for (const slot of require_compile_handler_frozen_validator.REQUEST_SLOTS) {
|
|
517
|
+
const value = hooks[slot];
|
|
518
|
+
if (value !== void 0) classify(require_compile_handler_frozen_validator.resolveModelRef(value, typedApp), slot);
|
|
474
519
|
}
|
|
475
|
-
if (hooks.response !== void 0
|
|
476
|
-
|
|
477
|
-
|
|
520
|
+
if (hooks.response !== void 0) {
|
|
521
|
+
const response = require_compile_handler_frozen_validator.resolveModelRef(hooks.response, typedApp);
|
|
522
|
+
if (require_compile_handler_frozen_validator.isResponseMap(response)) for (const status in response) classify(require_compile_handler_frozen_validator.resolveModelRef(response[status], typedApp), `response:${status}`);
|
|
523
|
+
else classify(response, "response:200");
|
|
478
524
|
}
|
|
479
525
|
const mergeSchemas = hooks.schemas;
|
|
480
526
|
if (Array.isArray(mergeSchemas) && mergeSchemas.length > 0) {
|
|
@@ -482,13 +528,13 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
482
528
|
}
|
|
483
529
|
}
|
|
484
530
|
if (typedApp["~config"]?.normalize === "typebox") routesForbidSeal = true;
|
|
485
|
-
const
|
|
486
|
-
const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.length > 0 || artifacts.validators.length > 0) && !routesForbidSeal &&
|
|
531
|
+
const validatorSlotsMatch = validatorSlotSetsMatch(expectedSlots, artifacts.validators);
|
|
532
|
+
const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.length > 0 || artifacts.validators.length > 0) && !routesForbidSeal && validatorSlotsMatch && artifacts.validators.every((v) => v.bridgeFree === true), artifacts.handlers.length === 0 && artifacts.validators.length === 0, adapterStub, productionStub, wsCookie);
|
|
487
533
|
if (options?.target === "workerd") {
|
|
488
534
|
if (!report.jit) throw new Error(`[elysia-aot] target 'workerd' but handler JIT is still reachable (${report.reasons.join(", ") || "unknown"}). Every route must be captured into the AOT manifest.`);
|
|
489
|
-
if (
|
|
535
|
+
if (!validatorSlotsMatch) console.warn("[elysia-aot] target 'workerd': captured validator slots do not exactly match declared slots; unfrozen slots compile at runtime and will fail on workerd.");
|
|
490
536
|
}
|
|
491
|
-
const virtualType = mode === "off" ? void 0 : await generateVirtualType("elysia/type");
|
|
537
|
+
const virtualType = mode === "off" ? void 0 : await generateVirtualType("elysia/type", moduleCondition);
|
|
492
538
|
return {
|
|
493
539
|
source: artifacts.source,
|
|
494
540
|
stub,
|
|
@@ -533,5 +579,7 @@ exports.planFromReport = planFromReport;
|
|
|
533
579
|
exports.realPath = realPath;
|
|
534
580
|
exports.resolveElysiaRoot = resolveElysiaRoot;
|
|
535
581
|
exports.resolveEntry = resolveEntry;
|
|
582
|
+
exports.resolveEntryModuleKind = resolveEntryModuleKind;
|
|
536
583
|
exports.rewriteIsProductionCalls = rewriteIsProductionCalls;
|
|
537
|
-
exports.siblingModuleExt = siblingModuleExt;
|
|
584
|
+
exports.siblingModuleExt = siblingModuleExt;
|
|
585
|
+
exports.validatorSlotSetsMatch = validatorSlotSetsMatch;
|
package/dist/plugin/aot/core.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { isStandardSchema, mergeSchemasAllStandard } from "../../compile/handler/frozen-validator.mjs";
|
|
1
|
+
import { REQUEST_SLOTS, isResponseMap, isStandardSchema, mergeSchemasAllStandard, resolveModelRef } from "../../compile/handler/frozen-validator.mjs";
|
|
2
2
|
import { composeRouteHook } from "../../compile/handler/index.mjs";
|
|
3
3
|
import { captureArtifacts, compileToSource, replayStubbability } from "./source.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
|
-
import { existsSync, realpathSync } from "node:fs";
|
|
6
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
6
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
8
|
import { Worker } from "node:worker_threads";
|
|
9
9
|
|
|
@@ -18,6 +18,28 @@ function findPackageRoot(from = process.cwd()) {
|
|
|
18
18
|
return dir;
|
|
19
19
|
}
|
|
20
20
|
const resolveEntry = (entry) => resolve(findPackageRoot(), entry);
|
|
21
|
+
/** @internal Resolve the package condition used to evaluate an AOT entry. */
|
|
22
|
+
const resolveEntryModuleKind = (entry) => {
|
|
23
|
+
const entryPath = resolveEntry(entry);
|
|
24
|
+
switch (extname(entryPath)) {
|
|
25
|
+
case ".cjs":
|
|
26
|
+
case ".cts": return "cjs";
|
|
27
|
+
case ".mjs":
|
|
28
|
+
case ".mts":
|
|
29
|
+
case ".ts":
|
|
30
|
+
case ".tsx": return "esm";
|
|
31
|
+
case ".js":
|
|
32
|
+
case ".jsx": {
|
|
33
|
+
const packagePath = join(findPackageRoot(dirname(entryPath)), "package.json");
|
|
34
|
+
if (!existsSync(packagePath)) return "cjs";
|
|
35
|
+
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
36
|
+
if (pkg.type === "module") return "esm";
|
|
37
|
+
if (pkg.type === void 0 || pkg.type === "commonjs") return "cjs";
|
|
38
|
+
throw new Error(`[elysia-aot] package.json has unsupported "type" ${JSON.stringify(pkg.type)} for JavaScript entry ${JSON.stringify(entryPath)}.`);
|
|
39
|
+
}
|
|
40
|
+
default: throw new Error(`[elysia-aot] entry ${JSON.stringify(entryPath)} has an ambiguous module condition. Use a .cjs/.cts CommonJS entry or a .mjs/.mts/.ts/.tsx ESM entry; .js/.jsx follows the nearest package.json "type".`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
21
43
|
const NO_STUB = {
|
|
22
44
|
jit: false,
|
|
23
45
|
ws: false,
|
|
@@ -300,17 +322,20 @@ const OVERRIDE_MAP = {
|
|
|
300
322
|
}
|
|
301
323
|
};
|
|
302
324
|
const requireFromHere = createRequire(import.meta.url);
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
325
|
+
const moduleMeta = import.meta;
|
|
326
|
+
const loadedModuleCondition = import.meta.url.endsWith(".js") ? "cjs" : "esm";
|
|
327
|
+
const resolveSpecifier = (specifier, moduleCondition) => {
|
|
328
|
+
if (moduleCondition === "cjs") return requireFromHere.resolve(specifier);
|
|
329
|
+
if (moduleMeta.resolve) {
|
|
330
|
+
const url = moduleMeta.resolve(specifier);
|
|
307
331
|
return url.startsWith("file://") ? new URL(url).pathname : url;
|
|
308
332
|
}
|
|
333
|
+
if (moduleCondition === "esm") throw new Error("[elysia-aot] CommonJS-loaded build plugin cannot resolve the ESM package condition. Load the build plugin through import for an ESM entry.");
|
|
309
334
|
return requireFromHere.resolve(specifier);
|
|
310
335
|
};
|
|
311
|
-
async function generateVirtualType(typeSpecifier = "elysia/type") {
|
|
312
|
-
const typePath = resolveSpecifier(typeSpecifier);
|
|
313
|
-
const typeboxPath = resolveSpecifier("typebox/type");
|
|
336
|
+
async function generateVirtualType(typeSpecifier = "elysia/type", moduleCondition) {
|
|
337
|
+
const typePath = resolveSpecifier(typeSpecifier, moduleCondition);
|
|
338
|
+
const typeboxPath = resolveSpecifier("typebox/type", moduleCondition);
|
|
314
339
|
const ext = typePath.slice(typePath.lastIndexOf("."));
|
|
315
340
|
const leafDir = join(dirname(typePath), "elysia");
|
|
316
341
|
const typebox = await import(pathToFileURL(typeboxPath).href);
|
|
@@ -346,12 +371,13 @@ const workerUrl = () => {
|
|
|
346
371
|
return new URL("./worker" + siblingModuleExt(moduleUrl), moduleUrl);
|
|
347
372
|
};
|
|
348
373
|
/** @internal Re-evaluate an entry in a disposable worker for watch rebuilds. */
|
|
349
|
-
async function generateCompiledArtifactsIsolated(file, options) {
|
|
374
|
+
async function generateCompiledArtifactsIsolated(file, options, moduleCondition = resolveEntryModuleKind(file)) {
|
|
350
375
|
const entry = resolveEntry(file);
|
|
351
376
|
console.warn("[elysia-aot] re-evaluating \"" + entry + "\" in an isolated worker for rebuild. Top-level side effects run only inside the worker.");
|
|
352
377
|
const worker = new Worker(workerUrl(), { workerData: {
|
|
353
378
|
file: entry,
|
|
354
|
-
options
|
|
379
|
+
options,
|
|
380
|
+
moduleCondition
|
|
355
381
|
} });
|
|
356
382
|
activeGenerationWorkers++;
|
|
357
383
|
const exit = new Promise((resolve) => worker.once("exit", resolve));
|
|
@@ -381,13 +407,14 @@ async function generateCompiledArtifactsIsolated(file, options) {
|
|
|
381
407
|
}
|
|
382
408
|
}
|
|
383
409
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const
|
|
389
|
-
if (
|
|
390
|
-
|
|
410
|
+
const validatorSlotKey = ({ method, path, slot }) => `${method}\0${path}\0${slot}`;
|
|
411
|
+
/** @internal Exact logical-slot gate used by AOT mode selection. */
|
|
412
|
+
function validatorSlotSetsMatch(expected, captured) {
|
|
413
|
+
const expectedKeys = new Set(expected.map(validatorSlotKey));
|
|
414
|
+
const capturedKeys = new Set(captured.map(validatorSlotKey));
|
|
415
|
+
if (expectedKeys.size !== capturedKeys.size) return false;
|
|
416
|
+
for (const key of expectedKeys) if (!capturedKeys.has(key)) return false;
|
|
417
|
+
return true;
|
|
391
418
|
}
|
|
392
419
|
/**
|
|
393
420
|
* The manifest is one flat `method -> path` table with no per-app namespace,
|
|
@@ -404,7 +431,8 @@ const assertNoMount = (app, entry) => {
|
|
|
404
431
|
if (!mounted.length) return;
|
|
405
432
|
throw new Error(`[elysia-aot] "${entry}" mounts a sub-app (${mounted.join(", ")}). AOT cannot compile a mounted sub-app. Compose with .use() instead of .mount(), or disable AOT plugin`);
|
|
406
433
|
};
|
|
407
|
-
async function generateCompiledArtifacts(file, options) {
|
|
434
|
+
async function generateCompiledArtifacts(file, options, moduleCondition = resolveEntryModuleKind(file)) {
|
|
435
|
+
if (moduleCondition !== loadedModuleCondition) throw new Error(`[elysia-aot] entry uses the ${moduleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""} package condition, but the AOT build plugin was loaded through ${loadedModuleCondition === "cjs" ? "CommonJS \"require\"" : "ESM \"import\""}; entry: ${JSON.stringify(resolveEntry(file))}. Load the plugin through ${moduleCondition === "cjs" ? "require()" : "import"} so capture and generated registration share one Elysia module instance.`);
|
|
408
436
|
const previousAotBuild = process.env.ELYSIA_AOT_BUILD;
|
|
409
437
|
process.env.ELYSIA_AOT_BUILD = "1";
|
|
410
438
|
const previousAotVerbose = process.env.ELYSIA_AOT_VERBOSE;
|
|
@@ -413,7 +441,7 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
413
441
|
try {
|
|
414
442
|
const entry = resolveEntry(file);
|
|
415
443
|
const entryReal = realPath(entry);
|
|
416
|
-
if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options);
|
|
444
|
+
if (_importedEntries.has(entryReal)) return generateCompiledArtifactsIsolated(file, options, moduleCondition);
|
|
417
445
|
_importedEntries.add(entryReal);
|
|
418
446
|
const mod = await import(entry);
|
|
419
447
|
const app = mod.app ?? mod.default;
|
|
@@ -422,6 +450,7 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
422
450
|
assertNoMount(typedApp, entry);
|
|
423
451
|
const sourceOptions = {
|
|
424
452
|
register: true,
|
|
453
|
+
moduleCondition,
|
|
425
454
|
registerFrom: options?.registerFrom,
|
|
426
455
|
reconstructFrom: options?.reconstructFrom,
|
|
427
456
|
lazy: options?.lazy,
|
|
@@ -448,31 +477,48 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
448
477
|
const hasWS = !!typedApp["~hasWS"] || !!typedApp["~routes"]?.some((route) => route?.[0] === "WS");
|
|
449
478
|
const history = typedApp["~routes"] ?? [];
|
|
450
479
|
const mayTrace = !!typedApp["~hasTrace"] || history.some((route) => (route?.[4])?.trace?.length || route?.[2]?.["~mount"]);
|
|
451
|
-
|
|
480
|
+
const expectedSlots = [];
|
|
481
|
+
const declaredTypeBoxSlots = /* @__PURE__ */ new Set();
|
|
452
482
|
let routesForbidSeal = false;
|
|
453
483
|
let wsCookie = false;
|
|
454
484
|
for (const route of history) {
|
|
485
|
+
const method = route[0];
|
|
486
|
+
const path = route[1];
|
|
487
|
+
const expectTypeBoxSlot = (slot) => {
|
|
488
|
+
const identity = {
|
|
489
|
+
method,
|
|
490
|
+
path,
|
|
491
|
+
slot
|
|
492
|
+
};
|
|
493
|
+
const key = validatorSlotKey(identity);
|
|
494
|
+
if (declaredTypeBoxSlots.has(key)) routesForbidSeal = true;
|
|
495
|
+
else {
|
|
496
|
+
declaredTypeBoxSlots.add(key);
|
|
497
|
+
expectedSlots.push(identity);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
455
500
|
const [, , , instance, hook, appHook, inheritedChain, macroScope] = route;
|
|
456
501
|
const hooks = composeRouteHook(instance, hook, appHook, inheritedChain, typedApp, macroScope);
|
|
457
502
|
if (route[0] === "WS" && (hook?.cookie !== void 0 || hooks?.cookie !== void 0)) wsCookie = true;
|
|
458
503
|
if (!hooks) continue;
|
|
459
504
|
let routeHasTypeBoxDirectSlot = false;
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
]) {
|
|
467
|
-
const value = hooks[slot];
|
|
468
|
-
if (value === void 0) continue;
|
|
469
|
-
if (isStandardSchema(value)) continue;
|
|
505
|
+
const classify = (schema, slot) => {
|
|
506
|
+
if (schema === void 0) {
|
|
507
|
+
routesForbidSeal = true;
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (isStandardSchema(schema)) return;
|
|
470
511
|
routeHasTypeBoxDirectSlot = true;
|
|
471
|
-
|
|
512
|
+
expectTypeBoxSlot(slot);
|
|
513
|
+
};
|
|
514
|
+
for (const slot of REQUEST_SLOTS) {
|
|
515
|
+
const value = hooks[slot];
|
|
516
|
+
if (value !== void 0) classify(resolveModelRef(value, typedApp), slot);
|
|
472
517
|
}
|
|
473
|
-
if (hooks.response !== void 0
|
|
474
|
-
|
|
475
|
-
|
|
518
|
+
if (hooks.response !== void 0) {
|
|
519
|
+
const response = resolveModelRef(hooks.response, typedApp);
|
|
520
|
+
if (isResponseMap(response)) for (const status in response) classify(resolveModelRef(response[status], typedApp), `response:${status}`);
|
|
521
|
+
else classify(response, "response:200");
|
|
476
522
|
}
|
|
477
523
|
const mergeSchemas = hooks.schemas;
|
|
478
524
|
if (Array.isArray(mergeSchemas) && mergeSchemas.length > 0) {
|
|
@@ -480,13 +526,13 @@ async function generateCompiledArtifacts(file, options) {
|
|
|
480
526
|
}
|
|
481
527
|
}
|
|
482
528
|
if (typedApp["~config"]?.normalize === "typebox") routesForbidSeal = true;
|
|
483
|
-
const
|
|
484
|
-
const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.length > 0 || artifacts.validators.length > 0) && !routesForbidSeal &&
|
|
529
|
+
const validatorSlotsMatch = validatorSlotSetsMatch(expectedSlots, artifacts.validators);
|
|
530
|
+
const { plan: stub, mode } = planFromReport(strip, report, hasWS, mayTrace, aliases, (artifacts.handlers.length > 0 || artifacts.validators.length > 0) && !routesForbidSeal && validatorSlotsMatch && artifacts.validators.every((v) => v.bridgeFree === true), artifacts.handlers.length === 0 && artifacts.validators.length === 0, adapterStub, productionStub, wsCookie);
|
|
485
531
|
if (options?.target === "workerd") {
|
|
486
532
|
if (!report.jit) throw new Error(`[elysia-aot] target 'workerd' but handler JIT is still reachable (${report.reasons.join(", ") || "unknown"}). Every route must be captured into the AOT manifest.`);
|
|
487
|
-
if (
|
|
533
|
+
if (!validatorSlotsMatch) console.warn("[elysia-aot] target 'workerd': captured validator slots do not exactly match declared slots; unfrozen slots compile at runtime and will fail on workerd.");
|
|
488
534
|
}
|
|
489
|
-
const virtualType = mode === "off" ? void 0 : await generateVirtualType("elysia/type");
|
|
535
|
+
const virtualType = mode === "off" ? void 0 : await generateVirtualType("elysia/type", moduleCondition);
|
|
490
536
|
return {
|
|
491
537
|
source: artifacts.source,
|
|
492
538
|
stub,
|
|
@@ -510,4 +556,4 @@ const realPath = (path) => {
|
|
|
510
556
|
};
|
|
511
557
|
|
|
512
558
|
//#endregion
|
|
513
|
-
export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, ELYSIA_MODULE_FILTER, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, getAotWorkerDiagnostics, makeElysiaModuleFilterRegex, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, rewriteIsProductionCalls, siblingModuleExt };
|
|
559
|
+
export { ADAPTER_BUN_FILTER, ADAPTER_CONSTANTS_FILTER, ELYSIA_MODULE_FILTER, IS_PRODUCTION_FILTER, NO_STUB, OVERRIDE_MAP, SOURCE_REGEX, STUB_SOURCES, adapterConstantsSource, alignStubExtensions, bunAdapterStubSource, generateCompiledArtifacts, generateCompiledArtifactsIsolated, generateVirtualType, getAotWorkerDiagnostics, makeElysiaModuleFilterRegex, makeIsElysiaModule, planFromReport, realPath, resolveElysiaRoot, resolveEntry, resolveEntryModuleKind, rewriteIsProductionCalls, siblingModuleExt, validatorSlotSetsMatch };
|
|
@@ -28,7 +28,11 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
28
28
|
const aot = (entry, options) => ({
|
|
29
29
|
name: "elysia-aot",
|
|
30
30
|
async setup(build) {
|
|
31
|
-
const
|
|
31
|
+
const entryPath = require_plugin_aot_core.resolveEntry(entry);
|
|
32
|
+
const moduleCondition = require_plugin_aot_core.resolveEntryModuleKind(entryPath);
|
|
33
|
+
if (build.initialOptions?.conditions?.includes("types")) throw new Error("[elysia-aot] esbuild conditions includes 'types'; this selects declaration files as runtime inputs. Remove the conflicting condition.");
|
|
34
|
+
if (moduleCondition === "cjs" && build.initialOptions?.conditions?.includes("import")) throw new Error("[elysia-aot] esbuild conditions includes 'import' for a CommonJS entry; this would load two Elysia module instances. Remove the conflicting condition.");
|
|
35
|
+
const hooks = require_plugin_aot_hooks.createAotPluginHooks(entry, options, moduleCondition);
|
|
32
36
|
let initial = true;
|
|
33
37
|
build.onStart(async () => {
|
|
34
38
|
if (initial) {
|
|
@@ -39,8 +43,10 @@ const aot = (entry, options) => ({
|
|
|
39
43
|
});
|
|
40
44
|
await require_plugin_aot_hooks.setupAotOnLoad(build, hooks, {
|
|
41
45
|
readText: (path) => (0, node_fs_promises.readFile)(path, "utf8"),
|
|
42
|
-
resolveDir: (0, node_path.dirname)(
|
|
46
|
+
resolveDir: (0, node_path.dirname)(entryPath)
|
|
43
47
|
});
|
|
48
|
+
const allowedKinds = moduleCondition === "cjs" ? new Set(["require-call", "require-resolve"]) : new Set(["import-statement", "dynamic-import"]);
|
|
49
|
+
build.onResolve({ filter: /^elysia(?:\/.*)?$/ }, (args) => allowedKinds.has(args.kind) ? void 0 : { errors: [{ text: `[elysia-aot] ${args.path} uses esbuild edge kind ${JSON.stringify(args.kind)}, which conflicts with the ${JSON.stringify(moduleCondition)} entry module condition. Use one consistent import/require condition for Elysia.` }] });
|
|
44
50
|
}
|
|
45
51
|
});
|
|
46
52
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveEntry } from "./core.mjs";
|
|
1
|
+
import { resolveEntry, resolveEntryModuleKind } from "./core.mjs";
|
|
2
2
|
import { createAotPluginHooks, setupAotOnLoad } from "./hooks.mjs";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
@@ -26,7 +26,11 @@ import { readFile } from "node:fs/promises";
|
|
|
26
26
|
const aot = (entry, options) => ({
|
|
27
27
|
name: "elysia-aot",
|
|
28
28
|
async setup(build) {
|
|
29
|
-
const
|
|
29
|
+
const entryPath = resolveEntry(entry);
|
|
30
|
+
const moduleCondition = resolveEntryModuleKind(entryPath);
|
|
31
|
+
if (build.initialOptions?.conditions?.includes("types")) throw new Error("[elysia-aot] esbuild conditions includes 'types'; this selects declaration files as runtime inputs. Remove the conflicting condition.");
|
|
32
|
+
if (moduleCondition === "cjs" && build.initialOptions?.conditions?.includes("import")) throw new Error("[elysia-aot] esbuild conditions includes 'import' for a CommonJS entry; this would load two Elysia module instances. Remove the conflicting condition.");
|
|
33
|
+
const hooks = createAotPluginHooks(entry, options, moduleCondition);
|
|
30
34
|
let initial = true;
|
|
31
35
|
build.onStart(async () => {
|
|
32
36
|
if (initial) {
|
|
@@ -37,8 +41,10 @@ const aot = (entry, options) => ({
|
|
|
37
41
|
});
|
|
38
42
|
await setupAotOnLoad(build, hooks, {
|
|
39
43
|
readText: (path) => readFile(path, "utf8"),
|
|
40
|
-
resolveDir: dirname(
|
|
44
|
+
resolveDir: dirname(entryPath)
|
|
41
45
|
});
|
|
46
|
+
const allowedKinds = moduleCondition === "cjs" ? new Set(["require-call", "require-resolve"]) : new Set(["import-statement", "dynamic-import"]);
|
|
47
|
+
build.onResolve({ filter: /^elysia(?:\/.*)?$/ }, (args) => allowedKinds.has(args.kind) ? void 0 : { errors: [{ text: `[elysia-aot] ${args.path} uses esbuild edge kind ${JSON.stringify(args.kind)}, which conflicts with the ${JSON.stringify(moduleCondition)} entry module condition. Use one consistent import/require condition for Elysia.` }] });
|
|
42
48
|
}
|
|
43
49
|
});
|
|
44
50
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AotModuleCondition } from "./source.js";
|
|
1
2
|
import { ElysiaAotOptions } from "./core.js";
|
|
2
3
|
|
|
3
4
|
//#region src/plugin/aot/hooks.d.ts
|
|
@@ -9,7 +10,7 @@ interface AotPluginHooks {
|
|
|
9
10
|
transform(code: string, id: string): string | undefined | Promise<string | undefined>;
|
|
10
11
|
isTransformCandidate(id: string): boolean;
|
|
11
12
|
}
|
|
12
|
-
declare const createAotPluginHooks: (entry: string, options?: ElysiaAotOptions) => AotPluginHooks;
|
|
13
|
+
declare const createAotPluginHooks: (entry: string, options?: ElysiaAotOptions, moduleCondition?: AotModuleCondition) => AotPluginHooks;
|
|
13
14
|
interface AotOnLoadAdapterOptions {
|
|
14
15
|
/** Read a file's UTF-8 text (abstracted so Bun and esbuild can supply their own reader). */
|
|
15
16
|
readText: (path: string) => Promise<string>;
|