lula2 0.0.7-nightly.1 → 0.0.8

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.
Files changed (30) hide show
  1. package/README.md +45 -28
  2. package/dist/_app/immutable/assets/0.C97xfQzG.css +1 -0
  3. package/dist/_app/immutable/chunks/BJF-sFqz.js +2 -0
  4. package/dist/_app/immutable/chunks/BRXZMf5M.js +3 -0
  5. package/dist/_app/immutable/chunks/{7x_q-1ab.js → BYKwBiub.js} +1 -1
  6. package/dist/_app/immutable/chunks/{BR-0Dorr.js → BqNBD7oY.js} +1 -1
  7. package/dist/_app/immutable/chunks/{D3aNP_lg.js → Bty54Wy4.js} +1 -1
  8. package/dist/_app/immutable/chunks/{B19gt6-g.js → CBYXl-8c.js} +1 -1
  9. package/dist/_app/immutable/chunks/{D4Q_ObIy.js → DUz6FRLu.js} +1 -1
  10. package/dist/_app/immutable/chunks/{K93PaNqe.js → SNK5323Z.js} +1 -1
  11. package/dist/_app/immutable/chunks/{hFa5WFL5.js → kBUVhV9H.js} +1 -1
  12. package/dist/_app/immutable/entry/{app.CR9HAzXp.js → app.DjyXDG_u.js} +2 -2
  13. package/dist/_app/immutable/entry/start.D9LG7NPS.js +1 -0
  14. package/dist/_app/immutable/nodes/{0.C9YpECjX.js → 0.BYRS6Cjd.js} +1 -1
  15. package/dist/_app/immutable/nodes/{1.BnaJJ_DJ.js → 1.Bx4S0PB8.js} +1 -1
  16. package/dist/_app/immutable/nodes/{2.CnXqeUxH.js → 2.x7nEXdOa.js} +1 -1
  17. package/dist/_app/immutable/nodes/{3.CfS9iO7H.js → 3.BYhcPkIl.js} +1 -1
  18. package/dist/_app/immutable/nodes/{4.DICGtP3c.js → 4.CuglzNnD.js} +1 -1
  19. package/dist/_app/version.json +1 -1
  20. package/dist/cli/commands/ui.js +2420 -3
  21. package/dist/cli/commands/version.js +4 -1
  22. package/dist/cli/server/index.js +2420 -3
  23. package/dist/cli/server/server.js +2420 -3
  24. package/dist/index.html +10 -10
  25. package/dist/index.js +2426 -6
  26. package/package.json +122 -120
  27. package/dist/_app/immutable/assets/0.PJPcSyra.css +0 -1
  28. package/dist/_app/immutable/chunks/B_3ksxz5.js +0 -2
  29. package/dist/_app/immutable/chunks/CtdFD_4O.js +0 -3
  30. package/dist/_app/immutable/entry/start.DduHkUe9.js +0 -1
package/dist/index.js CHANGED
@@ -1,13 +1,1566 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
8
  var __esm = (fn, res) => function __init() {
5
9
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
10
  };
11
+ var __commonJS = (cb, mod) => function __require() {
12
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
+ };
7
14
  var __export = (target, all) => {
8
15
  for (var name in all)
9
16
  __defProp(target, name, { get: all[name], enumerable: true });
10
17
  };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
