elysia 2.0.0-beta.20 → 2.0.0-beta.21
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/compile/aot.d.ts +8 -8
- package/dist/compile/aot.js +16 -14
- package/dist/compile/aot.mjs +14 -14
- package/dist/compile/handler/descriptor.js +2 -3
- package/dist/compile/handler/descriptor.mjs +2 -3
- package/dist/compile/handler/index.d.ts +2 -1
- package/dist/compile/handler/index.js +144 -24
- package/dist/compile/handler/index.mjs +146 -27
- package/dist/compile/handler/jit.d.ts +2 -0
- package/dist/compile/handler/jit.js +3 -2
- package/dist/compile/handler/jit.mjs +3 -2
- package/dist/compile/handler/reconstruct.js +3 -2
- package/dist/compile/handler/reconstruct.mjs +3 -2
- package/dist/cookie/config.d.ts +6 -2
- package/dist/cookie/config.js +68 -8
- package/dist/cookie/config.mjs +69 -10
- package/dist/cookie/utils.js +3 -3
- package/dist/cookie/utils.mjs +4 -4
- package/dist/package.js +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugin/aot/core.d.ts +5 -0
- package/dist/plugin/aot/core.js +37 -1
- package/dist/plugin/aot/core.mjs +37 -1
- package/dist/plugin/aot/source.js +24 -9
- package/dist/plugin/aot/source.mjs +24 -9
- package/dist/schema-snapshot.js +4 -3
- package/dist/schema-snapshot.mjs +4 -3
- package/dist/type/coerce.d.ts +1 -1
- package/dist/type/constants.d.ts +1 -1
- package/dist/type/elysia/keep-config.d.ts +14 -0
- package/dist/type/elysia/keep-config.js +62 -0
- package/dist/type/elysia/keep-config.mjs +53 -0
- package/dist/type/exports.d.ts +3 -2
- package/dist/type/exports.js +10 -0
- package/dist/type/exports.mjs +2 -1
- package/dist/type/index.js +10 -0
- package/dist/type/index.mjs +10 -0
- package/dist/type/typebox-type-live.d.ts +2 -2
- package/dist/type/typebox-type-live.js +8 -0
- package/dist/type/typebox-type-live.mjs +2 -2
- package/dist/type/typebox-type.d.ts +10 -2
- package/dist/type/typebox-type.js +64 -0
- package/dist/type/typebox-type.mjs +17 -1
- package/dist/types.d.ts +3 -2
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +23 -0
- package/dist/utils.mjs +22 -1
- package/dist/ws/route.js +33 -5
- package/dist/ws/route.mjs +35 -7
- package/package.json +1 -1
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { isBun } from "../../universal/constants.mjs";
|
|
2
2
|
import { ElysiaFile } from "../../universal/file.mjs";
|
|
3
|
-
import { cloneHook, compactBeforeHandleConflicts, compactBeforeHandlePrefix, eventProperties, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, isCompactBeforeHandleOnly, isHTMLBundle, isLocalScope, isNotEmpty, macroEpoch, mergeHook, nullObject, replaceUrlPath, rootSnapshot } from "../../utils.mjs";
|
|
3
|
+
import { cloneHook, compactBeforeHandleConflicts, compactBeforeHandlePrefix, compositionKeys, eventProperties, flattenChain, flattenChainMemo, flattenChainMemoReadonly, fnOrigin, fnv1a, isCompactBeforeHandleOnly, isHTMLBundle, isLocalScope, isNotEmpty, macroEpoch, mergeHook, nullObject, refTargets, replaceUrlPath, rootSnapshot } from "../../utils.mjs";
|
|
4
4
|
import { ElysiaStatus } from "../../error.mjs";
|
|
5
5
|
import { mapResponse } from "../../adapter/web-standard/handler.mjs";
|
|
6
|
-
import { Capture, Compiled } from "../aot.mjs";
|
|
6
|
+
import { Capture, Compiled, aotDrift, warnAotDrift } from "../aot.mjs";
|
|
7
7
|
import { frozenRootOf } from "../../generation.mjs";
|
|
8
|
+
import { isAsyncFunction } from "../utils.mjs";
|
|
8
9
|
import { returnedErrorClasses } from "../../handler/utils.mjs";
|
|
10
|
+
import { deriveModes } from "./utils.mjs";
|
|
9
11
|
import { resolveHandlerParams } from "./params.mjs";
|
|
10
12
|
import { compileHandlerJit, createInlineHandler, setCaptureHeaderShorthand } from "./jit.mjs";
|
|
11
|
-
import {
|
|
13
|
+
import { isResponseMap } from "./frozen-validator.mjs";
|
|
12
14
|
import { Reconstrct } from "./reconstruct.mjs";
|
|
15
|
+
import { describeRoute, routeDescriptors } from "./descriptor.mjs";
|
|
13
16
|
import { defaultAdapter } from "../../adapter/constants.mjs";
|
|
14
17
|
|
|
15
18
|
//#region src/compile/handler/index.ts
|
|
@@ -273,18 +276,129 @@ function composeRouteHook(instance, localHook, appHook, inheritedChain, root, ma
|
|
|
273
276
|
}
|
|
274
277
|
return hook;
|
|
275
278
|
}
|
|
276
|
-
const
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"
|
|
280
|
-
"
|
|
281
|
-
"
|
|
282
|
-
"
|
|
283
|
-
"
|
|
284
|
-
"
|
|
285
|
-
|
|
286
|
-
|
|
279
|
+
const shapeEvents = [
|
|
280
|
+
"parse",
|
|
281
|
+
"transform",
|
|
282
|
+
"beforeHandle",
|
|
283
|
+
"afterHandle",
|
|
284
|
+
"mapResponse",
|
|
285
|
+
"afterResponse",
|
|
286
|
+
"error",
|
|
287
|
+
"trace"
|
|
288
|
+
];
|
|
289
|
+
const shapeSlots = [
|
|
290
|
+
"body",
|
|
291
|
+
"headers",
|
|
292
|
+
"params",
|
|
293
|
+
"query",
|
|
294
|
+
"cookie",
|
|
295
|
+
"response"
|
|
287
296
|
];
|
|
297
|
+
const isCookieAt = (at) => at === "cookie" || at === "field";
|
|
298
|
+
function childAt(at, k, value, deferred) {
|
|
299
|
+
if (at.endsWith("*")) return at.slice(0, -1);
|
|
300
|
+
if (at.endsWith("^")) return k === "0" ? at.slice(0, -1) + (Array.isArray(value) ? "*" : "") : "";
|
|
301
|
+
if (!isCookieAt(at)) return "";
|
|
302
|
+
switch (k) {
|
|
303
|
+
case "$ref": return at;
|
|
304
|
+
case "properties": return at === "cookie" ? "field*" : "";
|
|
305
|
+
case "parameters": return deferred ? at + "^" : "";
|
|
306
|
+
}
|
|
307
|
+
return k === "$defs" || compositionKeys.includes(k) ? at + "*" : "";
|
|
308
|
+
}
|
|
309
|
+
function routeShape(hook, handler, root) {
|
|
310
|
+
const frozenRoot = frozenRootOf(root);
|
|
311
|
+
const config = frozenRoot["~config"];
|
|
312
|
+
const models = frozenRoot["~ext"]?.models;
|
|
313
|
+
const refs = /* @__PURE__ */ new Map();
|
|
314
|
+
const addRef = (name, at = "") => {
|
|
315
|
+
if (!isCookieAt(at)) at = "";
|
|
316
|
+
if (at === "cookie" || !refs.get(name)) refs.set(name, at);
|
|
317
|
+
};
|
|
318
|
+
const ids = /* @__PURE__ */ new Map();
|
|
319
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
320
|
+
let unsupported = false;
|
|
321
|
+
for (const _ in []) return;
|
|
322
|
+
const shape = (v, at = "") => {
|
|
323
|
+
switch (typeof v) {
|
|
324
|
+
case "string": return JSON.stringify(v);
|
|
325
|
+
case "number": return "n" + (Object.is(v, -0) ? "-0" : v);
|
|
326
|
+
case "bigint": return "b" + v;
|
|
327
|
+
case "boolean": return v ? "T" : "F";
|
|
328
|
+
case "undefined": return "U";
|
|
329
|
+
case "function":
|
|
330
|
+
if (ids.has(v)) return "#" + ids.get(v);
|
|
331
|
+
ids.set(v, ids.size);
|
|
332
|
+
return isAsyncFunction(v) ? "fa" : "fs";
|
|
333
|
+
case "symbol":
|
|
334
|
+
unsupported = true;
|
|
335
|
+
return "";
|
|
336
|
+
}
|
|
337
|
+
if (v === null) return "N";
|
|
338
|
+
if ("~standard" in v) return "S";
|
|
339
|
+
if (visiting.has(v)) {
|
|
340
|
+
unsupported = true;
|
|
341
|
+
return "";
|
|
342
|
+
}
|
|
343
|
+
let tag = "";
|
|
344
|
+
const list = Array.isArray(v);
|
|
345
|
+
const proto = Object.getPrototypeOf(v);
|
|
346
|
+
if (list ? proto !== Array.prototype : proto !== null && proto !== Object.prototype) {
|
|
347
|
+
const kind = proto && Object.getOwnPropertyDescriptor(proto, "~kind");
|
|
348
|
+
if (!kind || !("value" in kind) || Reflect.ownKeys(proto).length !== 1 || Object.getPrototypeOf(proto) !== Object.prototype) {
|
|
349
|
+
unsupported = true;
|
|
350
|
+
return "";
|
|
351
|
+
}
|
|
352
|
+
tag = shape(kind.value);
|
|
353
|
+
}
|
|
354
|
+
visiting.add(v);
|
|
355
|
+
const map = at === "response" && isResponseMap(v);
|
|
356
|
+
const deferred = v["~kind"] === "Deferred";
|
|
357
|
+
let s = (list ? "[" : "{") + tag;
|
|
358
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
359
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
360
|
+
if (typeof k === "symbol" || !("value" in d)) {
|
|
361
|
+
unsupported = true;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
const value = d.value;
|
|
365
|
+
if (k === "$ref" && typeof value === "string") addRef(value, at);
|
|
366
|
+
s += "," + (d.enumerable ? "" : "!") + JSON.stringify(k) + ":";
|
|
367
|
+
if (map) s += named(value);
|
|
368
|
+
else if (k === "config" && isCookieAt(at)) s += shape([value?.sign, !!value?.secrets]);
|
|
369
|
+
else if (k === "secrets" && (typeof value === "string" || Array.isArray(value))) s += shape(!!value);
|
|
370
|
+
else s += shape(value, childAt(at, k, value, deferred));
|
|
371
|
+
}
|
|
372
|
+
visiting.delete(v);
|
|
373
|
+
return s + (list ? "]" : "}");
|
|
374
|
+
};
|
|
375
|
+
const named = (v, at) => {
|
|
376
|
+
if (typeof v === "string") addRef(v, at);
|
|
377
|
+
return shape(v, at);
|
|
378
|
+
};
|
|
379
|
+
let s = typeof handler === "function" || handler == null ? shape(handler) : handler instanceof Response ? "R" : handler instanceof Promise ? "P" : typeof handler === "object" ? "O" : "V";
|
|
380
|
+
for (const event of shapeEvents) {
|
|
381
|
+
s += "|";
|
|
382
|
+
const fns = hook?.[event];
|
|
383
|
+
if (fns) for (const fn of Array.isArray(fns) ? fns : [fns]) s += shape(fn);
|
|
384
|
+
}
|
|
385
|
+
const bf = hook?.beforeHandle;
|
|
386
|
+
s += "|" + JSON.stringify(bf && deriveModes(Array.isArray(bf) ? bf : [bf], hook["~deriveEntries"]));
|
|
387
|
+
for (const from of [hook, ...hook?.schemas || []]) for (const slot of shapeSlots) s += "|" + named(from?.[slot], slot);
|
|
388
|
+
let targets;
|
|
389
|
+
for (const [ref, at] of refs) for (const target of at ? (targets ??= refTargets([], models))(ref) : [models?.[ref]]) s += "|" + JSON.stringify(ref) + shape(target, at);
|
|
390
|
+
s += "|" + JSON.stringify([
|
|
391
|
+
config?.cookie?.sign,
|
|
392
|
+
config?.cookie?.verify,
|
|
393
|
+
config?.normalize,
|
|
394
|
+
!!config?.allowUnsafeValidationDetails,
|
|
395
|
+
config?.abortSignal !== false,
|
|
396
|
+
isNotEmpty(frozenRoot["~ext"]?.headers),
|
|
397
|
+
!!(config?.adapter ?? defaultAdapter).response.supportsDefaultHeaderSink,
|
|
398
|
+
!!returnedErrorClasses(hook, root)
|
|
399
|
+
]) + shape(config?.sanitize);
|
|
400
|
+
return unsupported ? void 0 : fnv1a(s);
|
|
401
|
+
}
|
|
288
402
|
const isBareArrow = /^(?:async\s*)?\(\s*\)\s*=>/;
|
|
289
403
|
const isSucroseOpaque = /arguments|eval|\[native code\]/;
|
|
290
404
|
function compileHandler(route, root, liveOnly = false) {
|
|
@@ -302,17 +416,7 @@ function compileHandler(route, root, liveOnly = false) {
|
|
|
302
416
|
handler = (c) => handle(new Request(replaceUrlPath(c.request.url, c.path.slice(c.path.startsWith(encRoot) ? encLen : rawLen) || "/"), c.request));
|
|
303
417
|
}
|
|
304
418
|
const reconstructed = liveOnly ? void 0 : Compiled.getHandler(frozenRoot["~programId"], method, path);
|
|
305
|
-
if (reconstructed
|
|
306
|
-
if (!reconstructed.a.some((name) => hookStateAliases.includes(name))) return reconstructed.f(handler, ...resolveHandlerParams(reconstructed.a, {
|
|
307
|
-
root,
|
|
308
|
-
parse: adapter.parse,
|
|
309
|
-
res: adapter.response,
|
|
310
|
-
hook: nullObject(),
|
|
311
|
-
vali: void 0,
|
|
312
|
-
cookieConfig: void 0,
|
|
313
|
-
tracers: void 0
|
|
314
|
-
}));
|
|
315
|
-
}
|
|
419
|
+
if (!reconstructed) liveOnly ||= Compiled.hasProgram(frozenRoot["~programId"]);
|
|
316
420
|
const hook = composeRouteHook(instance, localHook, appHook, inheritedChain, root, macroScope, !reconstructed);
|
|
317
421
|
if (hook) {
|
|
318
422
|
promoteDerive(hook);
|
|
@@ -350,6 +454,20 @@ function compileHandler(route, root, liveOnly = false) {
|
|
|
350
454
|
const resolve = (p) => typeof p === "string" && p in namedParsers ? namedParsers[p] : p;
|
|
351
455
|
hook.parse = Array.isArray(hook.parse) ? hook.parse.map(resolve) : resolve(hook.parse);
|
|
352
456
|
}
|
|
457
|
+
let shape;
|
|
458
|
+
if (reconstructed || Capture.isCapturing()) {
|
|
459
|
+
shape = routeShape(hook, handler, root);
|
|
460
|
+
if (reconstructed && (!shape || reconstructed.k !== shape)) {
|
|
461
|
+
let live;
|
|
462
|
+
try {
|
|
463
|
+
live = compileHandler(route, root, true);
|
|
464
|
+
} catch (cause) {
|
|
465
|
+
throw new Error(aotDrift(method, path), { cause });
|
|
466
|
+
}
|
|
467
|
+
warnAotDrift(method, path);
|
|
468
|
+
return live;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
353
471
|
if (reconstructed) return reconstructed.f(handler, ...resolveHandlerParams(reconstructed.a, {
|
|
354
472
|
root,
|
|
355
473
|
parse: adapter.parse,
|
|
@@ -401,9 +519,10 @@ function compileHandler(route, root, liveOnly = false) {
|
|
|
401
519
|
isStaticResponse,
|
|
402
520
|
isPromiseHandler,
|
|
403
521
|
errorClasses,
|
|
404
|
-
state
|
|
522
|
+
state,
|
|
523
|
+
shape
|
|
405
524
|
});
|
|
406
525
|
}
|
|
407
526
|
|
|
408
527
|
//#endregion
|
|
409
|
-
export { buildNativeStaticResponse, chainResolver, clearHandlerAnalysisCaches, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook, resolveWSLocalHook, setCaptureHeaderShorthand };
|
|
528
|
+
export { buildNativeStaticResponse, chainResolver, clearHandlerAnalysisCaches, compileHandler, composeRouteHook, localMacroRoot, resolveLocalHook, resolveWSLocalHook, routeShape, setCaptureHeaderShorthand };
|
|
@@ -37,6 +37,8 @@ interface CompileHandlerJitOptions {
|
|
|
37
37
|
* The JIT no longer re-derives these facts; it names its emissions off them.
|
|
38
38
|
*/
|
|
39
39
|
state: RouteCompileState;
|
|
40
|
+
/** `routeShape`, recorded with the captured code */
|
|
41
|
+
shape?: number;
|
|
40
42
|
}
|
|
41
43
|
declare function compileHandlerJit(options: CompileHandlerJitOptions, tailPass?: TailMode): CompiledHandler;
|
|
42
44
|
//#endregion
|
|
@@ -162,7 +162,7 @@ const createInlineHandler = (map, h) => ((c) => {
|
|
|
162
162
|
return map(r, c.request, true);
|
|
163
163
|
});
|
|
164
164
|
function compileHandlerJit(options, tailPass) {
|
|
165
|
-
const { method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, errorClasses, state } = options;
|
|
165
|
+
const { method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, errorClasses, state, shape } = options;
|
|
166
166
|
const { vali, inference, cookieConfig, beforeHandlePrefix, traceHandlers, tracePhases, hasAnyPhase, traceHandleOn, descriptor: { async: isAsync, tail: tailRoute, responseMode, hasBody, bodyValiIsAsync, headersValiIsAsync, paramsValiIsAsync, queryValiIsAsync, cookieValiIsAsync: cookieValidIsAsync, responseValiAsync, hasCookieSign, syncCookieSign, asyncCookieSign, lazyCookieVerify, hasErrorHook, hasAfterResponse, hasBeforeHandle, hasAfterHandle, hasMapResponse, hasResponseValidator, hasTrace, traceCount, hasLifecycleHook, syncErrorHook, syncAfterResponse } } = state;
|
|
167
167
|
const hasStaticAfterResponse = !!hook?.afterResponse?.length;
|
|
168
168
|
const hasDeriveDispose = !!hook?.["~deriveEntries"]?.length;
|
|
@@ -567,7 +567,8 @@ if(_vr)_r.response=${responseValiAsync ? awaitValue(encodeStatus, arm) : encodeS
|
|
|
567
567
|
method,
|
|
568
568
|
path,
|
|
569
569
|
alias: fullAlias,
|
|
570
|
-
code
|
|
570
|
+
code,
|
|
571
|
+
k: shape
|
|
571
572
|
});
|
|
572
573
|
onEmit?.(code);
|
|
573
574
|
const isGeneratorHandler = isHandleFunction && handler.constructor.name.endsWith("GeneratorFunction");
|
|
@@ -161,7 +161,7 @@ const createInlineHandler = (map, h) => ((c) => {
|
|
|
161
161
|
return map(r, c.request, true);
|
|
162
162
|
});
|
|
163
163
|
function compileHandlerJit(options, tailPass) {
|
|
164
|
-
const { method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, errorClasses, state } = options;
|
|
164
|
+
const { method, path, handler, root, errorRoot, hook, adapter, isHandleFunction, isStaticResponse, isPromiseHandler, errorClasses, state, shape } = options;
|
|
165
165
|
const { vali, inference, cookieConfig, beforeHandlePrefix, traceHandlers, tracePhases, hasAnyPhase, traceHandleOn, descriptor: { async: isAsync, tail: tailRoute, responseMode, hasBody, bodyValiIsAsync, headersValiIsAsync, paramsValiIsAsync, queryValiIsAsync, cookieValiIsAsync: cookieValidIsAsync, responseValiAsync, hasCookieSign, syncCookieSign, asyncCookieSign, lazyCookieVerify, hasErrorHook, hasAfterResponse, hasBeforeHandle, hasAfterHandle, hasMapResponse, hasResponseValidator, hasTrace, traceCount, hasLifecycleHook, syncErrorHook, syncAfterResponse } } = state;
|
|
166
166
|
const hasStaticAfterResponse = !!hook?.afterResponse?.length;
|
|
167
167
|
const hasDeriveDispose = !!hook?.["~deriveEntries"]?.length;
|
|
@@ -566,7 +566,8 @@ if(_vr)_r.response=${responseValiAsync ? awaitValue(encodeStatus, arm) : encodeS
|
|
|
566
566
|
method,
|
|
567
567
|
path,
|
|
568
568
|
alias: fullAlias,
|
|
569
|
-
code
|
|
569
|
+
code,
|
|
570
|
+
k: shape
|
|
570
571
|
});
|
|
571
572
|
onEmit?.(code);
|
|
572
573
|
const isGeneratorHandler = isHandleFunction && handler.constructor.name.endsWith("GeneratorFunction");
|
|
@@ -28,14 +28,15 @@ var Reconstrct = class {
|
|
|
28
28
|
});
|
|
29
29
|
} catch (error) {
|
|
30
30
|
if (!require_compile_handler_frozen_validator.isBridgeNotInitialized(error)) throw error;
|
|
31
|
-
if (liveOnly) throw new Error("
|
|
31
|
+
if (liveOnly) throw new Error("Route requires live compilation but the TypeBox bridge is not initialized", { cause: error });
|
|
32
32
|
const frozen = require_compile_handler_frozen_validator.buildFrozenRouteValidator(hook, root, method, path);
|
|
33
33
|
if (frozen) return frozen;
|
|
34
34
|
throw error;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
static cookie(hook, root) {
|
|
38
|
-
|
|
38
|
+
const frozenRoot = require_generation.frozenRootOf(root);
|
|
39
|
+
return require_cookie_config.compileCookieConfig(hook?.cookie, frozenRoot["~config"]?.cookie, frozenRoot["~ext"]?.models, hook?.schemas);
|
|
39
40
|
}
|
|
40
41
|
static trace(hook, root) {
|
|
41
42
|
const traceHandlers = hook?.trace;
|
|
@@ -27,14 +27,15 @@ var Reconstrct = class {
|
|
|
27
27
|
});
|
|
28
28
|
} catch (error) {
|
|
29
29
|
if (!isBridgeNotInitialized(error)) throw error;
|
|
30
|
-
if (liveOnly) throw new Error("
|
|
30
|
+
if (liveOnly) throw new Error("Route requires live compilation but the TypeBox bridge is not initialized", { cause: error });
|
|
31
31
|
const frozen = buildFrozenRouteValidator(hook, root, method, path);
|
|
32
32
|
if (frozen) return frozen;
|
|
33
33
|
throw error;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
static cookie(hook, root) {
|
|
37
|
-
|
|
37
|
+
const frozenRoot = frozenRootOf(root);
|
|
38
|
+
return compileCookieConfig(hook?.cookie, frozenRoot["~config"]?.cookie, frozenRoot["~ext"]?.models, hook?.schemas);
|
|
38
39
|
}
|
|
39
40
|
static trace(hook, root) {
|
|
40
41
|
const traceHandlers = hook?.trace;
|
package/dist/cookie/config.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface FieldCookieConfig {
|
|
|
9
9
|
secrets?: string | null | (string | null)[];
|
|
10
10
|
sign: boolean;
|
|
11
11
|
defaults?: Partial<BaseCookie>;
|
|
12
|
+
legacySignature?: boolean;
|
|
12
13
|
}
|
|
13
14
|
interface CompiledCookieConfig {
|
|
14
15
|
defaults: Partial<BaseCookie>;
|
|
@@ -20,7 +21,10 @@ interface CompiledCookieConfig {
|
|
|
20
21
|
verify: 'lazy' | 'eager';
|
|
21
22
|
legacySignature: boolean;
|
|
22
23
|
}
|
|
23
|
-
declare function compileCookieConfig(routeSchema: AnySchema | undefined, appConfig: AppCookieConfig | undefined
|
|
24
|
+
declare function compileCookieConfig(routeSchema: AnySchema | string | undefined, appConfig: AppCookieConfig | undefined, models?: Record<string, unknown>, schemas?: {
|
|
25
|
+
cookie?: unknown;
|
|
26
|
+
}[]): CompiledCookieConfig;
|
|
27
|
+
declare const legacySignatureOf: (name: string, config: CompiledCookieConfig) => boolean;
|
|
24
28
|
declare function resolveSignSecrets(name: string, config: CompiledCookieConfig): CompiledCookieConfig['globalSecrets'] | undefined;
|
|
25
29
|
declare function isCookieSigned(name: string, config: CompiledCookieConfig): {
|
|
26
30
|
signed: true;
|
|
@@ -29,4 +33,4 @@ declare function isCookieSigned(name: string, config: CompiledCookieConfig): {
|
|
|
29
33
|
signed: false;
|
|
30
34
|
};
|
|
31
35
|
//#endregion
|
|
32
|
-
export { AppCookieConfig, CompiledCookieConfig, FieldCookieConfig, compileCookieConfig, isCookieSigned, resolveSignSecrets };
|
|
36
|
+
export { AppCookieConfig, CompiledCookieConfig, FieldCookieConfig, compileCookieConfig, isCookieSigned, legacySignatureOf, resolveSignSecrets };
|
package/dist/cookie/config.js
CHANGED
|
@@ -26,8 +26,67 @@ function getAttributes(source) {
|
|
|
26
26
|
return out;
|
|
27
27
|
}
|
|
28
28
|
const hasUsableSecret = (secrets) => Array.isArray(secrets) ? secrets.some((s) => !!s?.trim()) : !!secrets?.trim();
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const gathered = () => ({
|
|
30
|
+
config: require_utils.nullObject(),
|
|
31
|
+
fields: require_utils.nullObject()
|
|
32
|
+
});
|
|
33
|
+
function canonical(config) {
|
|
34
|
+
const out = require_utils.nullObject();
|
|
35
|
+
for (const key of Object.keys(config).sort()) if (key !== "sign") out[key] = key === "secrets" ? asList(config[key]) : config[key];
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
const unsigned = (from) => {
|
|
39
|
+
const fields = require_utils.nullObject();
|
|
40
|
+
for (const name of Object.keys(from.fields).sort()) {
|
|
41
|
+
const field = canonical(from.fields[name]);
|
|
42
|
+
if (Object.keys(field).length) fields[name] = field;
|
|
43
|
+
}
|
|
44
|
+
return JSON.stringify([canonical(from.config), fields]);
|
|
45
|
+
};
|
|
46
|
+
const unclear = () => /* @__PURE__ */ new Error("[Elysia] Cookie schema `$ref` is unresolvable or ambiguous; use a model name or `$id` instead");
|
|
47
|
+
const asList = (value) => JSON.stringify(typeof value === "string" ? [value] : value);
|
|
48
|
+
function foldConfig(into, config) {
|
|
49
|
+
for (const key in config) {
|
|
50
|
+
const value = config[key];
|
|
51
|
+
const prev = into[key];
|
|
52
|
+
if (value === void 0) continue;
|
|
53
|
+
if (prev === void 0) into[key] = value;
|
|
54
|
+
else if (key === "sign") into.sign = prev === true || value === true || [].concat(prev, value);
|
|
55
|
+
else if ((key === "secrets" || key === "legacySignature") && asList(prev) !== asList(value)) throw new Error(`[Elysia] Merged cookie schemas disagree on \`${key}\``);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function compileCookieConfig(routeSchema, appConfig, models, schemas) {
|
|
59
|
+
const roots = [routeSchema, ...(schemas ?? []).map((schema) => schema?.cookie).reverse()].map((schema) => typeof schema === "string" ? models?.[schema] : schema);
|
|
60
|
+
let targets;
|
|
61
|
+
const resolve = (name) => (targets ??= require_utils.refTargets(roots, models))(name);
|
|
62
|
+
const gather = (schema, into, field, path) => {
|
|
63
|
+
if (!schema || path.has(schema)) return;
|
|
64
|
+
path.add(schema);
|
|
65
|
+
const ref = schema.$ref;
|
|
66
|
+
const targets = typeof ref === "string" ? [...resolve(ref)] : [ref];
|
|
67
|
+
if (typeof ref === "string" && !targets.length || schema.$dynamicRef !== void 0 || schema.$recursiveRef !== void 0) throw unclear();
|
|
68
|
+
if (field === void 0) {
|
|
69
|
+
foldConfig(into.config, schema.config);
|
|
70
|
+
for (const name in schema.properties) gather(schema.properties[name], into, name, /* @__PURE__ */ new Set());
|
|
71
|
+
} else if (schema.config) foldConfig(into.fields[field] ??= require_utils.nullObject(), schema.config);
|
|
72
|
+
if (targets.length > 1) {
|
|
73
|
+
let first;
|
|
74
|
+
for (const target of targets) {
|
|
75
|
+
const from = gathered();
|
|
76
|
+
gather(target, from, field, path);
|
|
77
|
+
if ((first ??= unsigned(from)) !== unsigned(from)) throw unclear();
|
|
78
|
+
foldConfig(into.config, from.config);
|
|
79
|
+
for (const name in from.fields) foldConfig(into.fields[name] ??= require_utils.nullObject(), from.fields[name]);
|
|
80
|
+
}
|
|
81
|
+
} else gather(targets[0], into, field, path);
|
|
82
|
+
for (const key of require_utils.compositionKeys) if (Array.isArray(schema[key])) for (const member of schema[key]) gather(member, into, field, path);
|
|
83
|
+
if (schema["~kind"] === "Deferred") for (const operand of [].concat(schema.parameters?.[0])) gather(operand, into, field, path);
|
|
84
|
+
path.delete(schema);
|
|
85
|
+
};
|
|
86
|
+
const route = gathered();
|
|
87
|
+
for (const root of roots) gather(root, route, void 0, /* @__PURE__ */ new Set());
|
|
88
|
+
const routeConfig = route.config;
|
|
89
|
+
const fieldConfigs = route.fields;
|
|
31
90
|
const appAttributes = getAttributes(appConfig);
|
|
32
91
|
const routeAttributes = getAttributes(routeConfig);
|
|
33
92
|
const defaults = appAttributes && routeAttributes ? {
|
|
@@ -43,17 +102,16 @@ function compileCookieConfig(routeSchema, appConfig) {
|
|
|
43
102
|
else globalSign = [rawSign];
|
|
44
103
|
const globalSecrets = routeConfig?.secrets !== void 0 ? routeConfig.secrets : appConfig?.secrets;
|
|
45
104
|
const fields = require_utils.nullObject();
|
|
46
|
-
const properties = routeSchema?.properties;
|
|
47
105
|
let hasSign = false;
|
|
48
|
-
|
|
49
|
-
const config =
|
|
50
|
-
|
|
51
|
-
const sign = !!config.secrets || config.sign === true;
|
|
106
|
+
for (const name in fieldConfigs) {
|
|
107
|
+
const config = fieldConfigs[name];
|
|
108
|
+
const sign = config.secrets != null || config.sign === true;
|
|
52
109
|
if (sign) hasSign = true;
|
|
53
110
|
fields[name] = {
|
|
54
111
|
secrets: config.secrets,
|
|
55
112
|
sign,
|
|
56
|
-
defaults: getAttributes(config)
|
|
113
|
+
defaults: getAttributes(config),
|
|
114
|
+
legacySignature: config.legacySignature
|
|
57
115
|
};
|
|
58
116
|
}
|
|
59
117
|
if (globalSign !== void 0) hasSign = true;
|
|
@@ -77,6 +135,7 @@ function compileCookieConfig(routeSchema, appConfig) {
|
|
|
77
135
|
legacySignature: (routeConfig?.legacySignature ?? appConfig?.legacySignature) !== false
|
|
78
136
|
};
|
|
79
137
|
}
|
|
138
|
+
const legacySignatureOf = (name, config) => config.fields[name]?.legacySignature ?? config.legacySignature;
|
|
80
139
|
function resolveSignSecrets(name, config) {
|
|
81
140
|
const field = config.fields[name];
|
|
82
141
|
if (field?.sign) return field.secrets ?? config.globalSecrets;
|
|
@@ -95,4 +154,5 @@ function isCookieSigned(name, config) {
|
|
|
95
154
|
//#endregion
|
|
96
155
|
exports.compileCookieConfig = compileCookieConfig;
|
|
97
156
|
exports.isCookieSigned = isCookieSigned;
|
|
157
|
+
exports.legacySignatureOf = legacySignatureOf;
|
|
98
158
|
exports.resolveSignSecrets = resolveSignSecrets;
|
package/dist/cookie/config.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { nullObject } from "../utils.mjs";
|
|
1
|
+
import { compositionKeys, nullObject, refTargets } from "../utils.mjs";
|
|
2
2
|
import { InvalidCookie } from "./error.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/cookie/config.ts
|
|
@@ -25,8 +25,67 @@ function getAttributes(source) {
|
|
|
25
25
|
return out;
|
|
26
26
|
}
|
|
27
27
|
const hasUsableSecret = (secrets) => Array.isArray(secrets) ? secrets.some((s) => !!s?.trim()) : !!secrets?.trim();
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const gathered = () => ({
|
|
29
|
+
config: nullObject(),
|
|
30
|
+
fields: nullObject()
|
|
31
|
+
});
|
|
32
|
+
function canonical(config) {
|
|
33
|
+
const out = nullObject();
|
|
34
|
+
for (const key of Object.keys(config).sort()) if (key !== "sign") out[key] = key === "secrets" ? asList(config[key]) : config[key];
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
const unsigned = (from) => {
|
|
38
|
+
const fields = nullObject();
|
|
39
|
+
for (const name of Object.keys(from.fields).sort()) {
|
|
40
|
+
const field = canonical(from.fields[name]);
|
|
41
|
+
if (Object.keys(field).length) fields[name] = field;
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify([canonical(from.config), fields]);
|
|
44
|
+
};
|
|
45
|
+
const unclear = () => /* @__PURE__ */ new Error("[Elysia] Cookie schema `$ref` is unresolvable or ambiguous; use a model name or `$id` instead");
|
|
46
|
+
const asList = (value) => JSON.stringify(typeof value === "string" ? [value] : value);
|
|
47
|
+
function foldConfig(into, config) {
|
|
48
|
+
for (const key in config) {
|
|
49
|
+
const value = config[key];
|
|
50
|
+
const prev = into[key];
|
|
51
|
+
if (value === void 0) continue;
|
|
52
|
+
if (prev === void 0) into[key] = value;
|
|
53
|
+
else if (key === "sign") into.sign = prev === true || value === true || [].concat(prev, value);
|
|
54
|
+
else if ((key === "secrets" || key === "legacySignature") && asList(prev) !== asList(value)) throw new Error(`[Elysia] Merged cookie schemas disagree on \`${key}\``);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function compileCookieConfig(routeSchema, appConfig, models, schemas) {
|
|
58
|
+
const roots = [routeSchema, ...(schemas ?? []).map((schema) => schema?.cookie).reverse()].map((schema) => typeof schema === "string" ? models?.[schema] : schema);
|
|
59
|
+
let targets;
|
|
60
|
+
const resolve = (name) => (targets ??= refTargets(roots, models))(name);
|
|
61
|
+
const gather = (schema, into, field, path) => {
|
|
62
|
+
if (!schema || path.has(schema)) return;
|
|
63
|
+
path.add(schema);
|
|
64
|
+
const ref = schema.$ref;
|
|
65
|
+
const targets = typeof ref === "string" ? [...resolve(ref)] : [ref];
|
|
66
|
+
if (typeof ref === "string" && !targets.length || schema.$dynamicRef !== void 0 || schema.$recursiveRef !== void 0) throw unclear();
|
|
67
|
+
if (field === void 0) {
|
|
68
|
+
foldConfig(into.config, schema.config);
|
|
69
|
+
for (const name in schema.properties) gather(schema.properties[name], into, name, /* @__PURE__ */ new Set());
|
|
70
|
+
} else if (schema.config) foldConfig(into.fields[field] ??= nullObject(), schema.config);
|
|
71
|
+
if (targets.length > 1) {
|
|
72
|
+
let first;
|
|
73
|
+
for (const target of targets) {
|
|
74
|
+
const from = gathered();
|
|
75
|
+
gather(target, from, field, path);
|
|
76
|
+
if ((first ??= unsigned(from)) !== unsigned(from)) throw unclear();
|
|
77
|
+
foldConfig(into.config, from.config);
|
|
78
|
+
for (const name in from.fields) foldConfig(into.fields[name] ??= nullObject(), from.fields[name]);
|
|
79
|
+
}
|
|
80
|
+
} else gather(targets[0], into, field, path);
|
|
81
|
+
for (const key of compositionKeys) if (Array.isArray(schema[key])) for (const member of schema[key]) gather(member, into, field, path);
|
|
82
|
+
if (schema["~kind"] === "Deferred") for (const operand of [].concat(schema.parameters?.[0])) gather(operand, into, field, path);
|
|
83
|
+
path.delete(schema);
|
|
84
|
+
};
|
|
85
|
+
const route = gathered();
|
|
86
|
+
for (const root of roots) gather(root, route, void 0, /* @__PURE__ */ new Set());
|
|
87
|
+
const routeConfig = route.config;
|
|
88
|
+
const fieldConfigs = route.fields;
|
|
30
89
|
const appAttributes = getAttributes(appConfig);
|
|
31
90
|
const routeAttributes = getAttributes(routeConfig);
|
|
32
91
|
const defaults = appAttributes && routeAttributes ? {
|
|
@@ -42,17 +101,16 @@ function compileCookieConfig(routeSchema, appConfig) {
|
|
|
42
101
|
else globalSign = [rawSign];
|
|
43
102
|
const globalSecrets = routeConfig?.secrets !== void 0 ? routeConfig.secrets : appConfig?.secrets;
|
|
44
103
|
const fields = nullObject();
|
|
45
|
-
const properties = routeSchema?.properties;
|
|
46
104
|
let hasSign = false;
|
|
47
|
-
|
|
48
|
-
const config =
|
|
49
|
-
|
|
50
|
-
const sign = !!config.secrets || config.sign === true;
|
|
105
|
+
for (const name in fieldConfigs) {
|
|
106
|
+
const config = fieldConfigs[name];
|
|
107
|
+
const sign = config.secrets != null || config.sign === true;
|
|
51
108
|
if (sign) hasSign = true;
|
|
52
109
|
fields[name] = {
|
|
53
110
|
secrets: config.secrets,
|
|
54
111
|
sign,
|
|
55
|
-
defaults: getAttributes(config)
|
|
112
|
+
defaults: getAttributes(config),
|
|
113
|
+
legacySignature: config.legacySignature
|
|
56
114
|
};
|
|
57
115
|
}
|
|
58
116
|
if (globalSign !== void 0) hasSign = true;
|
|
@@ -76,6 +134,7 @@ function compileCookieConfig(routeSchema, appConfig) {
|
|
|
76
134
|
legacySignature: (routeConfig?.legacySignature ?? appConfig?.legacySignature) !== false
|
|
77
135
|
};
|
|
78
136
|
}
|
|
137
|
+
const legacySignatureOf = (name, config) => config.fields[name]?.legacySignature ?? config.legacySignature;
|
|
79
138
|
function resolveSignSecrets(name, config) {
|
|
80
139
|
const field = config.fields[name];
|
|
81
140
|
if (field?.sign) return field.secrets ?? config.globalSecrets;
|
|
@@ -92,4 +151,4 @@ function isCookieSigned(name, config) {
|
|
|
92
151
|
}
|
|
93
152
|
|
|
94
153
|
//#endregion
|
|
95
|
-
export { compileCookieConfig, isCookieSigned, resolveSignSecrets };
|
|
154
|
+
export { compileCookieConfig, isCookieSigned, legacySignatureOf, resolveSignSecrets };
|
package/dist/cookie/utils.js
CHANGED
|
@@ -66,7 +66,7 @@ async function parseCookieRaw(cookieString, config, lazy) {
|
|
|
66
66
|
let value = (0, deuri.default)(v) ?? v;
|
|
67
67
|
const signCheck = require_cookie_config.resolveSignSecrets(name, config);
|
|
68
68
|
if (signCheck !== void 0) try {
|
|
69
|
-
value = await require_cookie_crypto.unsignWithSecrets(name, value, signCheck, config
|
|
69
|
+
value = await require_cookie_crypto.unsignWithSecrets(name, value, signCheck, require_cookie_config.legacySignatureOf(name, config));
|
|
70
70
|
} catch (error) {
|
|
71
71
|
if (!lazy || !(error instanceof require_cookie_error.InvalidCookie)) throw error;
|
|
72
72
|
out[name] = invalidSignature();
|
|
@@ -87,7 +87,7 @@ function parseCookieRawSigned(cookieString, config, lazy) {
|
|
|
87
87
|
let value = (0, deuri.default)(v) ?? v;
|
|
88
88
|
const signCheck = require_cookie_config.resolveSignSecrets(name, config);
|
|
89
89
|
if (signCheck !== void 0) try {
|
|
90
|
-
value = require_cookie_crypto.unsignWithSecretsSync(name, value, signCheck, config
|
|
90
|
+
value = require_cookie_crypto.unsignWithSecretsSync(name, value, signCheck, require_cookie_config.legacySignatureOf(name, config));
|
|
91
91
|
} catch (error) {
|
|
92
92
|
if (!lazy || !(error instanceof require_cookie_error.InvalidCookie)) throw error;
|
|
93
93
|
out[name] = invalidSignature();
|
|
@@ -111,7 +111,7 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
|
|
|
111
111
|
const secrets = require_cookie_config.resolveSignSecrets(name, config);
|
|
112
112
|
if (secrets !== void 0) {
|
|
113
113
|
entry["~unsign"] = secrets;
|
|
114
|
-
if (!config
|
|
114
|
+
if (!require_cookie_config.legacySignatureOf(name, config)) entry["~strict"] = 1;
|
|
115
115
|
}
|
|
116
116
|
} else {
|
|
117
117
|
const value = entry.value;
|
package/dist/cookie/utils.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { InvalidCookie } from "./error.mjs";
|
|
|
3
3
|
import { parse } from "./lib.mjs";
|
|
4
4
|
import { deriveSignKey, hasSyncHmac, maybeJsonDecode, rawJsonValue, resolvePendingCookie, signCookie, signCookieSyncImpl, unsignWithSecrets, unsignWithSecretsSync } from "./crypto.mjs";
|
|
5
5
|
import { Cookie } from "./cookie.mjs";
|
|
6
|
-
import { isCookieSigned, resolveSignSecrets } from "./config.mjs";
|
|
6
|
+
import { isCookieSigned, legacySignatureOf, resolveSignSecrets } from "./config.mjs";
|
|
7
7
|
import decodeComponent from "deuri";
|
|
8
8
|
|
|
9
9
|
//#region src/cookie/utils.ts
|
|
@@ -63,7 +63,7 @@ async function parseCookieRaw(cookieString, config, lazy) {
|
|
|
63
63
|
let value = decodeComponent(v) ?? v;
|
|
64
64
|
const signCheck = resolveSignSecrets(name, config);
|
|
65
65
|
if (signCheck !== void 0) try {
|
|
66
|
-
value = await unsignWithSecrets(name, value, signCheck, config
|
|
66
|
+
value = await unsignWithSecrets(name, value, signCheck, legacySignatureOf(name, config));
|
|
67
67
|
} catch (error) {
|
|
68
68
|
if (!lazy || !(error instanceof InvalidCookie)) throw error;
|
|
69
69
|
out[name] = invalidSignature();
|
|
@@ -84,7 +84,7 @@ function parseCookieRawSigned(cookieString, config, lazy) {
|
|
|
84
84
|
let value = decodeComponent(v) ?? v;
|
|
85
85
|
const signCheck = resolveSignSecrets(name, config);
|
|
86
86
|
if (signCheck !== void 0) try {
|
|
87
|
-
value = unsignWithSecretsSync(name, value, signCheck, config
|
|
87
|
+
value = unsignWithSecretsSync(name, value, signCheck, legacySignatureOf(name, config));
|
|
88
88
|
} catch (error) {
|
|
89
89
|
if (!lazy || !(error instanceof InvalidCookie)) throw error;
|
|
90
90
|
out[name] = invalidSignature();
|
|
@@ -108,7 +108,7 @@ function buildCookieJar(set, raw, config, lazySign, deferDecode) {
|
|
|
108
108
|
const secrets = resolveSignSecrets(name, config);
|
|
109
109
|
if (secrets !== void 0) {
|
|
110
110
|
entry["~unsign"] = secrets;
|
|
111
|
-
if (!config
|
|
111
|
+
if (!legacySignatureOf(name, config)) entry["~strict"] = 1;
|
|
112
112
|
}
|
|
113
113
|
} else {
|
|
114
114
|
const value = entry.value;
|
package/dist/package.js
CHANGED
package/dist/package.mjs
CHANGED
|
@@ -3,6 +3,11 @@ import { JITProbeResult } from "../../compile/jit-probe.js";
|
|
|
3
3
|
import { AotModuleCondition, AotTarget } from "./source.js";
|
|
4
4
|
|
|
5
5
|
//#region src/plugin/aot/core.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A route that differs from the build compiles live with a warning, or fails
|
|
8
|
+
* when the JIT is stripped. A conditional hook must change the hook list
|
|
9
|
+
* (`isProd ? [auth] : []`), not swap functions. Keep `async` native
|
|
10
|
+
*/
|
|
6
11
|
interface ElysiaAotOptions {
|
|
7
12
|
/**
|
|
8
13
|
* Specifier the generated module imports `Compiled` from
|