routup 5.0.0-beta.4 → 5.0.0-beta.6
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/bun.d.mts +2 -2
- package/dist/bun.mjs +2 -2
- package/dist/cloudflare.d.mts +2 -2
- package/dist/cloudflare.mjs +2 -2
- package/dist/deno.d.mts +2 -2
- package/dist/deno.mjs +2 -2
- package/dist/generic.d.mts +2 -2
- package/dist/generic.mjs +2 -2
- package/dist/{index-doDmTYzg.d.mts → index-CDDPS8RL.d.mts} +132 -8
- package/dist/node.d.mts +2 -2
- package/dist/node.mjs +2 -2
- package/dist/service-worker.d.mts +2 -2
- package/dist/service-worker.mjs +2 -2
- package/dist/{src-Ck8GklBr.mjs → src-C32sKqPQ.mjs} +276 -39
- package/dist/src-C32sKqPQ.mjs.map +1 -0
- package/package.json +11 -7
- package/dist/src-Ck8GklBr.mjs.map +0 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FastURL } from "srvx";
|
|
2
2
|
import { HTTPError, isHTTPError } from "@ebec/http";
|
|
3
|
-
import { Buffer } from "node:buffer";
|
|
4
3
|
import { subtle } from "uncrypto";
|
|
5
4
|
import { merge } from "smob";
|
|
6
5
|
import { compile } from "proxy-addr";
|
|
@@ -138,22 +137,7 @@ function sanitizeHeaderValue(value) {
|
|
|
138
137
|
return value.replace(/[\r\n]/g, "");
|
|
139
138
|
}
|
|
140
139
|
//#endregion
|
|
141
|
-
//#region src/utils/object.ts
|
|
142
|
-
function isObject(item) {
|
|
143
|
-
return !!item && typeof item === "object" && !Array.isArray(item);
|
|
144
|
-
}
|
|
145
|
-
//#endregion
|
|
146
140
|
//#region src/utils/etag/module.ts
|
|
147
|
-
/**
|
|
148
|
-
* Determine if object is a Stats object.
|
|
149
|
-
*
|
|
150
|
-
* @param {object} obj
|
|
151
|
-
* @return {boolean}
|
|
152
|
-
* @api private
|
|
153
|
-
*/
|
|
154
|
-
function isStatsObject(obj) {
|
|
155
|
-
return isObject(obj) && "ctime" in obj && Object.prototype.toString.call(obj.ctime) === "[object Date]" && "mtime" in obj && Object.prototype.toString.call(obj.mtime) === "[object Date]" && "ino" in obj && typeof obj.ino === "number" && "size" in obj && typeof obj.size === "number";
|
|
156
|
-
}
|
|
157
141
|
async function sha1(str) {
|
|
158
142
|
const enc = new TextEncoder();
|
|
159
143
|
const hash = await subtle.digest("SHA-1", enc.encode(str));
|
|
@@ -163,39 +147,36 @@ async function sha1(str) {
|
|
|
163
147
|
* Generate an ETag.
|
|
164
148
|
*/
|
|
165
149
|
async function generateETag(input) {
|
|
166
|
-
if (isStatsObject(input)) {
|
|
167
|
-
const mtime = input.mtime.getTime().toString(16);
|
|
168
|
-
return `"${input.size.toString(16)}-${mtime}"`;
|
|
169
|
-
}
|
|
170
150
|
if (input.length === 0) return "\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"";
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
return `"${entity.length.toString(16)}-${hash.substring(0, 27)}"`;
|
|
151
|
+
const hash = await sha1(input);
|
|
152
|
+
return `"${input.length.toString(16)}-${hash.substring(0, 27)}"`;
|
|
174
153
|
}
|
|
175
154
|
/**
|
|
176
155
|
* Create a simple ETag.
|
|
177
156
|
*/
|
|
178
|
-
async function createEtag(input, options) {
|
|
179
|
-
options = options || {};
|
|
180
|
-
const weak = typeof options.weak === "boolean" ? options.weak : isStatsObject(input);
|
|
157
|
+
async function createEtag(input, options = {}) {
|
|
181
158
|
const tag = await generateETag(input);
|
|
182
|
-
return weak ? `W/${tag}` : tag;
|
|
159
|
+
return options.weak ? `W/${tag}` : tag;
|
|
160
|
+
}
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/utils/object.ts
|
|
163
|
+
function isObject(item) {
|
|
164
|
+
return !!item && typeof item === "object" && !Array.isArray(item);
|
|
183
165
|
}
|
|
184
166
|
//#endregion
|
|
185
167
|
//#region src/utils/etag/utils.ts
|
|
168
|
+
const textEncoder = /* @__PURE__ */ new TextEncoder();
|
|
186
169
|
function buildEtagFn(input) {
|
|
187
170
|
if (typeof input === "function") return input;
|
|
188
171
|
input = input ?? true;
|
|
189
172
|
if (input === false) return () => Promise.resolve(void 0);
|
|
190
173
|
let options = { weak: true };
|
|
191
174
|
if (isObject(input)) options = merge(input, options);
|
|
192
|
-
return async (body,
|
|
193
|
-
const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
|
|
175
|
+
return async (body, size) => {
|
|
194
176
|
if (typeof options.threshold !== "undefined") {
|
|
195
|
-
|
|
196
|
-
if (size <= options.threshold) return;
|
|
177
|
+
if ((size ?? textEncoder.encode(body).byteLength) <= options.threshold) return;
|
|
197
178
|
}
|
|
198
|
-
return createEtag(
|
|
179
|
+
return createEtag(body, options);
|
|
199
180
|
};
|
|
200
181
|
}
|
|
201
182
|
//#endregion
|
|
@@ -616,6 +597,9 @@ var RoutupEvent = class {
|
|
|
616
597
|
signal;
|
|
617
598
|
_context;
|
|
618
599
|
_routerOptions;
|
|
600
|
+
_nextCalled = false;
|
|
601
|
+
_nextResult;
|
|
602
|
+
_nextCalledDeferred;
|
|
619
603
|
constructor(context) {
|
|
620
604
|
this._context = context;
|
|
621
605
|
this.request = context.request;
|
|
@@ -633,8 +617,32 @@ var RoutupEvent = class {
|
|
|
633
617
|
if (!this._routerOptions) this._routerOptions = this._context.routerOptions();
|
|
634
618
|
return this._routerOptions;
|
|
635
619
|
}
|
|
620
|
+
get nextCalled() {
|
|
621
|
+
return this._nextCalled;
|
|
622
|
+
}
|
|
623
|
+
get nextResult() {
|
|
624
|
+
return this._nextResult;
|
|
625
|
+
}
|
|
626
|
+
whenNextCalled() {
|
|
627
|
+
if (!this._nextCalledDeferred) {
|
|
628
|
+
let resolve;
|
|
629
|
+
const promise = new Promise((r) => {
|
|
630
|
+
resolve = r;
|
|
631
|
+
});
|
|
632
|
+
this._nextCalledDeferred = {
|
|
633
|
+
promise,
|
|
634
|
+
resolve
|
|
635
|
+
};
|
|
636
|
+
if (this._nextCalled) resolve();
|
|
637
|
+
}
|
|
638
|
+
return this._nextCalledDeferred.promise;
|
|
639
|
+
}
|
|
636
640
|
async next(error) {
|
|
637
|
-
return this.
|
|
641
|
+
if (this._nextCalled) return this._nextResult;
|
|
642
|
+
this._nextCalled = true;
|
|
643
|
+
this._nextResult = this._context.next(this, error);
|
|
644
|
+
if (this._nextCalledDeferred) this._nextCalledDeferred.resolve();
|
|
645
|
+
return this._nextResult;
|
|
638
646
|
}
|
|
639
647
|
};
|
|
640
648
|
//#endregion
|
|
@@ -974,11 +982,11 @@ var Handler = class {
|
|
|
974
982
|
if (event.error) {
|
|
975
983
|
const { fn } = this.config;
|
|
976
984
|
const { error } = event;
|
|
977
|
-
result = await this.executeWithTimeout(() => fn(error, handlerEvent), handlerEvent.routerOptions, childController);
|
|
985
|
+
result = await this.executeWithTimeout(() => this.resolveHandlerResult(fn(error, handlerEvent), handlerEvent), handlerEvent.routerOptions, childController);
|
|
978
986
|
}
|
|
979
987
|
} else {
|
|
980
988
|
const { fn } = this.config;
|
|
981
|
-
result = await this.executeWithTimeout(() => fn(handlerEvent), handlerEvent.routerOptions, childController);
|
|
989
|
+
result = await this.executeWithTimeout(() => this.resolveHandlerResult(fn(handlerEvent), handlerEvent), handlerEvent.routerOptions, childController);
|
|
982
990
|
}
|
|
983
991
|
} finally {
|
|
984
992
|
if (cleanupParentListener) cleanupParentListener();
|
|
@@ -1015,6 +1023,41 @@ var Handler = class {
|
|
|
1015
1023
|
this.config.method = method;
|
|
1016
1024
|
this._method = method;
|
|
1017
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Resolve a handler's return value into the final value handed to `toResponse`.
|
|
1028
|
+
*
|
|
1029
|
+
* Contract:
|
|
1030
|
+
* - non-undefined value → return as-is (becomes the response)
|
|
1031
|
+
* - `undefined` + `event.next()` was called → forward downstream result
|
|
1032
|
+
* - `undefined` + `event.next()` not yet called → wait until either `next()` is
|
|
1033
|
+
* invoked (e.g. from an async callback) or `signal` aborts. A global or
|
|
1034
|
+
* per-handler timeout aborts `signal` and surfaces as 408. With no timeout
|
|
1035
|
+
* configured and no eventual `next()` call, the request hangs by design.
|
|
1036
|
+
*/
|
|
1037
|
+
async resolveHandlerResult(invocation, handlerEvent) {
|
|
1038
|
+
const value = await invocation;
|
|
1039
|
+
if (typeof value !== "undefined") return value;
|
|
1040
|
+
if (handlerEvent.nextCalled) return handlerEvent.nextResult;
|
|
1041
|
+
const { signal } = handlerEvent;
|
|
1042
|
+
if (signal.aborted) throw createError({
|
|
1043
|
+
status: 408,
|
|
1044
|
+
message: "Request Timeout"
|
|
1045
|
+
});
|
|
1046
|
+
return new Promise((resolve, reject) => {
|
|
1047
|
+
const onAbort = () => {
|
|
1048
|
+
signal.removeEventListener("abort", onAbort);
|
|
1049
|
+
reject(createError({
|
|
1050
|
+
status: 408,
|
|
1051
|
+
message: "Request Timeout"
|
|
1052
|
+
}));
|
|
1053
|
+
};
|
|
1054
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1055
|
+
handlerEvent.whenNextCalled().then(() => {
|
|
1056
|
+
signal.removeEventListener("abort", onAbort);
|
|
1057
|
+
resolve(handlerEvent.nextResult);
|
|
1058
|
+
});
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1018
1061
|
async executeWithTimeout(fn, routerOptions, controller) {
|
|
1019
1062
|
const effectiveTimeout = this.resolveTimeout(routerOptions);
|
|
1020
1063
|
if (!effectiveTimeout) return fn();
|
|
@@ -1325,7 +1368,9 @@ function getRequestProtocol(event, options = {}) {
|
|
|
1325
1368
|
const PluginErrorCode = {
|
|
1326
1369
|
PLUGIN: "PLUGIN",
|
|
1327
1370
|
NOT_INSTALLED: "PLUGIN_NOT_INSTALLED",
|
|
1328
|
-
|
|
1371
|
+
ALREADY_INSTALLED: "PLUGIN_ALREADY_INSTALLED",
|
|
1372
|
+
INSTALL: "PLUGIN_INSTALL",
|
|
1373
|
+
DEPENDENCY: "PLUGIN_DEPENDENCY"
|
|
1329
1374
|
};
|
|
1330
1375
|
//#endregion
|
|
1331
1376
|
//#region src/plugin/error/is.ts
|
|
@@ -1345,6 +1390,37 @@ var PluginError = class extends RoutupError {
|
|
|
1345
1390
|
}
|
|
1346
1391
|
};
|
|
1347
1392
|
//#endregion
|
|
1393
|
+
//#region src/plugin/error/sub/already-installed.ts
|
|
1394
|
+
var PluginAlreadyInstalledError = class extends PluginError {
|
|
1395
|
+
pluginName;
|
|
1396
|
+
constructor(pluginName) {
|
|
1397
|
+
super({
|
|
1398
|
+
message: `Plugin "${pluginName}" is already installed on this router.`,
|
|
1399
|
+
code: PluginErrorCode.ALREADY_INSTALLED
|
|
1400
|
+
});
|
|
1401
|
+
this.name = "PluginAlreadyInstalledError";
|
|
1402
|
+
this.pluginName = pluginName;
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
//#endregion
|
|
1406
|
+
//#region src/plugin/error/sub/dependency.ts
|
|
1407
|
+
var PluginDependencyError = class extends PluginError {
|
|
1408
|
+
pluginName;
|
|
1409
|
+
dependencyName;
|
|
1410
|
+
constructor(pluginName, dependencyName, detail) {
|
|
1411
|
+
let message;
|
|
1412
|
+
if (detail) message = `Plugin "${pluginName}" requires "${dependencyName}": ${detail}`;
|
|
1413
|
+
else message = `Plugin "${pluginName}" requires plugin "${dependencyName}" to be installed first. Register the dependency plugin before this one.`;
|
|
1414
|
+
super({
|
|
1415
|
+
message,
|
|
1416
|
+
code: PluginErrorCode.DEPENDENCY
|
|
1417
|
+
});
|
|
1418
|
+
this.name = "PluginDependencyError";
|
|
1419
|
+
this.pluginName = pluginName;
|
|
1420
|
+
this.dependencyName = dependencyName;
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
//#endregion
|
|
1348
1424
|
//#region src/plugin/error/sub/install.ts
|
|
1349
1425
|
var PluginInstallError = class extends PluginError {
|
|
1350
1426
|
pluginName;
|
|
@@ -1381,6 +1457,113 @@ function isPlugin(input) {
|
|
|
1381
1457
|
return typeof input.install === "function" && input.install.length === 1;
|
|
1382
1458
|
}
|
|
1383
1459
|
//#endregion
|
|
1460
|
+
//#region src/plugin/semver.ts
|
|
1461
|
+
function parseVersion(version) {
|
|
1462
|
+
const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*))?(?:\+.+)?$/);
|
|
1463
|
+
if (!match) return;
|
|
1464
|
+
return {
|
|
1465
|
+
major: Number(match[1]),
|
|
1466
|
+
minor: Number(match[2]),
|
|
1467
|
+
patch: Number(match[3]),
|
|
1468
|
+
prerelease: match[4] ? match[4].split(".") : void 0
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
function comparePrereleaseIdentifiers(a, b) {
|
|
1472
|
+
const len = Math.max(a.length, b.length);
|
|
1473
|
+
for (let i = 0; i < len; i++) {
|
|
1474
|
+
if (i >= a.length) return -1;
|
|
1475
|
+
if (i >= b.length) return 1;
|
|
1476
|
+
const aId = a[i];
|
|
1477
|
+
const bId = b[i];
|
|
1478
|
+
const aNum = /^\d+$/.test(aId) ? Number(aId) : void 0;
|
|
1479
|
+
const bNum = /^\d+$/.test(bId) ? Number(bId) : void 0;
|
|
1480
|
+
if (aNum !== void 0 && bNum !== void 0) {
|
|
1481
|
+
if (aNum !== bNum) return aNum - bNum;
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
if (aNum !== void 0) return -1;
|
|
1485
|
+
if (bNum !== void 0) return 1;
|
|
1486
|
+
if (aId < bId) return -1;
|
|
1487
|
+
if (aId > bId) return 1;
|
|
1488
|
+
}
|
|
1489
|
+
return 0;
|
|
1490
|
+
}
|
|
1491
|
+
function compareVersions(a, b) {
|
|
1492
|
+
if (a.major !== b.major) return a.major - b.major;
|
|
1493
|
+
if (a.minor !== b.minor) return a.minor - b.minor;
|
|
1494
|
+
if (a.patch !== b.patch) return a.patch - b.patch;
|
|
1495
|
+
if (!a.prerelease && b.prerelease) return 1;
|
|
1496
|
+
if (a.prerelease && !b.prerelease) return -1;
|
|
1497
|
+
if (a.prerelease && b.prerelease) return comparePrereleaseIdentifiers(a.prerelease, b.prerelease);
|
|
1498
|
+
return 0;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Check if a version satisfies a semver constraint.
|
|
1502
|
+
*
|
|
1503
|
+
* Supported constraint formats:
|
|
1504
|
+
* - Exact: '1.2.3'
|
|
1505
|
+
* - Comparison: '>=1.0.0', '>1.0.0', '<=2.0.0', '<2.0.0', '=1.0.0'
|
|
1506
|
+
* - Caret: '^1.2.3' (>=1.2.3 <2.0.0)
|
|
1507
|
+
* - Tilde: '~1.2.3' (>=1.2.3 <1.3.0)
|
|
1508
|
+
*/
|
|
1509
|
+
function satisfiesVersion(version, constraint) {
|
|
1510
|
+
const parsed = parseVersion(version);
|
|
1511
|
+
if (!parsed) return false;
|
|
1512
|
+
return constraint.trim().split(/\s+/).every((part) => satisfiesSingle(parsed, part));
|
|
1513
|
+
}
|
|
1514
|
+
function satisfiesSingle(version, constraint) {
|
|
1515
|
+
if (constraint.startsWith("^")) return satisfiesCaret(version, constraint.substring(1));
|
|
1516
|
+
if (constraint.startsWith("~")) return satisfiesTilde(version, constraint.substring(1));
|
|
1517
|
+
if (constraint.startsWith(">=")) {
|
|
1518
|
+
const target = parseVersion(constraint.substring(2));
|
|
1519
|
+
return !!target && compareVersions(version, target) >= 0;
|
|
1520
|
+
}
|
|
1521
|
+
if (constraint.startsWith(">")) {
|
|
1522
|
+
const target = parseVersion(constraint.substring(1));
|
|
1523
|
+
return !!target && compareVersions(version, target) > 0;
|
|
1524
|
+
}
|
|
1525
|
+
if (constraint.startsWith("<=")) {
|
|
1526
|
+
const target = parseVersion(constraint.substring(2));
|
|
1527
|
+
return !!target && compareVersions(version, target) <= 0;
|
|
1528
|
+
}
|
|
1529
|
+
if (constraint.startsWith("<")) {
|
|
1530
|
+
const target = parseVersion(constraint.substring(1));
|
|
1531
|
+
return !!target && compareVersions(version, target) < 0;
|
|
1532
|
+
}
|
|
1533
|
+
if (constraint.startsWith("=")) {
|
|
1534
|
+
const target = parseVersion(constraint.substring(1));
|
|
1535
|
+
return !!target && compareVersions(version, target) === 0;
|
|
1536
|
+
}
|
|
1537
|
+
const target = parseVersion(constraint);
|
|
1538
|
+
return !!target && compareVersions(version, target) === 0;
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* When the version under test has a prerelease tag, it only matches if it
|
|
1542
|
+
* shares the same [major, minor, patch] tuple as the range's lower bound.
|
|
1543
|
+
* This follows npm semver semantics where prereleases are scoped to their
|
|
1544
|
+
* exact version tuple.
|
|
1545
|
+
*/
|
|
1546
|
+
function prereleaseAllowed(version, min) {
|
|
1547
|
+
if (!version.prerelease) return true;
|
|
1548
|
+
return version.major === min.major && version.minor === min.minor && version.patch === min.patch;
|
|
1549
|
+
}
|
|
1550
|
+
function satisfiesCaret(version, range) {
|
|
1551
|
+
const min = parseVersion(range);
|
|
1552
|
+
if (!min) return false;
|
|
1553
|
+
if (compareVersions(version, min) < 0) return false;
|
|
1554
|
+
if (version.prerelease && !prereleaseAllowed(version, min)) return false;
|
|
1555
|
+
if (min.major > 0) return version.major === min.major;
|
|
1556
|
+
if (min.minor > 0) return version.major === 0 && version.minor === min.minor;
|
|
1557
|
+
return version.major === 0 && version.minor === 0 && version.patch === min.patch;
|
|
1558
|
+
}
|
|
1559
|
+
function satisfiesTilde(version, range) {
|
|
1560
|
+
const min = parseVersion(range);
|
|
1561
|
+
if (!min) return false;
|
|
1562
|
+
if (compareVersions(version, min) < 0) return false;
|
|
1563
|
+
if (version.prerelease && !prereleaseAllowed(version, min)) return false;
|
|
1564
|
+
return version.major === min.major && version.minor === min.minor;
|
|
1565
|
+
}
|
|
1566
|
+
//#endregion
|
|
1384
1567
|
//#region src/router/options.ts
|
|
1385
1568
|
function normalizeRouterOptions(input) {
|
|
1386
1569
|
if (typeof input.etag !== "undefined") input.etag = buildEtagFn(input.etag);
|
|
@@ -1449,6 +1632,18 @@ var Router = class Router {
|
|
|
1449
1632
|
* Normalized options for this router instance.
|
|
1450
1633
|
*/
|
|
1451
1634
|
_options;
|
|
1635
|
+
/**
|
|
1636
|
+
* Registry of installed plugins (name → version).
|
|
1637
|
+
*
|
|
1638
|
+
* @protected
|
|
1639
|
+
*/
|
|
1640
|
+
plugins = /* @__PURE__ */ new Map();
|
|
1641
|
+
/**
|
|
1642
|
+
* Parent router reference for dependency lookups.
|
|
1643
|
+
*
|
|
1644
|
+
* @protected
|
|
1645
|
+
*/
|
|
1646
|
+
parent;
|
|
1452
1647
|
constructor(input = {}) {
|
|
1453
1648
|
this.name = input.name;
|
|
1454
1649
|
this.hookManager = new HookManager();
|
|
@@ -1718,6 +1913,7 @@ var Router = class Router {
|
|
|
1718
1913
|
}
|
|
1719
1914
|
if (isRouterInstance(item)) {
|
|
1720
1915
|
if (path) item.setPath(path);
|
|
1916
|
+
item.parent = this;
|
|
1721
1917
|
this.stack.push(item);
|
|
1722
1918
|
continue;
|
|
1723
1919
|
}
|
|
@@ -1736,11 +1932,52 @@ var Router = class Router {
|
|
|
1736
1932
|
}
|
|
1737
1933
|
return this;
|
|
1738
1934
|
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Check if a plugin with the given name is installed on this router
|
|
1937
|
+
* or any parent router.
|
|
1938
|
+
*/
|
|
1939
|
+
hasPlugin(name) {
|
|
1940
|
+
if (this.plugins.has(name)) return true;
|
|
1941
|
+
if (this.parent) return this.parent.hasPlugin(name);
|
|
1942
|
+
return false;
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Get the version of an installed plugin by name,
|
|
1946
|
+
* searching this router and parent routers.
|
|
1947
|
+
*/
|
|
1948
|
+
getPluginVersion(name) {
|
|
1949
|
+
if (this.plugins.has(name)) return this.plugins.get(name);
|
|
1950
|
+
if (this.parent) return this.parent.getPluginVersion(name);
|
|
1951
|
+
}
|
|
1952
|
+
validatePluginDependencies(plugin) {
|
|
1953
|
+
if (!plugin.dependencies || plugin.dependencies.length === 0) return;
|
|
1954
|
+
for (const dep of plugin.dependencies) {
|
|
1955
|
+
const dependency = typeof dep === "string" ? { name: dep } : dep;
|
|
1956
|
+
if (!this.hasPlugin(dependency.name)) {
|
|
1957
|
+
if (dependency.optional) continue;
|
|
1958
|
+
throw new PluginDependencyError(plugin.name, dependency.name);
|
|
1959
|
+
}
|
|
1960
|
+
if (dependency.version) {
|
|
1961
|
+
const installedVersion = this.getPluginVersion(dependency.name);
|
|
1962
|
+
if (!installedVersion) {
|
|
1963
|
+
if (dependency.optional) continue;
|
|
1964
|
+
throw new PluginDependencyError(plugin.name, dependency.name, `version "${dependency.version}" required but "${dependency.name}" has no version`);
|
|
1965
|
+
}
|
|
1966
|
+
if (!satisfiesVersion(installedVersion, dependency.version)) {
|
|
1967
|
+
if (dependency.optional) continue;
|
|
1968
|
+
throw new PluginDependencyError(plugin.name, dependency.name, `version "${dependency.version}" required but "${installedVersion}" is installed`);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1739
1973
|
install(plugin, context = {}) {
|
|
1740
|
-
|
|
1974
|
+
if (this.plugins.has(plugin.name)) throw new PluginAlreadyInstalledError(plugin.name);
|
|
1975
|
+
this.validatePluginDependencies(plugin);
|
|
1976
|
+
const router = new Router({ name: plugin.name });
|
|
1741
1977
|
plugin.install(router);
|
|
1742
1978
|
if (context.path) this.use(context.path, router);
|
|
1743
1979
|
else this.use(router);
|
|
1980
|
+
this.plugins.set(plugin.name, plugin.version);
|
|
1744
1981
|
return this;
|
|
1745
1982
|
}
|
|
1746
1983
|
on(name, fn, priority) {
|
|
@@ -1756,6 +1993,6 @@ var Router = class Router {
|
|
|
1756
1993
|
}
|
|
1757
1994
|
};
|
|
1758
1995
|
//#endregion
|
|
1759
|
-
export {
|
|
1996
|
+
export { setResponseHeaderAttachment as $, defineErrorHandler as A, sendRedirect as B, isHandler as C, isWebHandlerProvider as D, isWebHandler as E, HandlerSymbol as F, getRequestHeader as G, getRequestAcceptableContentType as H, HandlerType as I, sendAccepted as J, sendFile as K, DispatcherEvent as L, Handler as M, isPath as N, fromNodeHandler as O, PathMatcher as P, setResponseHeaderContentType as Q, RoutupEvent as R, isRequestCacheable as S, fromWebHandler as T, getRequestAcceptableContentTypes as U, sendFormat as V, useRequestNegotiator as W, createError as X, toResponse as Y, isError as Z, getRequestAcceptableLanguages as _, PluginNotInstalledError as a, ErrorSymbol as at, getRequestAcceptableCharset as b, PluginAlreadyInstalledError as c, HeaderName as ct, PluginErrorCode as d, setResponseContentTypeByFileName as et, getRequestProtocol as f, getRequestAcceptableLanguage as g, matchRequestContentType as h, isPlugin as i, serializeEventStreamMessage as it, defineCoreHandler as j, fromNodeMiddleware as k, PluginError as l, MethodName as lt, getRequestHostName as m, normalizeRouterOptions as n, appendResponseHeaderDirective as nt, PluginInstallError as o, RoutupError as ot, getRequestIP as p, sendCreated as q, satisfiesVersion as r, createEventStream as rt, PluginDependencyError as s, setResponseCacheHeaders as st, Router as t, appendResponseHeader as tt, isPluginError as u, getRequestAcceptableEncoding as v, isHandlerOptions as w, getRequestAcceptableCharsets as x, getRequestAcceptableEncodings as y, sendStream as z };
|
|
1760
1997
|
|
|
1761
|
-
//# sourceMappingURL=src-
|
|
1998
|
+
//# sourceMappingURL=src-C32sKqPQ.mjs.map
|