27
+ // If the importer is in node compatibility mode or this is not an ESM
28
+ // file that has been converted to a CommonJS file using a Babel-
29
+ // compatible transform (i.e. "__esModule" has not been set), then set
30
+ // "default" to the CommonJS "module.exports" for node compatibility.
31
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
32
+ mod
33
+ ));
34
+
35
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/common.js
36
+ var require_common = __commonJS({
37
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/common.js"(exports) {
38
+ "use strict";
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.isInSubnet = isInSubnet;
41
+ exports.isCorrect = isCorrect;
42
+ exports.numberToPaddedHex = numberToPaddedHex;
43
+ exports.stringToPaddedHex = stringToPaddedHex;
44
+ exports.testBit = testBit;
45
+ function isInSubnet(address) {
46
+ if (this.subnetMask < address.subnetMask) {
47
+ return false;
48
+ }
49
+ if (this.mask(address.subnetMask) === address.mask()) {
50
+ return true;
51
+ }
52
+ return false;
53
+ }
54
+ function isCorrect(defaultBits) {
55
+ return function() {
56
+ if (this.addressMinusSuffix !== this.correctForm()) {
57
+ return false;
58
+ }
59
+ if (this.subnetMask === defaultBits && !this.parsedSubnet) {
60
+ return true;
61
+ }
62
+ return this.parsedSubnet === String(this.subnetMask);
63
+ };
64
+ }
65
+ function numberToPaddedHex(number) {
66
+ return number.toString(16).padStart(2, "0");
67
+ }
68
+ function stringToPaddedHex(numberString) {
69
+ return numberToPaddedHex(parseInt(numberString, 10));
70
+ }
71
+ function testBit(binaryValue, position) {
72
+ const { length } = binaryValue;
73
+ if (position > length) {
74
+ return false;
75
+ }
76
+ const positionInString = length - position;
77
+ return binaryValue.substring(positionInString, positionInString + 1) === "1";
78
+ }
79
+ }
80
+ });
81
+
82
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v4/constants.js
83
+ var require_constants = __commonJS({
84
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v4/constants.js"(exports) {
85
+ "use strict";
86
+ Object.defineProperty(exports, "__esModule", { value: true });
87
+ exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
88
+ exports.BITS = 32;
89
+ exports.GROUPS = 4;
90
+ exports.RE_ADDRESS = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/g;
91
+ exports.RE_SUBNET_STRING = /\/\d{1,2}$/;
92
+ }
93
+ });
94
+
95
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/address-error.js
96
+ var require_address_error = __commonJS({
97
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/address-error.js"(exports) {
98
+ "use strict";
99
+ Object.defineProperty(exports, "__esModule", { value: true });
100
+ exports.AddressError = void 0;
101
+ var AddressError = class extends Error {
102
+ constructor(message, parseMessage) {
103
+ super(message);
104
+ this.name = "AddressError";
105
+ this.parseMessage = parseMessage;
106
+ }
107
+ };
108
+ exports.AddressError = AddressError;
109
+ }
110
+ });
111
+
112
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ipv4.js
113
+ var require_ipv4 = __commonJS({
114
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ipv4.js"(exports) {
115
+ "use strict";
116
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
117
+ if (k2 === void 0) k2 = k;
118
+ var desc = Object.getOwnPropertyDescriptor(m, k);
119
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
120
+ desc = { enumerable: true, get: function() {
121
+ return m[k];
122
+ } };
123
+ }
124
+ Object.defineProperty(o, k2, desc);
125
+ }) : (function(o, m, k, k2) {
126
+ if (k2 === void 0) k2 = k;
127
+ o[k2] = m[k];
128
+ }));
129
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
130
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
131
+ }) : function(o, v) {
132
+ o["default"] = v;
133
+ });
134
+ var __importStar = exports && exports.__importStar || function(mod) {
135
+ if (mod && mod.__esModule) return mod;
136
+ var result = {};
137
+ if (mod != null) {
138
+ for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
139
+ }
140
+ __setModuleDefault(result, mod);
141
+ return result;
142
+ };
143
+ Object.defineProperty(exports, "__esModule", { value: true });
144
+ exports.Address4 = void 0;
145
+ var common = __importStar(require_common());
146
+ var constants = __importStar(require_constants());
147
+ var address_error_1 = require_address_error();
148
+ var Address4 = class _Address4 {
149
+ constructor(address) {
150
+ this.groups = constants.GROUPS;
151
+ this.parsedAddress = [];
152
+ this.parsedSubnet = "";
153
+ this.subnet = "/32";
154
+ this.subnetMask = 32;
155
+ this.v4 = true;
156
+ this.isCorrect = common.isCorrect(constants.BITS);
157
+ this.isInSubnet = common.isInSubnet;
158
+ this.address = address;
159
+ const subnet = constants.RE_SUBNET_STRING.exec(address);
160
+ if (subnet) {
161
+ this.parsedSubnet = subnet[0].replace("/", "");
162
+ this.subnetMask = parseInt(this.parsedSubnet, 10);
163
+ this.subnet = `/${this.subnetMask}`;
164
+ if (this.subnetMask < 0 || this.subnetMask > constants.BITS) {
165
+ throw new address_error_1.AddressError("Invalid subnet mask.");
166
+ }
167
+ address = address.replace(constants.RE_SUBNET_STRING, "");
168
+ }
169
+ this.addressMinusSuffix = address;
170
+ this.parsedAddress = this.parse(address);
171
+ }
172
+ static isValid(address) {
173
+ try {
174
+ new _Address4(address);
175
+ return true;
176
+ } catch (e) {
177
+ return false;
178
+ }
179
+ }
180
+ /*
181
+ * Parses a v4 address
182
+ */
183
+ parse(address) {
184
+ const groups = address.split(".");
185
+ if (!address.match(constants.RE_ADDRESS)) {
186
+ throw new address_error_1.AddressError("Invalid IPv4 address.");
187
+ }
188
+ return groups;
189
+ }
190
+ /**
191
+ * Returns the correct form of an address
192
+ * @memberof Address4
193
+ * @instance
194
+ * @returns {String}
195
+ */
196
+ correctForm() {
197
+ return this.parsedAddress.map((part) => parseInt(part, 10)).join(".");
198
+ }
199
+ /**
200
+ * Converts a hex string to an IPv4 address object
201
+ * @memberof Address4
202
+ * @static
203
+ * @param {string} hex - a hex string to convert
204
+ * @returns {Address4}
205
+ */
206
+ static fromHex(hex) {
207
+ const padded = hex.replace(/:/g, "").padStart(8, "0");
208
+ const groups = [];
209
+ let i;
210
+ for (i = 0; i < 8; i += 2) {
211
+ const h = padded.slice(i, i + 2);
212
+ groups.push(parseInt(h, 16));
213
+ }
214
+ return new _Address4(groups.join("."));
215
+ }
216
+ /**
217
+ * Converts an integer into a IPv4 address object
218
+ * @memberof Address4
219
+ * @static
220
+ * @param {integer} integer - a number to convert
221
+ * @returns {Address4}
222
+ */
223
+ static fromInteger(integer) {
224
+ return _Address4.fromHex(integer.toString(16));
225
+ }
226
+ /**
227
+ * Return an address from in-addr.arpa form
228
+ * @memberof Address4
229
+ * @static
230
+ * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
231
+ * @returns {Adress4}
232
+ * @example
233
+ * var address = Address4.fromArpa(42.2.0.192.in-addr.arpa.)
234
+ * address.correctForm(); // '192.0.2.42'
235
+ */
236
+ static fromArpa(arpaFormAddress) {
237
+ const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, "");
238
+ const address = leader.split(".").reverse().join(".");
239
+ return new _Address4(address);
240
+ }
241
+ /**
242
+ * Converts an IPv4 address object to a hex string
243
+ * @memberof Address4
244
+ * @instance
245
+ * @returns {String}
246
+ */
247
+ toHex() {
248
+ return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(":");
249
+ }
250
+ /**
251
+ * Converts an IPv4 address object to an array of bytes
252
+ * @memberof Address4
253
+ * @instance
254
+ * @returns {Array}
255
+ */
256
+ toArray() {
257
+ return this.parsedAddress.map((part) => parseInt(part, 10));
258
+ }
259
+ /**
260
+ * Converts an IPv4 address object to an IPv6 address group
261
+ * @memberof Address4
262
+ * @instance
263
+ * @returns {String}
264
+ */
265
+ toGroup6() {
266
+ const output = [];
267
+ let i;
268
+ for (i = 0; i < constants.GROUPS; i += 2) {
269
+ output.push(`${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(this.parsedAddress[i + 1])}`);
270
+ }
271
+ return output.join(":");
272
+ }
273
+ /**
274
+ * Returns the address as a `bigint`
275
+ * @memberof Address4
276
+ * @instance
277
+ * @returns {bigint}
278
+ */
279
+ bigInt() {
280
+ return BigInt(`0x${this.parsedAddress.map((n) => common.stringToPaddedHex(n)).join("")}`);
281
+ }
282
+ /**
283
+ * Helper function getting start address.
284
+ * @memberof Address4
285
+ * @instance
286
+ * @returns {bigint}
287
+ */
288
+ _startAddress() {
289
+ return BigInt(`0b${this.mask() + "0".repeat(constants.BITS - this.subnetMask)}`);
290
+ }
291
+ /**
292
+ * The first address in the range given by this address' subnet.
293
+ * Often referred to as the Network Address.
294
+ * @memberof Address4
295
+ * @instance
296
+ * @returns {Address4}
297
+ */
298
+ startAddress() {
299
+ return _Address4.fromBigInt(this._startAddress());
300
+ }
301
+ /**
302
+ * The first host address in the range given by this address's subnet ie
303
+ * the first address after the Network Address
304
+ * @memberof Address4
305
+ * @instance
306
+ * @returns {Address4}
307
+ */
308
+ startAddressExclusive() {
309
+ const adjust = BigInt("1");
310
+ return _Address4.fromBigInt(this._startAddress() + adjust);
311
+ }
312
+ /**
313
+ * Helper function getting end address.
314
+ * @memberof Address4
315
+ * @instance
316
+ * @returns {bigint}
317
+ */
318
+ _endAddress() {
319
+ return BigInt(`0b${this.mask() + "1".repeat(constants.BITS - this.subnetMask)}`);
320
+ }
321
+ /**
322
+ * The last address in the range given by this address' subnet
323
+ * Often referred to as the Broadcast
324
+ * @memberof Address4
325
+ * @instance
326
+ * @returns {Address4}
327
+ */
328
+ endAddress() {
329
+ return _Address4.fromBigInt(this._endAddress());
330
+ }
331
+ /**
332
+ * The last host address in the range given by this address's subnet ie
333
+ * the last address prior to the Broadcast Address
334
+ * @memberof Address4
335
+ * @instance
336
+ * @returns {Address4}
337
+ */
338
+ endAddressExclusive() {
339
+ const adjust = BigInt("1");
340
+ return _Address4.fromBigInt(this._endAddress() - adjust);
341
+ }
342
+ /**
343
+ * Converts a BigInt to a v4 address object
344
+ * @memberof Address4
345
+ * @static
346
+ * @param {bigint} bigInt - a BigInt to convert
347
+ * @returns {Address4}
348
+ */
349
+ static fromBigInt(bigInt) {
350
+ return _Address4.fromHex(bigInt.toString(16));
351
+ }
352
+ /**
353
+ * Returns the first n bits of the address, defaulting to the
354
+ * subnet mask
355
+ * @memberof Address4
356
+ * @instance
357
+ * @returns {String}
358
+ */
359
+ mask(mask) {
360
+ if (mask === void 0) {
361
+ mask = this.subnetMask;
362
+ }
363
+ return this.getBitsBase2(0, mask);
364
+ }
365
+ /**
366
+ * Returns the bits in the given range as a base-2 string
367
+ * @memberof Address4
368
+ * @instance
369
+ * @returns {string}
370
+ */
371
+ getBitsBase2(start, end) {
372
+ return this.binaryZeroPad().slice(start, end);
373
+ }
374
+ /**
375
+ * Return the reversed ip6.arpa form of the address
376
+ * @memberof Address4
377
+ * @param {Object} options
378
+ * @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
379
+ * @instance
380
+ * @returns {String}
381
+ */
382
+ reverseForm(options) {
383
+ if (!options) {
384
+ options = {};
385
+ }
386
+ const reversed = this.correctForm().split(".").reverse().join(".");
387
+ if (options.omitSuffix) {
388
+ return reversed;
389
+ }
390
+ return `${reversed}.in-addr.arpa.`;
391
+ }
392
+ /**
393
+ * Returns true if the given address is a multicast address
394
+ * @memberof Address4
395
+ * @instance
396
+ * @returns {boolean}
397
+ */
398
+ isMulticast() {
399
+ return this.isInSubnet(new _Address4("224.0.0.0/4"));
400
+ }
401
+ /**
402
+ * Returns a zero-padded base-2 string representation of the address
403
+ * @memberof Address4
404
+ * @instance
405
+ * @returns {string}
406
+ */
407
+ binaryZeroPad() {
408
+ return this.bigInt().toString(2).padStart(constants.BITS, "0");
409
+ }
410
+ /**
411
+ * Groups an IPv4 address for inclusion at the end of an IPv6 address
412
+ * @returns {String}
413
+ */
414
+ groupForV6() {
415
+ const segments = this.parsedAddress;
416
+ return this.address.replace(constants.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments.slice(0, 2).join(".")}</span>.<span class="hover-group group-v4 group-7">${segments.slice(2, 4).join(".")}</span>`);
417
+ }
418
+ };
419
+ exports.Address4 = Address4;
420
+ }
421
+ });
422
+
423
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/constants.js
424
+ var require_constants2 = __commonJS({
425
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/constants.js"(exports) {
426
+ "use strict";
427
+ Object.defineProperty(exports, "__esModule", { value: true });
428
+ exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
429
+ exports.BITS = 128;
430
+ exports.GROUPS = 8;
431
+ exports.SCOPES = {
432
+ 0: "Reserved",
433
+ 1: "Interface local",
434
+ 2: "Link local",
435
+ 4: "Admin local",
436
+ 5: "Site local",
437
+ 8: "Organization local",
438
+ 14: "Global",
439
+ 15: "Reserved"
440
+ };
441
+ exports.TYPES = {
442
+ "ff01::1/128": "Multicast (All nodes on this interface)",
443
+ "ff01::2/128": "Multicast (All routers on this interface)",
444
+ "ff02::1/128": "Multicast (All nodes on this link)",
445
+ "ff02::2/128": "Multicast (All routers on this link)",
446
+ "ff05::2/128": "Multicast (All routers in this site)",
447
+ "ff02::5/128": "Multicast (OSPFv3 AllSPF routers)",
448
+ "ff02::6/128": "Multicast (OSPFv3 AllDR routers)",
449
+ "ff02::9/128": "Multicast (RIP routers)",
450
+ "ff02::a/128": "Multicast (EIGRP routers)",
451
+ "ff02::d/128": "Multicast (PIM routers)",
452
+ "ff02::16/128": "Multicast (MLDv2 reports)",
453
+ "ff01::fb/128": "Multicast (mDNSv6)",
454
+ "ff02::fb/128": "Multicast (mDNSv6)",
455
+ "ff05::fb/128": "Multicast (mDNSv6)",
456
+ "ff02::1:2/128": "Multicast (All DHCP servers and relay agents on this link)",
457
+ "ff05::1:2/128": "Multicast (All DHCP servers and relay agents in this site)",
458
+ "ff02::1:3/128": "Multicast (All DHCP servers on this link)",
459
+ "ff05::1:3/128": "Multicast (All DHCP servers in this site)",
460
+ "::/128": "Unspecified",
461
+ "::1/128": "Loopback",
462
+ "ff00::/8": "Multicast",
463
+ "fe80::/10": "Link-local unicast"
464
+ };
465
+ exports.RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi;
466
+ exports.RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\/$)/gi;
467
+ exports.RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
468
+ exports.RE_ZONE_STRING = /%.*$/;
469
+ exports.RE_URL = /^\[{0,1}([0-9a-f:]+)\]{0,1}/;
470
+ exports.RE_URL_WITH_PORT = /\[([0-9a-f:]+)\]:([0-9]{1,5})/;
471
+ }
472
+ });
473
+
474
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/helpers.js
475
+ var require_helpers = __commonJS({
476
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/helpers.js"(exports) {
477
+ "use strict";
478
+ Object.defineProperty(exports, "__esModule", { value: true });
479
+ exports.spanAllZeroes = spanAllZeroes;
480
+ exports.spanAll = spanAll;
481
+ exports.spanLeadingZeroes = spanLeadingZeroes;
482
+ exports.simpleGroup = simpleGroup;
483
+ function spanAllZeroes(s) {
484
+ return s.replace(/(0+)/g, '<span class="zero">$1</span>');
485
+ }
486
+ function spanAll(s, offset = 0) {
487
+ const letters = s.split("");
488
+ return letters.map((n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`).join("");
489
+ }
490
+ function spanLeadingZeroesSimple(group) {
491
+ return group.replace(/^(0+)/, '<span class="zero">$1</span>');
492
+ }
493
+ function spanLeadingZeroes(address) {
494
+ const groups = address.split(":");
495
+ return groups.map((g) => spanLeadingZeroesSimple(g)).join(":");
496
+ }
497
+ function simpleGroup(addressString, offset = 0) {
498
+ const groups = addressString.split(":");
499
+ return groups.map((g, i) => {
500
+ if (/group-v4/.test(g)) {
501
+ return g;
502
+ }
503
+ return `<span class="hover-group group-${i + offset}">${spanLeadingZeroesSimple(g)}</span>`;
504
+ });
505
+ }
506
+ }
507
+ });
508
+
509
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/regular-expressions.js
510
+ var require_regular_expressions = __commonJS({
511
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/v6/regular-expressions.js"(exports) {
512
+ "use strict";
513
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
514
+ if (k2 === void 0) k2 = k;
515
+ var desc = Object.getOwnPropertyDescriptor(m, k);
516
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
517
+ desc = { enumerable: true, get: function() {
518
+ return m[k];
519
+ } };
520
+ }
521
+ Object.defineProperty(o, k2, desc);
522
+ }) : (function(o, m, k, k2) {
523
+ if (k2 === void 0) k2 = k;
524
+ o[k2] = m[k];
525
+ }));
526
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
527
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
528
+ }) : function(o, v) {
529
+ o["default"] = v;
530
+ });
531
+ var __importStar = exports && exports.__importStar || function(mod) {
532
+ if (mod && mod.__esModule) return mod;
533
+ var result = {};
534
+ if (mod != null) {
535
+ for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
536
+ }
537
+ __setModuleDefault(result, mod);
538
+ return result;
539
+ };
540
+ Object.defineProperty(exports, "__esModule", { value: true });
541
+ exports.ADDRESS_BOUNDARY = void 0;
542
+ exports.groupPossibilities = groupPossibilities;
543
+ exports.padGroup = padGroup;
544
+ exports.simpleRegularExpression = simpleRegularExpression;
545
+ exports.possibleElisions = possibleElisions;
546
+ var v6 = __importStar(require_constants2());
547
+ function groupPossibilities(possibilities) {
548
+ return `(${possibilities.join("|")})`;
549
+ }
550
+ function padGroup(group) {
551
+ if (group.length < 4) {
552
+ return `0{0,${4 - group.length}}${group}`;
553
+ }
554
+ return group;
555
+ }
556
+ exports.ADDRESS_BOUNDARY = "[^A-Fa-f0-9:]";
557
+ function simpleRegularExpression(groups) {
558
+ const zeroIndexes = [];
559
+ groups.forEach((group, i) => {
560
+ const groupInteger = parseInt(group, 16);
561
+ if (groupInteger === 0) {
562
+ zeroIndexes.push(i);
563
+ }
564
+ });
565
+ const possibilities = zeroIndexes.map((zeroIndex) => groups.map((group, i) => {
566
+ if (i === zeroIndex) {
567
+ const elision = i === 0 || i === v6.GROUPS - 1 ? ":" : "";
568
+ return groupPossibilities([padGroup(group), elision]);
569
+ }
570
+ return padGroup(group);
571
+ }).join(":"));
572
+ possibilities.push(groups.map(padGroup).join(":"));
573
+ return groupPossibilities(possibilities);
574
+ }
575
+ function possibleElisions(elidedGroups, moreLeft, moreRight) {
576
+ const left = moreLeft ? "" : ":";
577
+ const right = moreRight ? "" : ":";
578
+ const possibilities = [];
579
+ if (!moreLeft && !moreRight) {
580
+ possibilities.push("::");
581
+ }
582
+ if (moreLeft && moreRight) {
583
+ possibilities.push("");
584
+ }
585
+ if (moreRight && !moreLeft || !moreRight && moreLeft) {
586
+ possibilities.push(":");
587
+ }
588
+ possibilities.push(`${left}(:0{1,4}){1,${elidedGroups - 1}}`);
589
+ possibilities.push(`(0{1,4}:){1,${elidedGroups - 1}}${right}`);
590
+ possibilities.push(`(0{1,4}:){${elidedGroups - 1}}0{1,4}`);
591
+ for (let groups = 1; groups < elidedGroups - 1; groups++) {
592
+ for (let position = 1; position < elidedGroups - groups; position++) {
593
+ possibilities.push(`(0{1,4}:){${position}}:(0{1,4}:){${elidedGroups - position - groups - 1}}0{1,4}`);
594
+ }
595
+ }
596
+ return groupPossibilities(possibilities);
597
+ }
598
+ }
599
+ });
600
+
601
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ipv6.js
602
+ var require_ipv6 = __commonJS({
603
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ipv6.js"(exports) {
604
+ "use strict";
605
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
606
+ if (k2 === void 0) k2 = k;
607
+ var desc = Object.getOwnPropertyDescriptor(m, k);
608
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
609
+ desc = { enumerable: true, get: function() {
610
+ return m[k];
611
+ } };
612
+ }
613
+ Object.defineProperty(o, k2, desc);
614
+ }) : (function(o, m, k, k2) {
615
+ if (k2 === void 0) k2 = k;
616
+ o[k2] = m[k];
617
+ }));
618
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
619
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
620
+ }) : function(o, v) {
621
+ o["default"] = v;
622
+ });
623
+ var __importStar = exports && exports.__importStar || function(mod) {
624
+ if (mod && mod.__esModule) return mod;
625
+ var result = {};
626
+ if (mod != null) {
627
+ for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
628
+ }
629
+ __setModuleDefault(result, mod);
630
+ return result;
631
+ };
632
+ Object.defineProperty(exports, "__esModule", { value: true });
633
+ exports.Address6 = void 0;
634
+ var common = __importStar(require_common());
635
+ var constants4 = __importStar(require_constants());
636
+ var constants6 = __importStar(require_constants2());
637
+ var helpers = __importStar(require_helpers());
638
+ var ipv4_1 = require_ipv4();
639
+ var regular_expressions_1 = require_regular_expressions();
640
+ var address_error_1 = require_address_error();
641
+ var common_1 = require_common();
642
+ function assert(condition) {
643
+ if (!condition) {
644
+ throw new Error("Assertion failed.");
645
+ }
646
+ }
647
+ function addCommas(number) {
648
+ const r = /(\d+)(\d{3})/;
649
+ while (r.test(number)) {
650
+ number = number.replace(r, "$1,$2");
651
+ }
652
+ return number;
653
+ }
654
+ function spanLeadingZeroes4(n) {
655
+ n = n.replace(/^(0{1,})([1-9]+)$/, '<span class="parse-error">$1</span>$2');
656
+ n = n.replace(/^(0{1,})(0)$/, '<span class="parse-error">$1</span>$2');
657
+ return n;
658
+ }
659
+ function compact(address, slice) {
660
+ const s1 = [];
661
+ const s2 = [];
662
+ let i;
663
+ for (i = 0; i < address.length; i++) {
664
+ if (i < slice[0]) {
665
+ s1.push(address[i]);
666
+ } else if (i > slice[1]) {
667
+ s2.push(address[i]);
668
+ }
669
+ }
670
+ return s1.concat(["compact"]).concat(s2);
671
+ }
672
+ function paddedHex(octet) {
673
+ return parseInt(octet, 16).toString(16).padStart(4, "0");
674
+ }
675
+ function unsignByte(b) {
676
+ return b & 255;
677
+ }
678
+ var Address62 = class _Address6 {
679
+ constructor(address, optionalGroups) {
680
+ this.addressMinusSuffix = "";
681
+ this.parsedSubnet = "";
682
+ this.subnet = "/128";
683
+ this.subnetMask = 128;
684
+ this.v4 = false;
685
+ this.zone = "";
686
+ this.isInSubnet = common.isInSubnet;
687
+ this.isCorrect = common.isCorrect(constants6.BITS);
688
+ if (optionalGroups === void 0) {
689
+ this.groups = constants6.GROUPS;
690
+ } else {
691
+ this.groups = optionalGroups;
692
+ }
693
+ this.address = address;
694
+ const subnet = constants6.RE_SUBNET_STRING.exec(address);
695
+ if (subnet) {
696
+ this.parsedSubnet = subnet[0].replace("/", "");
697
+ this.subnetMask = parseInt(this.parsedSubnet, 10);
698
+ this.subnet = `/${this.subnetMask}`;
699
+ if (Number.isNaN(this.subnetMask) || this.subnetMask < 0 || this.subnetMask > constants6.BITS) {
700
+ throw new address_error_1.AddressError("Invalid subnet mask.");
701
+ }
702
+ address = address.replace(constants6.RE_SUBNET_STRING, "");
703
+ } else if (/\//.test(address)) {
704
+ throw new address_error_1.AddressError("Invalid subnet mask.");
705
+ }
706
+ const zone = constants6.RE_ZONE_STRING.exec(address);
707
+ if (zone) {
708
+ this.zone = zone[0];
709
+ address = address.replace(constants6.RE_ZONE_STRING, "");
710
+ }
711
+ this.addressMinusSuffix = address;
712
+ this.parsedAddress = this.parse(this.addressMinusSuffix);
713
+ }
714
+ static isValid(address) {
715
+ try {
716
+ new _Address6(address);
717
+ return true;
718
+ } catch (e) {
719
+ return false;
720
+ }
721
+ }
722
+ /**
723
+ * Convert a BigInt to a v6 address object
724
+ * @memberof Address6
725
+ * @static
726
+ * @param {bigint} bigInt - a BigInt to convert
727
+ * @returns {Address6}
728
+ * @example
729
+ * var bigInt = BigInt('1000000000000');
730
+ * var address = Address6.fromBigInt(bigInt);
731
+ * address.correctForm(); // '::e8:d4a5:1000'
732
+ */
733
+ static fromBigInt(bigInt) {
734
+ const hex = bigInt.toString(16).padStart(32, "0");
735
+ const groups = [];
736
+ let i;
737
+ for (i = 0; i < constants6.GROUPS; i++) {
738
+ groups.push(hex.slice(i * 4, (i + 1) * 4));
739
+ }
740
+ return new _Address6(groups.join(":"));
741
+ }
742
+ /**
743
+ * Convert a URL (with optional port number) to an address object
744
+ * @memberof Address6
745
+ * @static
746
+ * @param {string} url - a URL with optional port number
747
+ * @example
748
+ * var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
749
+ * addressAndPort.address.correctForm(); // 'ffff::'
750
+ * addressAndPort.port; // 8080
751
+ */
752
+ static fromURL(url) {
753
+ let host;
754
+ let port = null;
755
+ let result;
756
+ if (url.indexOf("[") !== -1 && url.indexOf("]:") !== -1) {
757
+ result = constants6.RE_URL_WITH_PORT.exec(url);
758
+ if (result === null) {
759
+ return {
760
+ error: "failed to parse address with port",
761
+ address: null,
762
+ port: null
763
+ };
764
+ }
765
+ host = result[1];
766
+ port = result[2];
767
+ } else if (url.indexOf("/") !== -1) {
768
+ url = url.replace(/^[a-z0-9]+:\/\//, "");
769
+ result = constants6.RE_URL.exec(url);
770
+ if (result === null) {
771
+ return {
772
+ error: "failed to parse address from URL",
773
+ address: null,
774
+ port: null
775
+ };
776
+ }
777
+ host = result[1];
778
+ } else {
779
+ host = url;
780
+ }
781
+ if (port) {
782
+ port = parseInt(port, 10);
783
+ if (port < 0 || port > 65536) {
784
+ port = null;
785
+ }
786
+ } else {
787
+ port = null;
788
+ }
789
+ return {
790
+ address: new _Address6(host),
791
+ port
792
+ };
793
+ }
794
+ /**
795
+ * Create an IPv6-mapped address given an IPv4 address
796
+ * @memberof Address6
797
+ * @static
798
+ * @param {string} address - An IPv4 address string
799
+ * @returns {Address6}
800
+ * @example
801
+ * var address = Address6.fromAddress4('192.168.0.1');
802
+ * address.correctForm(); // '::ffff:c0a8:1'
803
+ * address.to4in6(); // '::ffff:192.168.0.1'
804
+ */
805
+ static fromAddress4(address) {
806
+ const address4 = new ipv4_1.Address4(address);
807
+ const mask6 = constants6.BITS - (constants4.BITS - address4.subnetMask);
808
+ return new _Address6(`::ffff:${address4.correctForm()}/${mask6}`);
809
+ }
810
+ /**
811
+ * Return an address from ip6.arpa form
812
+ * @memberof Address6
813
+ * @static
814
+ * @param {string} arpaFormAddress - an 'ip6.arpa' form address
815
+ * @returns {Adress6}
816
+ * @example
817
+ * var address = Address6.fromArpa(e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.)
818
+ * address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe'
819
+ */
820
+ static fromArpa(arpaFormAddress) {
821
+ let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, "");
822
+ const semicolonAmount = 7;
823
+ if (address.length !== 63) {
824
+ throw new address_error_1.AddressError("Invalid 'ip6.arpa' form.");
825
+ }
826
+ const parts = address.split(".").reverse();
827
+ for (let i = semicolonAmount; i > 0; i--) {
828
+ const insertIndex = i * 4;
829
+ parts.splice(insertIndex, 0, ":");
830
+ }
831
+ address = parts.join("");
832
+ return new _Address6(address);
833
+ }
834
+ /**
835
+ * Return the Microsoft UNC transcription of the address
836
+ * @memberof Address6
837
+ * @instance
838
+ * @returns {String} the Microsoft UNC transcription of the address
839
+ */
840
+ microsoftTranscription() {
841
+ return `${this.correctForm().replace(/:/g, "-")}.ipv6-literal.net`;
842
+ }
843
+ /**
844
+ * Return the first n bits of the address, defaulting to the subnet mask
845
+ * @memberof Address6
846
+ * @instance
847
+ * @param {number} [mask=subnet] - the number of bits to mask
848
+ * @returns {String} the first n bits of the address as a string
849
+ */
850
+ mask(mask = this.subnetMask) {
851
+ return this.getBitsBase2(0, mask);
852
+ }
853
+ /**
854
+ * Return the number of possible subnets of a given size in the address
855
+ * @memberof Address6
856
+ * @instance
857
+ * @param {number} [subnetSize=128] - the subnet size
858
+ * @returns {String}
859
+ */
860
+ // TODO: probably useful to have a numeric version of this too
861
+ possibleSubnets(subnetSize = 128) {
862
+ const availableBits = constants6.BITS - this.subnetMask;
863
+ const subnetBits = Math.abs(subnetSize - constants6.BITS);
864
+ const subnetPowers = availableBits - subnetBits;
865
+ if (subnetPowers < 0) {
866
+ return "0";
867
+ }
868
+ return addCommas((BigInt("2") ** BigInt(subnetPowers)).toString(10));
869
+ }
870
+ /**
871
+ * Helper function getting start address.
872
+ * @memberof Address6
873
+ * @instance
874
+ * @returns {bigint}
875
+ */
876
+ _startAddress() {
877
+ return BigInt(`0b${this.mask() + "0".repeat(constants6.BITS - this.subnetMask)}`);
878
+ }
879
+ /**
880
+ * The first address in the range given by this address' subnet
881
+ * Often referred to as the Network Address.
882
+ * @memberof Address6
883
+ * @instance
884
+ * @returns {Address6}
885
+ */
886
+ startAddress() {
887
+ return _Address6.fromBigInt(this._startAddress());
888
+ }
889
+ /**
890
+ * The first host address in the range given by this address's subnet ie
891
+ * the first address after the Network Address
892
+ * @memberof Address6
893
+ * @instance
894
+ * @returns {Address6}
895
+ */
896
+ startAddressExclusive() {
897
+ const adjust = BigInt("1");
898
+ return _Address6.fromBigInt(this._startAddress() + adjust);
899
+ }
900
+ /**
901
+ * Helper function getting end address.
902
+ * @memberof Address6
903
+ * @instance
904
+ * @returns {bigint}
905
+ */
906
+ _endAddress() {
907
+ return BigInt(`0b${this.mask() + "1".repeat(constants6.BITS - this.subnetMask)}`);
908
+ }
909
+ /**
910
+ * The last address in the range given by this address' subnet
911
+ * Often referred to as the Broadcast
912
+ * @memberof Address6
913
+ * @instance
914
+ * @returns {Address6}
915
+ */
916
+ endAddress() {
917
+ return _Address6.fromBigInt(this._endAddress());
918
+ }
919
+ /**
920
+ * The last host address in the range given by this address's subnet ie
921
+ * the last address prior to the Broadcast Address
922
+ * @memberof Address6
923
+ * @instance
924
+ * @returns {Address6}
925
+ */
926
+ endAddressExclusive() {
927
+ const adjust = BigInt("1");
928
+ return _Address6.fromBigInt(this._endAddress() - adjust);
929
+ }
930
+ /**
931
+ * Return the scope of the address
932
+ * @memberof Address6
933
+ * @instance
934
+ * @returns {String}
935
+ */
936
+ getScope() {
937
+ let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
938
+ if (this.getType() === "Global unicast" && scope !== "Link local") {
939
+ scope = "Global";
940
+ }
941
+ return scope || "Unknown";
942
+ }
943
+ /**
944
+ * Return the type of the address
945
+ * @memberof Address6
946
+ * @instance
947
+ * @returns {String}
948
+ */
949
+ getType() {
950
+ for (const subnet of Object.keys(constants6.TYPES)) {
951
+ if (this.isInSubnet(new _Address6(subnet))) {
952
+ return constants6.TYPES[subnet];
953
+ }
954
+ }
955
+ return "Global unicast";
956
+ }
957
+ /**
958
+ * Return the bits in the given range as a BigInt
959
+ * @memberof Address6
960
+ * @instance
961
+ * @returns {bigint}
962
+ */
963
+ getBits(start, end) {
964
+ return BigInt(`0b${this.getBitsBase2(start, end)}`);
965
+ }
966
+ /**
967
+ * Return the bits in the given range as a base-2 string
968
+ * @memberof Address6
969
+ * @instance
970
+ * @returns {String}
971
+ */
972
+ getBitsBase2(start, end) {
973
+ return this.binaryZeroPad().slice(start, end);
974
+ }
975
+ /**
976
+ * Return the bits in the given range as a base-16 string
977
+ * @memberof Address6
978
+ * @instance
979
+ * @returns {String}
980
+ */
981
+ getBitsBase16(start, end) {
982
+ const length = end - start;
983
+ if (length % 4 !== 0) {
984
+ throw new Error("Length of bits to retrieve must be divisible by four");
985
+ }
986
+ return this.getBits(start, end).toString(16).padStart(length / 4, "0");
987
+ }
988
+ /**
989
+ * Return the bits that are set past the subnet mask length
990
+ * @memberof Address6
991
+ * @instance
992
+ * @returns {String}
993
+ */
994
+ getBitsPastSubnet() {
995
+ return this.getBitsBase2(this.subnetMask, constants6.BITS);
996
+ }
997
+ /**
998
+ * Return the reversed ip6.arpa form of the address
999
+ * @memberof Address6
1000
+ * @param {Object} options
1001
+ * @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
1002
+ * @instance
1003
+ * @returns {String}
1004
+ */
1005
+ reverseForm(options) {
1006
+ if (!options) {
1007
+ options = {};
1008
+ }
1009
+ const characters = Math.floor(this.subnetMask / 4);
1010
+ const reversed = this.canonicalForm().replace(/:/g, "").split("").slice(0, characters).reverse().join(".");
1011
+ if (characters > 0) {
1012
+ if (options.omitSuffix) {
1013
+ return reversed;
1014
+ }
1015
+ return `${reversed}.ip6.arpa.`;
1016
+ }
1017
+ if (options.omitSuffix) {
1018
+ return "";
1019
+ }
1020
+ return "ip6.arpa.";
1021
+ }
1022
+ /**
1023
+ * Return the correct form of the address
1024
+ * @memberof Address6
1025
+ * @instance
1026
+ * @returns {String}
1027
+ */
1028
+ correctForm() {
1029
+ let i;
1030
+ let groups = [];
1031
+ let zeroCounter = 0;
1032
+ const zeroes = [];
1033
+ for (i = 0; i < this.parsedAddress.length; i++) {
1034
+ const value = parseInt(this.parsedAddress[i], 16);
1035
+ if (value === 0) {
1036
+ zeroCounter++;
1037
+ }
1038
+ if (value !== 0 && zeroCounter > 0) {
1039
+ if (zeroCounter > 1) {
1040
+ zeroes.push([i - zeroCounter, i - 1]);
1041
+ }
1042
+ zeroCounter = 0;
1043
+ }
1044
+ }
1045
+ if (zeroCounter > 1) {
1046
+ zeroes.push([this.parsedAddress.length - zeroCounter, this.parsedAddress.length - 1]);
1047
+ }
1048
+ const zeroLengths = zeroes.map((n) => n[1] - n[0] + 1);
1049
+ if (zeroes.length > 0) {
1050
+ const index = zeroLengths.indexOf(Math.max(...zeroLengths));
1051
+ groups = compact(this.parsedAddress, zeroes[index]);
1052
+ } else {
1053
+ groups = this.parsedAddress;
1054
+ }
1055
+ for (i = 0; i < groups.length; i++) {
1056
+ if (groups[i] !== "compact") {
1057
+ groups[i] = parseInt(groups[i], 16).toString(16);
1058
+ }
1059
+ }
1060
+ let correct = groups.join(":");
1061
+ correct = correct.replace(/^compact$/, "::");
1062
+ correct = correct.replace(/(^compact)|(compact$)/, ":");
1063
+ correct = correct.replace(/compact/, "");
1064
+ return correct;
1065
+ }
1066
+ /**
1067
+ * Return a zero-padded base-2 string representation of the address
1068
+ * @memberof Address6
1069
+ * @instance
1070
+ * @returns {String}
1071
+ * @example
1072
+ * var address = new Address6('2001:4860:4001:803::1011');
1073
+ * address.binaryZeroPad();
1074
+ * // '0010000000000001010010000110000001000000000000010000100000000011
1075
+ * // 0000000000000000000000000000000000000000000000000001000000010001'
1076
+ */
1077
+ binaryZeroPad() {
1078
+ return this.bigInt().toString(2).padStart(constants6.BITS, "0");
1079
+ }
1080
+ // TODO: Improve the semantics of this helper function
1081
+ parse4in6(address) {
1082
+ const groups = address.split(":");
1083
+ const lastGroup = groups.slice(-1)[0];
1084
+ const address4 = lastGroup.match(constants4.RE_ADDRESS);
1085
+ if (address4) {
1086
+ this.parsedAddress4 = address4[0];
1087
+ this.address4 = new ipv4_1.Address4(this.parsedAddress4);
1088
+ for (let i = 0; i < this.address4.groups; i++) {
1089
+ if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
1090
+ throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join(".")));
1091
+ }
1092
+ }
1093
+ this.v4 = true;
1094
+ groups[groups.length - 1] = this.address4.toGroup6();
1095
+ address = groups.join(":");
1096
+ }
1097
+ return address;
1098
+ }
1099
+ // TODO: Make private?
1100
+ parse(address) {
1101
+ address = this.parse4in6(address);
1102
+ const badCharacters = address.match(constants6.RE_BAD_CHARACTERS);
1103
+ if (badCharacters) {
1104
+ throw new address_error_1.AddressError(`Bad character${badCharacters.length > 1 ? "s" : ""} detected in address: ${badCharacters.join("")}`, address.replace(constants6.RE_BAD_CHARACTERS, '<span class="parse-error">$1</span>'));
1105
+ }
1106
+ const badAddress = address.match(constants6.RE_BAD_ADDRESS);
1107
+ if (badAddress) {
1108
+ throw new address_error_1.AddressError(`Address failed regex: ${badAddress.join("")}`, address.replace(constants6.RE_BAD_ADDRESS, '<span class="parse-error">$1</span>'));
1109
+ }
1110
+ let groups = [];
1111
+ const halves = address.split("::");
1112
+ if (halves.length === 2) {
1113
+ let first = halves[0].split(":");
1114
+ let last = halves[1].split(":");
1115
+ if (first.length === 1 && first[0] === "") {
1116
+ first = [];
1117
+ }
1118
+ if (last.length === 1 && last[0] === "") {
1119
+ last = [];
1120
+ }
1121
+ const remaining = this.groups - (first.length + last.length);
1122
+ if (!remaining) {
1123
+ throw new address_error_1.AddressError("Error parsing groups");
1124
+ }
1125
+ this.elidedGroups = remaining;
1126
+ this.elisionBegin = first.length;
1127
+ this.elisionEnd = first.length + this.elidedGroups;
1128
+ groups = groups.concat(first);
1129
+ for (let i = 0; i < remaining; i++) {
1130
+ groups.push("0");
1131
+ }
1132
+ groups = groups.concat(last);
1133
+ } else if (halves.length === 1) {
1134
+ groups = address.split(":");
1135
+ this.elidedGroups = 0;
1136
+ } else {
1137
+ throw new address_error_1.AddressError("Too many :: groups found");
1138
+ }
1139
+ groups = groups.map((group) => parseInt(group, 16).toString(16));
1140
+ if (groups.length !== this.groups) {
1141
+ throw new address_error_1.AddressError("Incorrect number of groups found");
1142
+ }
1143
+ return groups;
1144
+ }
1145
+ /**
1146
+ * Return the canonical form of the address
1147
+ * @memberof Address6
1148
+ * @instance
1149
+ * @returns {String}
1150
+ */
1151
+ canonicalForm() {
1152
+ return this.parsedAddress.map(paddedHex).join(":");
1153
+ }
1154
+ /**
1155
+ * Return the decimal form of the address
1156
+ * @memberof Address6
1157
+ * @instance
1158
+ * @returns {String}
1159
+ */
1160
+ decimal() {
1161
+ return this.parsedAddress.map((n) => parseInt(n, 16).toString(10).padStart(5, "0")).join(":");
1162
+ }
1163
+ /**
1164
+ * Return the address as a BigInt
1165
+ * @memberof Address6
1166
+ * @instance
1167
+ * @returns {bigint}
1168
+ */
1169
+ bigInt() {
1170
+ return BigInt(`0x${this.parsedAddress.map(paddedHex).join("")}`);
1171
+ }
1172
+ /**
1173
+ * Return the last two groups of this address as an IPv4 address string
1174
+ * @memberof Address6
1175
+ * @instance
1176
+ * @returns {Address4}
1177
+ * @example
1178
+ * var address = new Address6('2001:4860:4001::1825:bf11');
1179
+ * address.to4().correctForm(); // '24.37.191.17'
1180
+ */
1181
+ to4() {
1182
+ const binary = this.binaryZeroPad().split("");
1183
+ return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join("")}`).toString(16));
1184
+ }
1185
+ /**
1186
+ * Return the v4-in-v6 form of the address
1187
+ * @memberof Address6
1188
+ * @instance
1189
+ * @returns {String}
1190
+ */
1191
+ to4in6() {
1192
+ const address4 = this.to4();
1193
+ const address6 = new _Address6(this.parsedAddress.slice(0, 6).join(":"), 6);
1194
+ const correct = address6.correctForm();
1195
+ let infix = "";
1196
+ if (!/:$/.test(correct)) {
1197
+ infix = ":";
1198
+ }
1199
+ return correct + infix + address4.address;
1200
+ }
1201
+ /**
1202
+ * Return an object containing the Teredo properties of the address
1203
+ * @memberof Address6
1204
+ * @instance
1205
+ * @returns {Object}
1206
+ */
1207
+ inspectTeredo() {
1208
+ const prefix = this.getBitsBase16(0, 32);
1209
+ const bitsForUdpPort = this.getBits(80, 96);
1210
+ const udpPort = (bitsForUdpPort ^ BigInt("0xffff")).toString();
1211
+ const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
1212
+ const bitsForClient4 = this.getBits(96, 128);
1213
+ const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt("0xffffffff")).toString(16));
1214
+ const flagsBase2 = this.getBitsBase2(64, 80);
1215
+ const coneNat = (0, common_1.testBit)(flagsBase2, 15);
1216
+ const reserved = (0, common_1.testBit)(flagsBase2, 14);
1217
+ const groupIndividual = (0, common_1.testBit)(flagsBase2, 8);
1218
+ const universalLocal = (0, common_1.testBit)(flagsBase2, 9);
1219
+ const nonce = BigInt(`0b${flagsBase2.slice(2, 6) + flagsBase2.slice(8, 16)}`).toString(10);
1220
+ return {
1221
+ prefix: `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}`,
1222
+ server4: server4.address,
1223
+ client4: client4.address,
1224
+ flags: flagsBase2,
1225
+ coneNat,
1226
+ microsoft: {
1227
+ reserved,
1228
+ universalLocal,
1229
+ groupIndividual,
1230
+ nonce
1231
+ },
1232
+ udpPort
1233
+ };
1234
+ }
1235
+ /**
1236
+ * Return an object containing the 6to4 properties of the address
1237
+ * @memberof Address6
1238
+ * @instance
1239
+ * @returns {Object}
1240
+ */
1241
+ inspect6to4() {
1242
+ const prefix = this.getBitsBase16(0, 16);
1243
+ const gateway = ipv4_1.Address4.fromHex(this.getBitsBase16(16, 48));
1244
+ return {
1245
+ prefix: prefix.slice(0, 4),
1246
+ gateway: gateway.address
1247
+ };
1248
+ }
1249
+ /**
1250
+ * Return a v6 6to4 address from a v6 v4inv6 address
1251
+ * @memberof Address6
1252
+ * @instance
1253
+ * @returns {Address6}
1254
+ */
1255
+ to6to4() {
1256
+ if (!this.is4()) {
1257
+ return null;
1258
+ }
1259
+ const addr6to4 = [
1260
+ "2002",
1261
+ this.getBitsBase16(96, 112),
1262
+ this.getBitsBase16(112, 128),
1263
+ "",
1264
+ "/16"
1265
+ ].join(":");
1266
+ return new _Address6(addr6to4);
1267
+ }
1268
+ /**
1269
+ * Return a byte array
1270
+ * @memberof Address6
1271
+ * @instance
1272
+ * @returns {Array}
1273
+ */
1274
+ toByteArray() {
1275
+ const valueWithoutPadding = this.bigInt().toString(16);
1276
+ const leadingPad = "0".repeat(valueWithoutPadding.length % 2);
1277
+ const value = `${leadingPad}${valueWithoutPadding}`;
1278
+ const bytes = [];
1279
+ for (let i = 0, length = value.length; i < length; i += 2) {
1280
+ bytes.push(parseInt(value.substring(i, i + 2), 16));
1281
+ }
1282
+ return bytes;
1283
+ }
1284
+ /**
1285
+ * Return an unsigned byte array
1286
+ * @memberof Address6
1287
+ * @instance
1288
+ * @returns {Array}
1289
+ */
1290
+ toUnsignedByteArray() {
1291
+ return this.toByteArray().map(unsignByte);
1292
+ }
1293
+ /**
1294
+ * Convert a byte array to an Address6 object
1295
+ * @memberof Address6
1296
+ * @static
1297
+ * @returns {Address6}
1298
+ */
1299
+ static fromByteArray(bytes) {
1300
+ return this.fromUnsignedByteArray(bytes.map(unsignByte));
1301
+ }
1302
+ /**
1303
+ * Convert an unsigned byte array to an Address6 object
1304
+ * @memberof Address6
1305
+ * @static
1306
+ * @returns {Address6}
1307
+ */
1308
+ static fromUnsignedByteArray(bytes) {
1309
+ const BYTE_MAX = BigInt("256");
1310
+ let result = BigInt("0");
1311
+ let multiplier = BigInt("1");
1312
+ for (let i = bytes.length - 1; i >= 0; i--) {
1313
+ result += multiplier * BigInt(bytes[i].toString(10));
1314
+ multiplier *= BYTE_MAX;
1315
+ }
1316
+ return _Address6.fromBigInt(result);
1317
+ }
1318
+ /**
1319
+ * Returns true if the address is in the canonical form, false otherwise
1320
+ * @memberof Address6
1321
+ * @instance
1322
+ * @returns {boolean}
1323
+ */
1324
+ isCanonical() {
1325
+ return this.addressMinusSuffix === this.canonicalForm();
1326
+ }
1327
+ /**
1328
+ * Returns true if the address is a link local address, false otherwise
1329
+ * @memberof Address6
1330
+ * @instance
1331
+ * @returns {boolean}
1332
+ */
1333
+ isLinkLocal() {
1334
+ if (this.getBitsBase2(0, 64) === "1111111010000000000000000000000000000000000000000000000000000000") {
1335
+ return true;
1336
+ }
1337
+ return false;
1338
+ }
1339
+ /**
1340
+ * Returns true if the address is a multicast address, false otherwise
1341
+ * @memberof Address6
1342
+ * @instance
1343
+ * @returns {boolean}
1344
+ */
1345
+ isMulticast() {
1346
+ return this.getType() === "Multicast";
1347
+ }
1348
+ /**
1349
+ * Returns true if the address is a v4-in-v6 address, false otherwise
1350
+ * @memberof Address6
1351
+ * @instance
1352
+ * @returns {boolean}
1353
+ */
1354
+ is4() {
1355
+ return this.v4;
1356
+ }
1357
+ /**
1358
+ * Returns true if the address is a Teredo address, false otherwise
1359
+ * @memberof Address6
1360
+ * @instance
1361
+ * @returns {boolean}
1362
+ */
1363
+ isTeredo() {
1364
+ return this.isInSubnet(new _Address6("2001::/32"));
1365
+ }
1366
+ /**
1367
+ * Returns true if the address is a 6to4 address, false otherwise
1368
+ * @memberof Address6
1369
+ * @instance
1370
+ * @returns {boolean}
1371
+ */
1372
+ is6to4() {
1373
+ return this.isInSubnet(new _Address6("2002::/16"));
1374
+ }
1375
+ /**
1376
+ * Returns true if the address is a loopback address, false otherwise
1377
+ * @memberof Address6
1378
+ * @instance
1379
+ * @returns {boolean}
1380
+ */
1381
+ isLoopback() {
1382
+ return this.getType() === "Loopback";
1383
+ }
1384
+ // #endregion
1385
+ // #region HTML
1386
+ /**
1387
+ * @returns {String} the address in link form with a default port of 80
1388
+ */
1389
+ href(optionalPort) {
1390
+ if (optionalPort === void 0) {
1391
+ optionalPort = "";
1392
+ } else {
1393
+ optionalPort = `:${optionalPort}`;
1394
+ }
1395
+ return `http://[${this.correctForm()}]${optionalPort}/`;
1396
+ }
1397
+ /**
1398
+ * @returns {String} a link suitable for conveying the address via a URL hash
1399
+ */
1400
+ link(options) {
1401
+ if (!options) {
1402
+ options = {};
1403
+ }
1404
+ if (options.className === void 0) {
1405
+ options.className = "";
1406
+ }
1407
+ if (options.prefix === void 0) {
1408
+ options.prefix = "/#address=";
1409
+ }
1410
+ if (options.v4 === void 0) {
1411
+ options.v4 = false;
1412
+ }
1413
+ let formFunction = this.correctForm;
1414
+ if (options.v4) {
1415
+ formFunction = this.to4in6;
1416
+ }
1417
+ const form = formFunction.call(this);
1418
+ if (options.className) {
1419
+ return `<a href="${options.prefix}${form}" class="${options.className}">${form}</a>`;
1420
+ }
1421
+ return `<a href="${options.prefix}${form}">${form}</a>`;
1422
+ }
1423
+ /**
1424
+ * Groups an address
1425
+ * @returns {String}
1426
+ */
1427
+ group() {
1428
+ if (this.elidedGroups === 0) {
1429
+ return helpers.simpleGroup(this.address).join(":");
1430
+ }
1431
+ assert(typeof this.elidedGroups === "number");
1432
+ assert(typeof this.elisionBegin === "number");
1433
+ const output = [];
1434
+ const [left, right] = this.address.split("::");
1435
+ if (left.length) {
1436
+ output.push(...helpers.simpleGroup(left));
1437
+ } else {
1438
+ output.push("");
1439
+ }
1440
+ const classes = ["hover-group"];
1441
+ for (let i = this.elisionBegin; i < this.elisionBegin + this.elidedGroups; i++) {
1442
+ classes.push(`group-${i}`);
1443
+ }
1444
+ output.push(`<span class="${classes.join(" ")}"></span>`);
1445
+ if (right.length) {
1446
+ output.push(...helpers.simpleGroup(right, this.elisionEnd));
1447
+ } else {
1448
+ output.push("");
1449
+ }
1450
+ if (this.is4()) {
1451
+ assert(this.address4 instanceof ipv4_1.Address4);
1452
+ output.pop();
1453
+ output.push(this.address4.groupForV6());
1454
+ }
1455
+ return output.join(":");
1456
+ }
1457
+ // #endregion
1458
+ // #region Regular expressions
1459
+ /**
1460
+ * Generate a regular expression string that can be used to find or validate
1461
+ * all variations of this address
1462
+ * @memberof Address6
1463
+ * @instance
1464
+ * @param {boolean} substringSearch
1465
+ * @returns {string}
1466
+ */
1467
+ regularExpressionString(substringSearch = false) {
1468
+ let output = [];
1469
+ const address6 = new _Address6(this.correctForm());
1470
+ if (address6.elidedGroups === 0) {
1471
+ output.push((0, regular_expressions_1.simpleRegularExpression)(address6.parsedAddress));
1472
+ } else if (address6.elidedGroups === constants6.GROUPS) {
1473
+ output.push((0, regular_expressions_1.possibleElisions)(constants6.GROUPS));
1474
+ } else {
1475
+ const halves = address6.address.split("::");
1476
+ if (halves[0].length) {
1477
+ output.push((0, regular_expressions_1.simpleRegularExpression)(halves[0].split(":")));
1478
+ }
1479
+ assert(typeof address6.elidedGroups === "number");
1480
+ output.push((0, regular_expressions_1.possibleElisions)(address6.elidedGroups, halves[0].length !== 0, halves[1].length !== 0));
1481
+ if (halves[1].length) {
1482
+ output.push((0, regular_expressions_1.simpleRegularExpression)(halves[1].split(":")));
1483
+ }
1484
+ output = [output.join(":")];
1485
+ }
1486
+ if (!substringSearch) {
1487
+ output = [
1488
+ "(?=^|",
1489
+ regular_expressions_1.ADDRESS_BOUNDARY,
1490
+ "|[^\\w\\:])(",
1491
+ ...output,
1492
+ ")(?=[^\\w\\:]|",
1493
+ regular_expressions_1.ADDRESS_BOUNDARY,
1494
+ "|$)"
1495
+ ];
1496
+ }
1497
+ return output.join("");
1498
+ }
1499
+ /**
1500
+ * Generate a regular expression that can be used to find or validate all
1501
+ * variations of this address.
1502
+ * @memberof Address6
1503
+ * @instance
1504
+ * @param {boolean} substringSearch
1505
+ * @returns {RegExp}
1506
+ */
1507
+ regularExpression(substringSearch = false) {
1508
+ return new RegExp(this.regularExpressionString(substringSearch), "i");
1509
+ }
1510
+ };
1511
+ exports.Address6 = Address62;
1512
+ }
1513
+ });
1514
+
1515
+ // node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ip-address.js
1516
+ var require_ip_address = __commonJS({
1517
+ "node_modules/.pnpm/ip-address@10.0.1/node_modules/ip-address/dist/ip-address.js"(exports) {
1518
+ "use strict";
1519
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
1520
+ if (k2 === void 0) k2 = k;
1521
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1522
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1523
+ desc = { enumerable: true, get: function() {
1524
+ return m[k];
1525
+ } };
1526
+ }
1527
+ Object.defineProperty(o, k2, desc);
1528
+ }) : (function(o, m, k, k2) {
1529
+ if (k2 === void 0) k2 = k;
1530
+ o[k2] = m[k];
1531
+ }));
1532
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
1533
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1534
+ }) : function(o, v) {
1535
+ o["default"] = v;
1536
+ });
1537
+ var __importStar = exports && exports.__importStar || function(mod) {
1538
+ if (mod && mod.__esModule) return mod;
1539
+ var result = {};
1540
+ if (mod != null) {
1541
+ for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
1542
+ }
1543
+ __setModuleDefault(result, mod);
1544
+ return result;
1545
+ };
1546
+ Object.defineProperty(exports, "__esModule", { value: true });
1547
+ exports.v6 = exports.AddressError = exports.Address6 = exports.Address4 = void 0;
1548
+ var ipv4_1 = require_ipv4();
1549
+ Object.defineProperty(exports, "Address4", { enumerable: true, get: function() {
1550
+ return ipv4_1.Address4;
1551
+ } });
1552
+ var ipv6_1 = require_ipv6();
1553
+ Object.defineProperty(exports, "Address6", { enumerable: true, get: function() {
1554
+ return ipv6_1.Address6;
1555
+ } });
1556
+ var address_error_1 = require_address_error();
1557
+ Object.defineProperty(exports, "AddressError", { enumerable: true, get: function() {
1558
+ return address_error_1.AddressError;
1559
+ } });
1560
+ var helpers = __importStar(require_helpers());
1561
+ exports.v6 = { helpers };
1562
+ }
1563
+ });
11
1564
 
12
1565
  // cli/utils/debug.ts
13
1566
  var debug_exports = {};
@@ -2046,10 +3599,867 @@ import open from "open";
2046
3599
  import { join as join7 } from "path";
2047
3600
 
2048
3601
  // cli/server/server.ts
2049
- init_serverState();
2050
- init_spreadsheetRoutes();
2051
3602
  import cors from "cors";
2052
3603
  import express2 from "express";
3604
+
3605
+ // node_modules/.pnpm/express-rate-limit@8.1.0_express@5.1.0/node_modules/express-rate-limit/dist/index.mjs
3606
+ var import_ip_address = __toESM(require_ip_address(), 1);
3607
+ import { isIPv6 } from "node:net";
3608
+ import { isIPv6 as isIPv62 } from "node:net";
3609
+ import { Buffer as Buffer2 } from "node:buffer";
3610
+ import { createHash } from "node:crypto";
3611
+ import { isIP } from "node:net";
3612
+ function ipKeyGenerator(ip, ipv6Subnet = 56) {
3613
+ if (ipv6Subnet && isIPv6(ip)) {
3614
+ return `${new import_ip_address.Address6(`${ip}/${ipv6Subnet}`).startAddress().correctForm()}/${ipv6Subnet}`;
3615
+ }
3616
+ return ip;
3617
+ }
3618
+ var MemoryStore = class {
3619
+ constructor(validations2) {
3620
+ this.validations = validations2;
3621
+ this.previous = /* @__PURE__ */ new Map();
3622
+ this.current = /* @__PURE__ */ new Map();
3623
+ this.localKeys = true;
3624
+ }
3625
+ /**
3626
+ * Method that initializes the store.
3627
+ *
3628
+ * @param options {Options} - The options used to setup the middleware.
3629
+ */
3630
+ init(options) {
3631
+ this.windowMs = options.windowMs;
3632
+ this.validations?.windowMs(this.windowMs);
3633
+ if (this.interval) clearInterval(this.interval);
3634
+ this.interval = setInterval(() => {
3635
+ this.clearExpired();
3636
+ }, this.windowMs);
3637
+ this.interval.unref?.();
3638
+ }
3639
+ /**
3640
+ * Method to fetch a client's hit count and reset time.
3641
+ *
3642
+ * @param key {string} - The identifier for a client.
3643
+ *
3644
+ * @returns {ClientRateLimitInfo | undefined} - The number of hits and reset time for that client.
3645
+ *
3646
+ * @public
3647
+ */
3648
+ async get(key) {
3649
+ return this.current.get(key) ?? this.previous.get(key);
3650
+ }
3651
+ /**
3652
+ * Method to increment a client's hit counter.
3653
+ *
3654
+ * @param key {string} - The identifier for a client.
3655
+ *
3656
+ * @returns {ClientRateLimitInfo} - The number of hits and reset time for that client.
3657
+ *
3658
+ * @public
3659
+ */
3660
+ async increment(key) {
3661
+ const client = this.getClient(key);
3662
+ const now = Date.now();
3663
+ if (client.resetTime.getTime() <= now) {
3664
+ this.resetClient(client, now);
3665
+ }
3666
+ client.totalHits++;
3667
+ return client;
3668
+ }
3669
+ /**
3670
+ * Method to decrement a client's hit counter.
3671
+ *
3672
+ * @param key {string} - The identifier for a client.
3673
+ *
3674
+ * @public
3675
+ */
3676
+ async decrement(key) {
3677
+ const client = this.getClient(key);
3678
+ if (client.totalHits > 0) client.totalHits--;
3679
+ }
3680
+ /**
3681
+ * Method to reset a client's hit counter.
3682
+ *
3683
+ * @param key {string} - The identifier for a client.
3684
+ *
3685
+ * @public
3686
+ */
3687
+ async resetKey(key) {
3688
+ this.current.delete(key);
3689
+ this.previous.delete(key);
3690
+ }
3691
+ /**
3692
+ * Method to reset everyone's hit counter.
3693
+ *
3694
+ * @public
3695
+ */
3696
+ async resetAll() {
3697
+ this.current.clear();
3698
+ this.previous.clear();
3699
+ }
3700
+ /**
3701
+ * Method to stop the timer (if currently running) and prevent any memory
3702
+ * leaks.
3703
+ *
3704
+ * @public
3705
+ */
3706
+ shutdown() {
3707
+ clearInterval(this.interval);
3708
+ void this.resetAll();
3709
+ }
3710
+ /**
3711
+ * Recycles a client by setting its hit count to zero, and reset time to
3712
+ * `windowMs` milliseconds from now.
3713
+ *
3714
+ * NOT to be confused with `#resetKey()`, which removes a client from both the
3715
+ * `current` and `previous` maps.
3716
+ *
3717
+ * @param client {Client} - The client to recycle.
3718
+ * @param now {number} - The current time, to which the `windowMs` is added to get the `resetTime` for the client.
3719
+ *
3720
+ * @return {Client} - The modified client that was passed in, to allow for chaining.
3721
+ */
3722
+ resetClient(client, now = Date.now()) {
3723
+ client.totalHits = 0;
3724
+ client.resetTime.setTime(now + this.windowMs);
3725
+ return client;
3726
+ }
3727
+ /**
3728
+ * Retrieves or creates a client, given a key. Also ensures that the client being
3729
+ * returned is in the `current` map.
3730
+ *
3731
+ * @param key {string} - The key under which the client is (or is to be) stored.
3732
+ *
3733
+ * @returns {Client} - The requested client.
3734
+ */
3735
+ getClient(key) {
3736
+ if (this.current.has(key)) return this.current.get(key);
3737
+ let client;
3738
+ if (this.previous.has(key)) {
3739
+ client = this.previous.get(key);
3740
+ this.previous.delete(key);
3741
+ } else {
3742
+ client = { totalHits: 0, resetTime: /* @__PURE__ */ new Date() };
3743
+ this.resetClient(client);
3744
+ }
3745
+ this.current.set(key, client);
3746
+ return client;
3747
+ }
3748
+ /**
3749
+ * Move current clients to previous, create a new map for current.
3750
+ *
3751
+ * This function is called every `windowMs`.
3752
+ */
3753
+ clearExpired() {
3754
+ this.previous = this.current;
3755
+ this.current = /* @__PURE__ */ new Map();
3756
+ }
3757
+ };
3758
+ var SUPPORTED_DRAFT_VERSIONS = [
3759
+ "draft-6",
3760
+ "draft-7",
3761
+ "draft-8"
3762
+ ];
3763
+ var getResetSeconds = (windowMs, resetTime) => {
3764
+ let resetSeconds;
3765
+ if (resetTime) {
3766
+ const deltaSeconds = Math.ceil((resetTime.getTime() - Date.now()) / 1e3);
3767
+ resetSeconds = Math.max(0, deltaSeconds);
3768
+ } else {
3769
+ resetSeconds = Math.ceil(windowMs / 1e3);
3770
+ }
3771
+ return resetSeconds;
3772
+ };
3773
+ var getPartitionKey = (key) => {
3774
+ const hash = createHash("sha256");
3775
+ hash.update(key);
3776
+ const partitionKey = hash.digest("hex").slice(0, 12);
3777
+ return Buffer2.from(partitionKey).toString("base64");
3778
+ };
3779
+ var setLegacyHeaders = (response, info) => {
3780
+ if (response.headersSent) return;
3781
+ response.setHeader("X-RateLimit-Limit", info.limit.toString());
3782
+ response.setHeader("X-RateLimit-Remaining", info.remaining.toString());
3783
+ if (info.resetTime instanceof Date) {
3784
+ response.setHeader("Date", (/* @__PURE__ */ new Date()).toUTCString());
3785
+ response.setHeader(
3786
+ "X-RateLimit-Reset",
3787
+ Math.ceil(info.resetTime.getTime() / 1e3).toString()
3788
+ );
3789
+ }
3790
+ };
3791
+ var setDraft6Headers = (response, info, windowMs) => {
3792
+ if (response.headersSent) return;
3793
+ const windowSeconds = Math.ceil(windowMs / 1e3);
3794
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
3795
+ response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
3796
+ response.setHeader("RateLimit-Limit", info.limit.toString());
3797
+ response.setHeader("RateLimit-Remaining", info.remaining.toString());
3798
+ if (typeof resetSeconds === "number")
3799
+ response.setHeader("RateLimit-Reset", resetSeconds.toString());
3800
+ };
3801
+ var setDraft7Headers = (response, info, windowMs) => {
3802
+ if (response.headersSent) return;
3803
+ const windowSeconds = Math.ceil(windowMs / 1e3);
3804
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
3805
+ response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
3806
+ response.setHeader(
3807
+ "RateLimit",
3808
+ `limit=${info.limit}, remaining=${info.remaining}, reset=${resetSeconds}`
3809
+ );
3810
+ };
3811
+ var setDraft8Headers = (response, info, windowMs, name, key) => {
3812
+ if (response.headersSent) return;
3813
+ const windowSeconds = Math.ceil(windowMs / 1e3);
3814
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
3815
+ const partitionKey = getPartitionKey(key);
3816
+ const header = `r=${info.remaining}; t=${resetSeconds}`;
3817
+ const policy = `q=${info.limit}; w=${windowSeconds}; pk=:${partitionKey}:`;
3818
+ response.append("RateLimit", `"${name}"; ${header}`);
3819
+ response.append("RateLimit-Policy", `"${name}"; ${policy}`);
3820
+ };
3821
+ var setRetryAfterHeader = (response, info, windowMs) => {
3822
+ if (response.headersSent) return;
3823
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
3824
+ response.setHeader("Retry-After", resetSeconds.toString());
3825
+ };
3826
+ var omitUndefinedProperties = (passedOptions) => {
3827
+ const omittedOptions = {};
3828
+ for (const k of Object.keys(passedOptions)) {
3829
+ const key = k;
3830
+ if (passedOptions[key] !== void 0) {
3831
+ omittedOptions[key] = passedOptions[key];
3832
+ }
3833
+ }
3834
+ return omittedOptions;
3835
+ };
3836
+ var ValidationError = class extends Error {
3837
+ /**
3838
+ * The code must be a string, in snake case and all capital, that starts with
3839
+ * the substring `ERR_ERL_`.
3840
+ *
3841
+ * The message must be a string, starting with an uppercase character,
3842
+ * describing the issue in detail.
3843
+ */
3844
+ constructor(code, message) {
3845
+ const url = `https://express-rate-limit.github.io/${code}/`;
3846
+ super(`${message} See ${url} for more information.`);
3847
+ this.name = this.constructor.name;
3848
+ this.code = code;
3849
+ this.help = url;
3850
+ }
3851
+ };
3852
+ var ChangeWarning = class extends ValidationError {
3853
+ };
3854
+ var usedStores = /* @__PURE__ */ new Set();
3855
+ var singleCountKeys = /* @__PURE__ */ new WeakMap();
3856
+ var validations = {
3857
+ enabled: {
3858
+ default: true
3859
+ },
3860
+ // Should be EnabledValidations type, but that's a circular reference
3861
+ disable() {
3862
+ for (const k of Object.keys(this.enabled)) this.enabled[k] = false;
3863
+ },
3864
+ /**
3865
+ * Checks whether the IP address is valid, and that it does not have a port
3866
+ * number in it.
3867
+ *
3868
+ * See https://github.com/express-rate-limit/express-rate-limit/wiki/Error-Codes#err_erl_invalid_ip_address.
3869
+ *
3870
+ * @param ip {string | undefined} - The IP address provided by Express as request.ip.
3871
+ *
3872
+ * @returns {void}
3873
+ */
3874
+ ip(ip) {
3875
+ if (ip === void 0) {
3876
+ throw new ValidationError(
3877
+ "ERR_ERL_UNDEFINED_IP_ADDRESS",
3878
+ `An undefined 'request.ip' was detected. This might indicate a misconfiguration or the connection being destroyed prematurely.`
3879
+ );
3880
+ }
3881
+ if (!isIP(ip)) {
3882
+ throw new ValidationError(
3883
+ "ERR_ERL_INVALID_IP_ADDRESS",
3884
+ `An invalid 'request.ip' (${ip}) was detected. Consider passing a custom 'keyGenerator' function to the rate limiter.`
3885
+ );
3886
+ }
3887
+ },
3888
+ /**
3889
+ * Makes sure the trust proxy setting is not set to `true`.
3890
+ *
3891
+ * See https://github.com/express-rate-limit/express-rate-limit/wiki/Error-Codes#err_erl_permissive_trust_proxy.
3892
+ *
3893
+ * @param request {Request} - The Express request object.
3894
+ *
3895
+ * @returns {void}
3896
+ */
3897
+ trustProxy(request) {
3898
+ if (request.app.get("trust proxy") === true) {
3899
+ throw new ValidationError(
3900
+ "ERR_ERL_PERMISSIVE_TRUST_PROXY",
3901
+ `The Express 'trust proxy' setting is true, which allows anyone to trivially bypass IP-based rate limiting.`
3902
+ );
3903
+ }
3904
+ },
3905
+ /**
3906
+ * Makes sure the trust proxy setting is set in case the `X-Forwarded-For`
3907
+ * header is present.
3908
+ *
3909
+ * See https://github.com/express-rate-limit/express-rate-limit/wiki/Error-Codes#err_erl_unset_trust_proxy.
3910
+ *
3911
+ * @param request {Request} - The Express request object.
3912
+ *
3913
+ * @returns {void}
3914
+ */
3915
+ xForwardedForHeader(request) {
3916
+ if (request.headers["x-forwarded-for"] && request.app.get("trust proxy") === false) {
3917
+ throw new ValidationError(
3918
+ "ERR_ERL_UNEXPECTED_X_FORWARDED_FOR",
3919
+ `The 'X-Forwarded-For' header is set but the Express 'trust proxy' setting is false (default). This could indicate a misconfiguration which would prevent express-rate-limit from accurately identifying users.`
3920
+ );
3921
+ }
3922
+ },
3923
+ /**
3924
+ * Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
3925
+ *
3926
+ * @param request {Request} - The Express request object.
3927
+ *
3928
+ * @returns {void}
3929
+ */
3930
+ forwardedHeader(request) {
3931
+ if (request.headers.forwarded && request.ip === request.socket?.remoteAddress) {
3932
+ throw new ValidationError(
3933
+ "ERR_ERL_FORWARDED_HEADER",
3934
+ `The 'Forwarded' header (standardized X-Forwarded-For) is set but currently being ignored. Add a custom keyGenerator to use a value from this header.`
3935
+ );
3936
+ }
3937
+ },
3938
+ /**
3939
+ * Ensures totalHits value from store is a positive integer.
3940
+ *
3941
+ * @param hits {any} - The `totalHits` returned by the store.
3942
+ */
3943
+ positiveHits(hits) {
3944
+ if (typeof hits !== "number" || hits < 1 || hits !== Math.round(hits)) {
3945
+ throw new ValidationError(
3946
+ "ERR_ERL_INVALID_HITS",
3947
+ `The totalHits value returned from the store must be a positive integer, got ${hits}`
3948
+ );
3949
+ }
3950
+ },
3951
+ /**
3952
+ * Ensures a single store instance is not used with multiple express-rate-limit instances
3953
+ */
3954
+ unsharedStore(store) {
3955
+ if (usedStores.has(store)) {
3956
+ const maybeUniquePrefix = store?.localKeys ? "" : " (with a unique prefix)";
3957
+ throw new ValidationError(
3958
+ "ERR_ERL_STORE_REUSE",
3959
+ `A Store instance must not be shared across multiple rate limiters. Create a new instance of ${store.constructor.name}${maybeUniquePrefix} for each limiter instead.`
3960
+ );
3961
+ }
3962
+ usedStores.add(store);
3963
+ },
3964
+ /**
3965
+ * Ensures a given key is incremented only once per request.
3966
+ *
3967
+ * @param request {Request} - The Express request object.
3968
+ * @param store {Store} - The store class.
3969
+ * @param key {string} - The key used to store the client's hit count.
3970
+ *
3971
+ * @returns {void}
3972
+ */
3973
+ singleCount(request, store, key) {
3974
+ let storeKeys = singleCountKeys.get(request);
3975
+ if (!storeKeys) {
3976
+ storeKeys = /* @__PURE__ */ new Map();
3977
+ singleCountKeys.set(request, storeKeys);
3978
+ }
3979
+ const storeKey = store.localKeys ? store : store.constructor.name;
3980
+ let keys = storeKeys.get(storeKey);
3981
+ if (!keys) {
3982
+ keys = [];
3983
+ storeKeys.set(storeKey, keys);
3984
+ }
3985
+ const prefixedKey = `${store.prefix ?? ""}${key}`;
3986
+ if (keys.includes(prefixedKey)) {
3987
+ throw new ValidationError(
3988
+ "ERR_ERL_DOUBLE_COUNT",
3989
+ `The hit count for ${key} was incremented more than once for a single request.`
3990
+ );
3991
+ }
3992
+ keys.push(prefixedKey);
3993
+ },
3994
+ /**
3995
+ * Warns the user that the behaviour for `max: 0` / `limit: 0` is
3996
+ * changing in the next major release.
3997
+ *
3998
+ * @param limit {number} - The maximum number of hits per client.
3999
+ *
4000
+ * @returns {void}
4001
+ */
4002
+ limit(limit) {
4003
+ if (limit === 0) {
4004
+ throw new ChangeWarning(
4005
+ "WRN_ERL_MAX_ZERO",
4006
+ "Setting limit or max to 0 disables rate limiting in express-rate-limit v6 and older, but will cause all requests to be blocked in v7"
4007
+ );
4008
+ }
4009
+ },
4010
+ /**
4011
+ * Warns the user that the `draft_polli_ratelimit_headers` option is deprecated
4012
+ * and will be removed in the next major release.
4013
+ *
4014
+ * @param draft_polli_ratelimit_headers {any | undefined} - The now-deprecated setting that was used to enable standard headers.
4015
+ *
4016
+ * @returns {void}
4017
+ */
4018
+ draftPolliHeaders(draft_polli_ratelimit_headers) {
4019
+ if (draft_polli_ratelimit_headers) {
4020
+ throw new ChangeWarning(
4021
+ "WRN_ERL_DEPRECATED_DRAFT_POLLI_HEADERS",
4022
+ `The draft_polli_ratelimit_headers configuration option is deprecated and has been removed in express-rate-limit v7, please set standardHeaders: 'draft-6' instead.`
4023
+ );
4024
+ }
4025
+ },
4026
+ /**
4027
+ * Warns the user that the `onLimitReached` option is deprecated and
4028
+ * will be removed in the next major release.
4029
+ *
4030
+ * @param onLimitReached {any | undefined} - The maximum number of hits per client.
4031
+ *
4032
+ * @returns {void}
4033
+ */
4034
+ onLimitReached(onLimitReached) {
4035
+ if (onLimitReached) {
4036
+ throw new ChangeWarning(
4037
+ "WRN_ERL_DEPRECATED_ON_LIMIT_REACHED",
4038
+ "The onLimitReached configuration option is deprecated and has been removed in express-rate-limit v7."
4039
+ );
4040
+ }
4041
+ },
4042
+ /**
4043
+ * Warns the user when an invalid/unsupported version of the draft spec is passed.
4044
+ *
4045
+ * @param version {any | undefined} - The version passed by the user.
4046
+ *
4047
+ * @returns {void}
4048
+ */
4049
+ headersDraftVersion(version) {
4050
+ if (typeof version !== "string" || // @ts-expect-error This is fine. If version is not in the array, it will just return false.
4051
+ !SUPPORTED_DRAFT_VERSIONS.includes(version)) {
4052
+ const versionString = SUPPORTED_DRAFT_VERSIONS.join(", ");
4053
+ throw new ValidationError(
4054
+ "ERR_ERL_HEADERS_UNSUPPORTED_DRAFT_VERSION",
4055
+ `standardHeaders: only the following versions of the IETF draft specification are supported: ${versionString}.`
4056
+ );
4057
+ }
4058
+ },
4059
+ /**
4060
+ * Warns the user when the selected headers option requires a reset time but
4061
+ * the store does not provide one.
4062
+ *
4063
+ * @param resetTime {Date | undefined} - The timestamp when the client's hit count will be reset.
4064
+ *
4065
+ * @returns {void}
4066
+ */
4067
+ headersResetTime(resetTime) {
4068
+ if (!resetTime) {
4069
+ throw new ValidationError(
4070
+ "ERR_ERL_HEADERS_NO_RESET",
4071
+ `standardHeaders: 'draft-7' requires a 'resetTime', but the store did not provide one. The 'windowMs' value will be used instead, which may cause clients to wait longer than necessary.`
4072
+ );
4073
+ }
4074
+ },
4075
+ /**
4076
+ * Checks the options.validate setting to ensure that only recognized
4077
+ * validations are enabled or disabled.
4078
+ *
4079
+ * If any unrecognized values are found, an error is logged that
4080
+ * includes the list of supported vaidations.
4081
+ */
4082
+ validationsConfig() {
4083
+ const supportedValidations = Object.keys(this).filter(
4084
+ (k) => !["enabled", "disable"].includes(k)
4085
+ );
4086
+ supportedValidations.push("default");
4087
+ for (const key of Object.keys(this.enabled)) {
4088
+ if (!supportedValidations.includes(key)) {
4089
+ throw new ValidationError(
4090
+ "ERR_ERL_UNKNOWN_VALIDATION",
4091
+ `options.validate.${key} is not recognized. Supported validate options are: ${supportedValidations.join(
4092
+ ", "
4093
+ )}.`
4094
+ );
4095
+ }
4096
+ }
4097
+ },
4098
+ /**
4099
+ * Checks to see if the instance was created inside of a request handler,
4100
+ * which would prevent it from working correctly, with the default memory
4101
+ * store (or any other store with localKeys.)
4102
+ */
4103
+ creationStack(store) {
4104
+ const { stack } = new Error(
4105
+ "express-rate-limit validation check (set options.validate.creationStack=false to disable)"
4106
+ );
4107
+ if (stack?.includes("Layer.handle [as handle_request]") || // express v4
4108
+ stack?.includes("Layer.handleRequest")) {
4109
+ if (!store.localKeys) {
4110
+ throw new ValidationError(
4111
+ "ERR_ERL_CREATED_IN_REQUEST_HANDLER",
4112
+ "express-rate-limit instance should *usually* be created at app initialization, not when responding to a request."
4113
+ );
4114
+ }
4115
+ throw new ValidationError(
4116
+ "ERR_ERL_CREATED_IN_REQUEST_HANDLER",
4117
+ "express-rate-limit instance should be created at app initialization, not when responding to a request."
4118
+ );
4119
+ }
4120
+ },
4121
+ ipv6Subnet(ipv6Subnet) {
4122
+ if (ipv6Subnet === false) {
4123
+ return;
4124
+ }
4125
+ if (!Number.isInteger(ipv6Subnet) || ipv6Subnet < 32 || ipv6Subnet > 64) {
4126
+ throw new ValidationError(
4127
+ "ERR_ERL_IPV6_SUBNET",
4128
+ `Unexpected ipv6Subnet value: ${ipv6Subnet}. Expected an integer between 32 and 64 (usually 48-64).`
4129
+ );
4130
+ }
4131
+ },
4132
+ ipv6SubnetOrKeyGenerator(options) {
4133
+ if (options.ipv6Subnet !== void 0 && options.keyGenerator) {
4134
+ throw new ValidationError(
4135
+ "ERR_ERL_IPV6SUBNET_OR_KEYGENERATOR",
4136
+ `Incompatible options: the 'ipv6Subnet' option is ignored when a custom 'keyGenerator' function is also set.`
4137
+ );
4138
+ }
4139
+ },
4140
+ keyGeneratorIpFallback(keyGenerator) {
4141
+ if (!keyGenerator) {
4142
+ return;
4143
+ }
4144
+ const src = keyGenerator.toString();
4145
+ if ((src.includes("req.ip") || src.includes("request.ip")) && !src.includes("ipKeyGenerator")) {
4146
+ throw new ValidationError(
4147
+ "ERR_ERL_KEY_GEN_IPV6",
4148
+ "Custom keyGenerator appears to use request IP without calling the ipKeyGenerator helper function for IPv6 addresses. This could allow IPv6 users to bypass limits."
4149
+ );
4150
+ }
4151
+ },
4152
+ /**
4153
+ * Checks to see if the window duration is greater than 2^32 - 1. This is only
4154
+ * called by the default MemoryStore, since it uses Node's setInterval method.
4155
+ *
4156
+ * See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
4157
+ */
4158
+ windowMs(windowMs) {
4159
+ const SET_TIMEOUT_MAX = 2 ** 31 - 1;
4160
+ if (typeof windowMs !== "number" || Number.isNaN(windowMs) || windowMs < 1 || windowMs > SET_TIMEOUT_MAX) {
4161
+ throw new ValidationError(
4162
+ "ERR_ERL_WINDOW_MS",
4163
+ `Invalid windowMs value: ${windowMs}${typeof windowMs !== "number" ? ` (${typeof windowMs})` : ""}, must be a number between 1 and ${SET_TIMEOUT_MAX} when using the default MemoryStore`
4164
+ );
4165
+ }
4166
+ }
4167
+ };
4168
+ var getValidations = (_enabled) => {
4169
+ let enabled;
4170
+ if (typeof _enabled === "boolean") {
4171
+ enabled = {
4172
+ default: _enabled
4173
+ };
4174
+ } else {
4175
+ enabled = {
4176
+ default: true,
4177
+ ..._enabled
4178
+ };
4179
+ }
4180
+ const wrappedValidations = { enabled };
4181
+ for (const [name, validation] of Object.entries(validations)) {
4182
+ if (typeof validation === "function")
4183
+ wrappedValidations[name] = (...args) => {
4184
+ if (!(enabled[name] ?? enabled.default)) {
4185
+ return;
4186
+ }
4187
+ try {
4188
+ ;
4189
+ validation.apply(
4190
+ wrappedValidations,
4191
+ args
4192
+ );
4193
+ } catch (error) {
4194
+ if (error instanceof ChangeWarning) console.warn(error);
4195
+ else console.error(error);
4196
+ }
4197
+ };
4198
+ }
4199
+ return wrappedValidations;
4200
+ };
4201
+ var isLegacyStore = (store) => (
4202
+ // Check that `incr` exists but `increment` does not - store authors might want
4203
+ // to keep both around for backwards compatibility.
4204
+ typeof store.incr === "function" && typeof store.increment !== "function"
4205
+ );
4206
+ var promisifyStore = (passedStore) => {
4207
+ if (!isLegacyStore(passedStore)) {
4208
+ return passedStore;
4209
+ }
4210
+ const legacyStore = passedStore;
4211
+ class PromisifiedStore {
4212
+ async increment(key) {
4213
+ return new Promise((resolve, reject) => {
4214
+ legacyStore.incr(
4215
+ key,
4216
+ (error, totalHits, resetTime) => {
4217
+ if (error) reject(error);
4218
+ resolve({ totalHits, resetTime });
4219
+ }
4220
+ );
4221
+ });
4222
+ }
4223
+ async decrement(key) {
4224
+ return legacyStore.decrement(key);
4225
+ }
4226
+ async resetKey(key) {
4227
+ return legacyStore.resetKey(key);
4228
+ }
4229
+ /* istanbul ignore next */
4230
+ async resetAll() {
4231
+ if (typeof legacyStore.resetAll === "function")
4232
+ return legacyStore.resetAll();
4233
+ }
4234
+ }
4235
+ return new PromisifiedStore();
4236
+ };
4237
+ var getOptionsFromConfig = (config) => {
4238
+ const { validations: validations2, ...directlyPassableEntries } = config;
4239
+ return {
4240
+ ...directlyPassableEntries,
4241
+ validate: validations2.enabled
4242
+ };
4243
+ };
4244
+ var parseOptions = (passedOptions) => {
4245
+ const notUndefinedOptions = omitUndefinedProperties(passedOptions);
4246
+ const validations2 = getValidations(notUndefinedOptions?.validate ?? true);
4247
+ validations2.validationsConfig();
4248
+ validations2.draftPolliHeaders(
4249
+ // @ts-expect-error see the note above.
4250
+ notUndefinedOptions.draft_polli_ratelimit_headers
4251
+ );
4252
+ validations2.onLimitReached(notUndefinedOptions.onLimitReached);
4253
+ if (notUndefinedOptions.ipv6Subnet !== void 0 && typeof notUndefinedOptions.ipv6Subnet !== "function") {
4254
+ validations2.ipv6Subnet(notUndefinedOptions.ipv6Subnet);
4255
+ }
4256
+ validations2.keyGeneratorIpFallback(notUndefinedOptions.keyGenerator);
4257
+ validations2.ipv6SubnetOrKeyGenerator(notUndefinedOptions);
4258
+ let standardHeaders = notUndefinedOptions.standardHeaders ?? false;
4259
+ if (standardHeaders === true) standardHeaders = "draft-6";
4260
+ const config = {
4261
+ windowMs: 60 * 1e3,
4262
+ limit: passedOptions.max ?? 5,
4263
+ // `max` is deprecated, but support it anyways.
4264
+ message: "Too many requests, please try again later.",
4265
+ statusCode: 429,
4266
+ legacyHeaders: passedOptions.headers ?? true,
4267
+ identifier(request, _response) {
4268
+ let duration = "";
4269
+ const property = config.requestPropertyName;
4270
+ const { limit } = request[property];
4271
+ const seconds = config.windowMs / 1e3;
4272
+ const minutes = config.windowMs / (1e3 * 60);
4273
+ const hours = config.windowMs / (1e3 * 60 * 60);
4274
+ const days = config.windowMs / (1e3 * 60 * 60 * 24);
4275
+ if (seconds < 60) duration = `${seconds}sec`;
4276
+ else if (minutes < 60) duration = `${minutes}min`;
4277
+ else if (hours < 24) duration = `${hours}hr${hours > 1 ? "s" : ""}`;
4278
+ else duration = `${days}day${days > 1 ? "s" : ""}`;
4279
+ return `${limit}-in-${duration}`;
4280
+ },
4281
+ requestPropertyName: "rateLimit",
4282
+ skipFailedRequests: false,
4283
+ skipSuccessfulRequests: false,
4284
+ requestWasSuccessful: (_request, response) => response.statusCode < 400,
4285
+ skip: (_request, _response) => false,
4286
+ async keyGenerator(request, response) {
4287
+ validations2.ip(request.ip);
4288
+ validations2.trustProxy(request);
4289
+ validations2.xForwardedForHeader(request);
4290
+ validations2.forwardedHeader(request);
4291
+ const ip = request.ip;
4292
+ let subnet = 56;
4293
+ if (isIPv62(ip)) {
4294
+ subnet = typeof config.ipv6Subnet === "function" ? await config.ipv6Subnet(request, response) : config.ipv6Subnet;
4295
+ if (typeof config.ipv6Subnet === "function")
4296
+ validations2.ipv6Subnet(subnet);
4297
+ }
4298
+ return ipKeyGenerator(ip, subnet);
4299
+ },
4300
+ ipv6Subnet: 56,
4301
+ async handler(request, response, _next, _optionsUsed) {
4302
+ response.status(config.statusCode);
4303
+ const message = typeof config.message === "function" ? await config.message(
4304
+ request,
4305
+ response
4306
+ ) : config.message;
4307
+ if (!response.writableEnded) response.send(message);
4308
+ },
4309
+ passOnStoreError: false,
4310
+ // Allow the default options to be overridden by the passed options.
4311
+ ...notUndefinedOptions,
4312
+ // `standardHeaders` is resolved into a draft version above, use that.
4313
+ standardHeaders,
4314
+ // Note that this field is declared after the user's options are spread in,
4315
+ // so that this field doesn't get overridden with an un-promisified store!
4316
+ store: promisifyStore(
4317
+ notUndefinedOptions.store ?? new MemoryStore(validations2)
4318
+ ),
4319
+ // Print an error to the console if a few known misconfigurations are detected.
4320
+ validations: validations2
4321
+ };
4322
+ if (typeof config.store.increment !== "function" || typeof config.store.decrement !== "function" || typeof config.store.resetKey !== "function" || config.store.resetAll !== void 0 && typeof config.store.resetAll !== "function" || config.store.init !== void 0 && typeof config.store.init !== "function") {
4323
+ throw new TypeError(
4324
+ "An invalid store was passed. Please ensure that the store is a class that implements the `Store` interface."
4325
+ );
4326
+ }
4327
+ return config;
4328
+ };
4329
+ var handleAsyncErrors = (fn) => async (request, response, next) => {
4330
+ try {
4331
+ await Promise.resolve(fn(request, response, next)).catch(next);
4332
+ } catch (error) {
4333
+ next(error);
4334
+ }
4335
+ };
4336
+ var rateLimit = (passedOptions) => {
4337
+ const config = parseOptions(passedOptions ?? {});
4338
+ const options = getOptionsFromConfig(config);
4339
+ config.validations.creationStack(config.store);
4340
+ config.validations.unsharedStore(config.store);
4341
+ if (typeof config.store.init === "function") config.store.init(options);
4342
+ const middleware = handleAsyncErrors(
4343
+ async (request, response, next) => {
4344
+ const skip = await config.skip(request, response);
4345
+ if (skip) {
4346
+ next();
4347
+ return;
4348
+ }
4349
+ const augmentedRequest = request;
4350
+ const key = await config.keyGenerator(request, response);
4351
+ let totalHits = 0;
4352
+ let resetTime;
4353
+ try {
4354
+ const incrementResult = await config.store.increment(key);
4355
+ totalHits = incrementResult.totalHits;
4356
+ resetTime = incrementResult.resetTime;
4357
+ } catch (error) {
4358
+ if (config.passOnStoreError) {
4359
+ console.error(
4360
+ "express-rate-limit: error from store, allowing request without rate-limiting.",
4361
+ error
4362
+ );
4363
+ next();
4364
+ return;
4365
+ }
4366
+ throw error;
4367
+ }
4368
+ config.validations.positiveHits(totalHits);
4369
+ config.validations.singleCount(request, config.store, key);
4370
+ const retrieveLimit = typeof config.limit === "function" ? config.limit(request, response) : config.limit;
4371
+ const limit = await retrieveLimit;
4372
+ config.validations.limit(limit);
4373
+ const info = {
4374
+ limit,
4375
+ used: totalHits,
4376
+ remaining: Math.max(limit - totalHits, 0),
4377
+ resetTime,
4378
+ key
4379
+ };
4380
+ Object.defineProperty(info, "current", {
4381
+ configurable: false,
4382
+ enumerable: false,
4383
+ value: totalHits
4384
+ });
4385
+ augmentedRequest[config.requestPropertyName] = info;
4386
+ if (config.legacyHeaders && !response.headersSent) {
4387
+ setLegacyHeaders(response, info);
4388
+ }
4389
+ if (config.standardHeaders && !response.headersSent) {
4390
+ switch (config.standardHeaders) {
4391
+ case "draft-6": {
4392
+ setDraft6Headers(response, info, config.windowMs);
4393
+ break;
4394
+ }
4395
+ case "draft-7": {
4396
+ config.validations.headersResetTime(info.resetTime);
4397
+ setDraft7Headers(response, info, config.windowMs);
4398
+ break;
4399
+ }
4400
+ case "draft-8": {
4401
+ const retrieveName = typeof config.identifier === "function" ? config.identifier(request, response) : config.identifier;
4402
+ const name = await retrieveName;
4403
+ config.validations.headersResetTime(info.resetTime);
4404
+ setDraft8Headers(response, info, config.windowMs, name, key);
4405
+ break;
4406
+ }
4407
+ default: {
4408
+ config.validations.headersDraftVersion(config.standardHeaders);
4409
+ break;
4410
+ }
4411
+ }
4412
+ }
4413
+ if (config.skipFailedRequests || config.skipSuccessfulRequests) {
4414
+ let decremented = false;
4415
+ const decrementKey = async () => {
4416
+ if (!decremented) {
4417
+ await config.store.decrement(key);
4418
+ decremented = true;
4419
+ }
4420
+ };
4421
+ if (config.skipFailedRequests) {
4422
+ response.on("finish", async () => {
4423
+ if (!await config.requestWasSuccessful(request, response))
4424
+ await decrementKey();
4425
+ });
4426
+ response.on("close", async () => {
4427
+ if (!response.writableEnded) await decrementKey();
4428
+ });
4429
+ response.on("error", async () => {
4430
+ await decrementKey();
4431
+ });
4432
+ }
4433
+ if (config.skipSuccessfulRequests) {
4434
+ response.on("finish", async () => {
4435
+ if (await config.requestWasSuccessful(request, response))
4436
+ await decrementKey();
4437
+ });
4438
+ }
4439
+ }
4440
+ config.validations.disable();
4441
+ if (totalHits > limit) {
4442
+ if (config.legacyHeaders || config.standardHeaders) {
4443
+ setRetryAfterHeader(response, info, config.windowMs);
4444
+ }
4445
+ config.handler(request, response, next, options);
4446
+ return;
4447
+ }
4448
+ next();
4449
+ }
4450
+ );
4451
+ const getThrowFn = () => {
4452
+ throw new Error("The current store does not support the get/getKey method");
4453
+ };
4454
+ middleware.resetKey = config.store.resetKey.bind(config.store);
4455
+ middleware.getKey = typeof config.store.get === "function" ? config.store.get.bind(config.store) : getThrowFn;
4456
+ return middleware;
4457
+ };
4458
+ var rate_limit_default = rateLimit;
4459
+
4460
+ // cli/server/server.ts
4461
+ init_serverState();
4462
+ init_spreadsheetRoutes();
2053
4463
  import { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
2054
4464
  import { createServer as createHttpServer } from "http";
2055
4465
  import { dirname as dirname2, join as join6 } from "path";
@@ -2666,15 +5076,22 @@ async function createServer(options) {
2666
5076
  if (!existsSync4(controlSetDir)) {
2667
5077
  mkdirSync3(controlSetDir, { recursive: true });
2668
5078
  }
5079
+ const limiter = rate_limit_default({
5080
+ windowMs: 15 * 60 * 1e3,
5081
+ // 15 minutes
5082
+ max: 200
5083
+ // max requests per windowMs
5084
+ });
2669
5085
  initializeServerState(controlSetDir);
2670
5086
  await loadAllData();
2671
5087
  const app = express2();
2672
5088
  app.use(cors());
2673
5089
  app.use(express2.json({ limit: "50mb" }));
5090
+ app.use(limiter);
2674
5091
  const distPath = join6(__dirname, "../dist");
2675
5092
  app.use(express2.static(distPath));
2676
5093
  app.use("/api", spreadsheetRoutes_default);
2677
- app.get("*", (req, res) => {
5094
+ app.get("/*splat", (req, res) => {
2678
5095
  res.sendFile(join6(distPath, "index.html"));
2679
5096
  });
2680
5097
  const httpServer = createHttpServer(app);
@@ -2775,7 +5192,10 @@ import fs3 from "fs";
2775
5192
  import path from "path";
2776
5193
  var __dirname2 = path.dirname(fileURLToPath2(import.meta.url));
2777
5194
  function getVersion() {
2778
- const pkgPath = path.resolve(__dirname2, "../package.json");
5195
+ let pkgPath = path.resolve(__dirname2, "../package.json");
5196
+ if (!fs3.existsSync(pkgPath)) {
5197
+ pkgPath = path.resolve(__dirname2, "../../package.json");
5198
+ }
2779
5199
  const packageJson = fs3.readFileSync(pkgPath, "utf8");
2780
5200
  const { version } = JSON.parse(packageJson);
2781
5201
  return version;
@@ -2785,7 +5205,7 @@ function getVersion() {
2785
5205
  import fs4 from "fs";
2786
5206
  import { Octokit } from "@octokit/rest";
2787
5207
  import { Command } from "commander";
2788
- import { createHash } from "crypto";
5208
+ import { createHash as createHash2 } from "crypto";
2789
5209
  function getPRContext() {
2790
5210
  const fallbackOwner = process.env.OWNER;
2791
5211
  const fallbackRepo = process.env.REPO;
@@ -2882,7 +5302,7 @@ function crawlCommand() {
2882
5302
  const changedBlocks = getChangedBlocks(oldText, newText);
2883
5303
  for (const block of changedBlocks) {
2884
5304
  const newBlockText = newText.split("\n").slice(block.startLine, block.endLine).join("\n");
2885
- const blockSha256 = createHash("sha256").update(newBlockText).digest("hex");
5305
+ const blockSha256 = createHash2("sha256").update(newBlockText).digest("hex");
2886
5306
  const commentBody = `**Compliance Alert**:\`${file.filename}\` changed between lines ${block.startLine + 1}\u2013${block.endLine}.
2887
5307
  UUID \`${block.uuid}\` may be out of compliance.
2888
5308
  SHA-256 of block contents: \`${blockSha256}\`.