From 495104026698fd01eeb8acd0a14b9aa62625ab87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s?= Date: Sun, 14 Jun 2026 13:52:45 +0200 Subject: [PATCH 01/14] update package + metrics --- bun.lock | 577 ++++++ package.json | 15 +- pnpm-lock.yaml | 2623 ------------------------- src/config.ts | 3 - src/connection/connection.commands.ts | 14 +- src/hosts/host.commands.ts | 9 +- src/hosts/host.entity.ts | 5 +- src/hosts/host.repository.ts | 3 +- src/logger.ts | 3 - src/metrics/metrics.ts | 38 +- src/noray.ts | 53 +- 11 files changed, 634 insertions(+), 2709 deletions(-) create mode 100644 bun.lock delete mode 100644 pnpm-lock.yaml diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..4d802ce --- /dev/null +++ b/bun.lock @@ -0,0 +1,577 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "@foxssake/noray", + "dependencies": { + "@foxssake/trimsock-bun": "^0.17.0", + "@foxssake/trimsock-js": "^0.17.0", + "dotenv": "^16.0.3", + "nanoid": "^4.0.1", + "pino": "^8.11.0", + "prom-client": "^14.2.0", + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "eslint": "^10.4.1", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "pino-pretty": "^10.0.0", + "sinon": "^22.0.0", + "typescript": "^6.0.3", + "typescript-eslint": "^8.60.1", + "utap": "^0.2.0", + }, + }, + }, + "packages": { + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "3.4.3" }, "peerDependencies": { "eslint": "10.4.1" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "3.0.5", "debug": "4.4.3", "minimatch": "10.2.5" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.6.0", "", { "dependencies": { "@eslint/core": "1.2.1" } }, "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA=="], + + "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="], + + "@eslint/js": ["@eslint/js@10.0.1", "", { "optionalDependencies": { "eslint": "10.4.1" } }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="], + + "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.2", "", { "dependencies": { "@eslint/core": "1.2.1", "levn": "0.4.1" } }, "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A=="], + + "@foxssake/trimsock-bun": ["@foxssake/trimsock-bun@0.17.0", "", { "dependencies": { "@foxssake/trimsock-js": "*" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-hHMcFUt6yCT5FhbEW4C+skVDFBmcM4V3YQ0KQFG60H0cPV4onVbol+l6ObXVb8ad8BhUXbxTs7H6XQNEvnNMjQ=="], + + "@foxssake/trimsock-js": ["@foxssake/trimsock-js@0.17.0", "", { "peerDependencies": { "typescript": "6.0.3" } }, "sha512-s81agKjOeUOZ/E+3SdjIntEnc7r879QbREBsVPmDvHuw2tDUdq7SsWJomNjwdFpt8Vlqj7WVTQ+pioo2T5De2A=="], + + "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], + + "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "0.19.2", "@humanfs/types": "0.15.0", "@humanwhocodes/retry": "0.4.3" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="], + + "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "@sinonjs/fake-timers": ["@sinonjs/fake-timers@15.4.0", "", { "dependencies": { "@sinonjs/commons": "3.0.1" } }, "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA=="], + + "@sinonjs/samsam": ["@sinonjs/samsam@10.0.2", "", { "dependencies": { "@sinonjs/commons": "3.0.1", "type-detect": "4.1.0" } }, "sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A=="], + + "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="], + + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.60.1", "", { "dependencies": { "@eslint-community/regexpp": "4.12.2", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/type-utils": "8.60.1", "@typescript-eslint/utils": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "ignore": "7.0.5", "natural-compare": "1.4.0", "ts-api-utils": "2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "8.60.1", "eslint": "10.4.1", "typescript": "6.0.3" } }, "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.60.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "4.4.3" }, "peerDependencies": { "eslint": "10.4.1", "typescript": "6.0.3" } }, "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.60.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "8.60.1", "@typescript-eslint/types": "8.60.1", "debug": "4.4.3" }, "peerDependencies": { "typescript": "6.0.3" } }, "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1" } }, "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.60.1", "", { "peerDependencies": { "typescript": "6.0.3" } }, "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1", "debug": "4.4.3", "ts-api-utils": "2.5.0" }, "peerDependencies": { "eslint": "10.4.1", "typescript": "6.0.3" } }, "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.60.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.60.1", "@typescript-eslint/tsconfig-utils": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "4.4.3", "minimatch": "10.2.5", "semver": "7.8.2", "tinyglobby": "0.2.17", "ts-api-utils": "2.5.0" }, "peerDependencies": { "typescript": "6.0.3" } }, "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.60.1", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1" }, "peerDependencies": { "eslint": "10.4.1", "typescript": "6.0.3" } }, "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "5.0.1" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], + + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "5.0.1" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "8.16.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-json-stable-stringify": "2.1.0", "json-schema-traverse": "0.4.1", "uri-js": "4.4.1" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "is-array-buffer": "3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "is-string": "1.1.1" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "es-shim-unscopables": "1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-shim-unscopables": "1.1.0" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-shim-unscopables": "1.1.0" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "is-array-buffer": "3.0.5" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "1.1.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bintrees": ["bintrees@1.0.2", "", {}, "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw=="], + + "brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "1.5.1", "ieee754": "1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + + "builtins": ["builtins@5.1.0", "", { "dependencies": { "semver": "7.7.2" } }, "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg=="], + + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "get-intrinsic": "1.3.0", "set-function-length": "1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "1.3.0", "function-bind": "1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "get-intrinsic": "1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], + + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "1.0.1", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "1.1.4", "has-property-descriptors": "1.0.2", "object-keys": "1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], + + "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "arraybuffer.prototype.slice": "1.0.4", "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "call-bound": "1.0.4", "data-view-buffer": "1.0.2", "data-view-byte-length": "1.0.2", "data-view-byte-offset": "1.0.1", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "es-set-tostringtag": "2.1.0", "es-to-primitive": "1.3.0", "function.prototype.name": "1.1.8", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "get-symbol-description": "1.1.0", "globalthis": "1.0.4", "gopd": "1.2.0", "has-property-descriptors": "1.0.2", "has-proto": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.2", "internal-slot": "1.1.0", "is-array-buffer": "3.0.5", "is-callable": "1.2.7", "is-data-view": "1.0.2", "is-negative-zero": "2.0.3", "is-regex": "1.2.1", "is-set": "2.0.3", "is-shared-array-buffer": "1.0.4", "is-string": "1.1.1", "is-typed-array": "1.1.15", "is-weakref": "1.1.1", "math-intrinsics": "1.1.0", "object-inspect": "1.13.4", "object-keys": "1.1.1", "object.assign": "4.1.7", "own-keys": "1.0.1", "regexp.prototype.flags": "1.5.4", "safe-array-concat": "1.1.3", "safe-push-apply": "1.0.0", "safe-regex-test": "1.1.0", "set-proto": "1.0.0", "stop-iteration-iterator": "1.1.0", "string.prototype.trim": "1.2.10", "string.prototype.trimend": "1.0.9", "string.prototype.trimstart": "1.0.8", "typed-array-buffer": "1.0.3", "typed-array-byte-length": "1.0.3", "typed-array-byte-offset": "1.0.4", "typed-array-length": "1.0.7", "unbox-primitive": "1.1.0", "which-typed-array": "1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "has-tostringtag": "1.0.2", "hasown": "2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "1.2.7", "is-date-object": "1.1.0", "is-symbol": "1.1.1" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@10.4.1", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/config-array": "0.23.5", "@eslint/config-helpers": "0.6.0", "@eslint/core": "1.2.1", "@eslint/plugin-kit": "0.7.2", "@humanfs/node": "0.16.8", "@humanwhocodes/module-importer": "1.0.1", "@humanwhocodes/retry": "0.4.3", "@types/estree": "1.0.9", "ajv": "6.15.0", "cross-spawn": "7.0.6", "debug": "4.4.3", "escape-string-regexp": "4.0.0", "eslint-scope": "9.1.2", "eslint-visitor-keys": "5.0.1", "espree": "11.2.0", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "8.0.0", "find-up": "5.0.0", "glob-parent": "6.0.2", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "json-stable-stringify-without-jsonify": "1.0.1", "minimatch": "10.2.5", "natural-compare": "1.4.0", "optionator": "0.9.4" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw=="], + + "eslint-config-standard": ["eslint-config-standard@17.1.0", "", { "peerDependencies": { "eslint": "10.4.1", "eslint-plugin-import": "2.31.0", "eslint-plugin-n": "15.7.0", "eslint-plugin-promise": "6.6.0" } }, "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q=="], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "3.2.7", "is-core-module": "2.16.1", "resolve": "1.22.10" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.0", "", { "dependencies": { "debug": "3.2.7" }, "optionalDependencies": { "@typescript-eslint/parser": "8.60.1", "eslint": "10.4.1", "eslint-import-resolver-node": "0.3.9" } }, "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg=="], + + "eslint-plugin-es": ["eslint-plugin-es@4.1.0", "", { "dependencies": { "eslint-utils": "2.1.0", "regexpp": "3.2.0" }, "peerDependencies": { "eslint": "10.4.1" } }, "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.31.0", "", { "dependencies": { "@rtsao/scc": "1.1.0", "array-includes": "3.1.8", "array.prototype.findlastindex": "1.2.6", "array.prototype.flat": "1.3.3", "array.prototype.flatmap": "1.3.3", "debug": "3.2.7", "doctrine": "2.1.0", "eslint-import-resolver-node": "0.3.9", "eslint-module-utils": "2.12.0", "hasown": "2.0.2", "is-core-module": "2.16.1", "is-glob": "4.0.3", "minimatch": "3.1.2", "object.fromentries": "2.0.8", "object.groupby": "1.0.3", "object.values": "1.2.1", "semver": "6.3.1", "string.prototype.trimend": "1.0.9", "tsconfig-paths": "3.15.0" }, "optionalDependencies": { "@typescript-eslint/parser": "8.60.1" }, "peerDependencies": { "eslint": "10.4.1" } }, "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A=="], + + "eslint-plugin-n": ["eslint-plugin-n@15.7.0", "", { "dependencies": { "builtins": "5.1.0", "eslint-plugin-es": "4.1.0", "eslint-utils": "3.0.0", "ignore": "5.3.2", "is-core-module": "2.16.1", "minimatch": "3.1.2", "resolve": "1.22.10", "semver": "7.7.2" }, "peerDependencies": { "eslint": "10.4.1" } }, "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q=="], + + "eslint-plugin-promise": ["eslint-plugin-promise@6.6.0", "", { "peerDependencies": { "eslint": "10.4.1" } }, "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ=="], + + "eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "4.3.1", "@types/estree": "1.0.9", "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="], + + "eslint-utils": ["eslint-utils@3.0.0", "", { "dependencies": { "eslint-visitor-keys": "2.1.0" }, "peerDependencies": { "eslint": "10.4.1" } }, "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "8.16.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + + "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], + + "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + + "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "4.0.1" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "6.0.0", "path-exists": "4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "3.4.2", "keyv": "4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "functions-have-names": "1.2.3", "hasown": "2.0.2", "is-callable": "1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "function-bind": "1.1.2", "get-proto": "1.0.1", "gopd": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.2", "math-intrinsics": "1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "1.0.1", "es-object-atoms": "1.1.1" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "1.2.1", "gopd": "1.2.0" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "1.0.1" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "1.0.1" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "1.1.0" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "hasown": "2.0.2", "side-channel": "1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "1.0.0", "call-bound": "1.0.4", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "1.1.0" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "gopd": "1.2.0", "has-tostringtag": "1.0.2", "hasown": "2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-symbols": "1.1.0", "safe-regex-test": "1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "1.1.19" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "1.2.8" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "1.2.1", "type-check": "0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@4.0.2", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1", "has-symbols": "1.1.0", "object-keys": "1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-object-atoms": "1.1.1" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "0.1.4", "fast-levenshtein": "2.0.6", "levn": "0.4.1", "prelude-ls": "1.2.1", "type-check": "0.4.0", "word-wrap": "1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "1.3.0", "object-keys": "1.1.1", "safe-push-apply": "1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "3.1.0" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "pino": ["pino@8.21.0", "", { "dependencies": { "atomic-sleep": "1.0.0", "fast-redact": "3.5.0", "on-exit-leak-free": "2.1.2", "pino-abstract-transport": "1.2.0", "pino-std-serializers": "6.2.2", "process-warning": "3.0.0", "quick-format-unescaped": "4.0.4", "real-require": "0.2.0", "safe-stable-stringify": "2.5.0", "sonic-boom": "3.8.1", "thread-stream": "2.7.0" }, "bin": { "pino": "bin.js" } }, "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q=="], + + "pino-abstract-transport": ["pino-abstract-transport@1.2.0", "", { "dependencies": { "readable-stream": "4.7.0", "split2": "4.2.0" } }, "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q=="], + + "pino-pretty": ["pino-pretty@10.3.1", "", { "dependencies": { "colorette": "2.0.20", "dateformat": "4.6.3", "fast-copy": "3.0.2", "fast-safe-stringify": "2.1.1", "help-me": "5.0.0", "joycon": "3.1.1", "minimist": "1.2.8", "on-exit-leak-free": "2.1.2", "pino-abstract-transport": "1.2.0", "pump": "3.0.2", "readable-stream": "4.7.0", "secure-json-parse": "2.7.0", "sonic-boom": "3.8.1", "strip-json-comments": "3.1.1" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g=="], + + "pino-std-serializers": ["pino-std-serializers@6.2.2", "", {}, "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + + "process-warning": ["process-warning@3.0.0", "", {}, "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="], + + "prom-client": ["prom-client@14.2.0", "", { "dependencies": { "tdigest": "0.1.2" } }, "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA=="], + + "pump": ["pump@3.0.2", "", { "dependencies": { "end-of-stream": "1.4.4", "once": "1.4.0" } }, "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + + "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "3.0.0", "buffer": "6.0.3", "events": "3.3.0", "process": "0.11.10", "string_decoder": "1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + + "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "which-builtin-type": "1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-errors": "1.3.0", "get-proto": "1.0.1", "gopd": "1.2.0", "set-function-name": "2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "regexpp": ["regexpp@3.2.0", "", {}, "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="], + + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "2.16.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "has-symbols": "1.1.0", "isarray": "2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "1.3.0", "isarray": "2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-regex": "1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + + "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "function-bind": "1.1.2", "get-intrinsic": "1.3.0", "gopd": "1.2.0", "has-property-descriptors": "1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "functions-have-names": "1.2.3", "has-property-descriptors": "1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4", "side-channel-list": "1.0.0", "side-channel-map": "1.0.1", "side-channel-weakmap": "1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4", "side-channel-map": "1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "sinon": ["sinon@22.0.0", "", { "dependencies": { "@sinonjs/commons": "3.0.1", "@sinonjs/fake-timers": "15.4.0", "@sinonjs/samsam": "10.0.2", "diff": "9.0.0" } }, "sha512-sq/6DpdXOrLyfbKlXLg/Usc7xu8YXPeLkOFZRvA3bNUSA2lhbrZ06yuXbH1fkzBPCbz9O10+7hznzUsjaYNm0Q=="], + + "sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "1.0.0" } }, "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "internal-slot": "1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-data-property": "1.1.4", "define-properties": "1.2.1", "es-abstract": "1.24.0", "es-object-atoms": "1.1.1", "has-property-descriptors": "1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "tdigest": ["tdigest@0.1.2", "", { "dependencies": { "bintrees": "1.0.2" } }, "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA=="], + + "thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="], + + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + + "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": "6.0.3" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], + + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "0.0.29", "json5": "1.0.2", "minimist": "1.2.8", "strip-bom": "3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15", "reflect.getprototypeof": "1.0.10" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "is-typed-array": "1.1.15", "possible-typed-array-names": "1.1.0", "reflect.getprototypeof": "1.0.10" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "typescript-eslint": ["typescript-eslint@8.60.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.60.1", "@typescript-eslint/parser": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1" }, "peerDependencies": { "eslint": "10.4.1", "typescript": "6.0.3" } }, "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-bigints": "1.1.0", "has-symbols": "1.1.0", "which-boxed-primitive": "1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "2.3.1" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "utap": ["utap@0.2.0", "", { "dependencies": { "chalk": "5.4.1" }, "bin": { "utap": "src/utap.js" } }, "sha512-YbDY2Qb/+UHUc7Qhued83UzmTyxSozwczDpWxLs4Htees2H7Krj7WkmMbyJI4Pq2UCxQuPHrVv4/kozHz4WWYQ=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "1.1.0", "is-boolean-object": "1.2.2", "is-number-object": "1.1.1", "is-string": "1.1.1", "is-symbol": "1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "function.prototype.name": "1.1.8", "has-tostringtag": "1.0.2", "is-async-function": "2.1.1", "is-date-object": "1.1.0", "is-finalizationregistry": "1.1.1", "is-generator-function": "1.1.0", "is-regex": "1.2.1", "is-weakref": "1.1.1", "isarray": "2.0.5", "which-boxed-primitive": "1.1.1", "which-collection": "1.0.2", "which-typed-array": "1.1.19" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "2.0.3", "is-set": "2.0.3", "is-weakmap": "2.0.2", "is-weakset": "2.0.4" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "call-bound": "1.0.4", "for-each": "0.3.5", "get-proto": "1.0.1", "gopd": "1.2.0", "has-tostringtag": "1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@sinonjs/samsam/type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/semver": ["semver@7.8.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ=="], + + "builtins/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-es/eslint-utils": ["eslint-utils@2.1.0", "", { "dependencies": { "eslint-visitor-keys": "1.3.0" } }, "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.11" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "eslint-plugin-n/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.11" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "eslint-plugin-n/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="], + + "eslint-plugin-es/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@1.3.0", "", {}, "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="], + + "eslint-plugin-import/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], + + "eslint-plugin-n/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], + + "eslint-plugin-import/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "eslint-plugin-n/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + } +} diff --git a/package.json b/package.json index b654e95..877a408 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "lint": "eslint src bin", "test": "node --test test/spec/**/*.test.ts", "test:e2e": "node --test test/e2e/**/*.test.ts | node scripts/taplog.ts utap \"pino-pretty -c\"", - "start": "node bin/noray.ts | pino-pretty", - "start:prod": "NODE_ENV=production node bin/noray.ts" + "start": "bun bin/noray.ts | pino-pretty", + "start:prod": "NODE_ENV=production bun bin/noray.ts" }, "keywords": [ "online", @@ -43,18 +43,13 @@ }, "dependencies": { "@foxssake/trimsock-js": "^0.17.0", - "@foxssake/trimsock-node": "^0.17.0", - "dotenv": "^16.0.3", + "@foxssake/trimsock-bun": "^0.17.0", "nanoid": "^4.0.1", "pino": "^8.11.0", "prom-client": "^14.2.0" }, - "devEngines": { - "runtime": { - "name": "node", - "version": "24.x", - "onFail": "download" - } + "engines": { + "bun": ">=1.3.0" }, "files": [ "src/*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 910876e..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,2623 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@foxssake/trimsock-js': - specifier: ^0.17.0 - version: 0.17.0(typescript@6.0.3) - '@foxssake/trimsock-node': - specifier: ^0.17.0 - version: 0.17.0(typescript@6.0.3) - dotenv: - specifier: ^16.0.3 - version: 16.5.0 - nanoid: - specifier: ^4.0.1 - version: 4.0.2 - pino: - specifier: ^8.11.0 - version: 8.21.0 - prom-client: - specifier: ^14.2.0 - version: 14.2.0 - devDependencies: - '@eslint/js': - specifier: ^10.0.1 - version: 10.0.1(eslint@10.4.1) - eslint: - specifier: ^10.4.1 - version: 10.4.1 - eslint-config-standard: - specifier: ^17.0.0 - version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1))(eslint-plugin-n@15.7.0(eslint@10.4.1))(eslint-plugin-promise@6.6.0(eslint@10.4.1))(eslint@10.4.1) - eslint-plugin-import: - specifier: ^2.25.2 - version: 2.31.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1) - eslint-plugin-n: - specifier: ^15.0.0 - version: 15.7.0(eslint@10.4.1) - eslint-plugin-promise: - specifier: ^6.0.0 - version: 6.6.0(eslint@10.4.1) - node: - specifier: runtime:24.x - version: runtime:24.16.0 - pino-pretty: - specifier: ^10.0.0 - version: 10.3.1 - sinon: - specifier: ^22.0.0 - version: 22.0.0 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - typescript-eslint: - specifier: ^8.60.1 - version: 8.60.1(eslint@10.4.1)(typescript@6.0.3) - utap: - specifier: ^0.2.0 - version: 0.2.0 - -packages: - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.23.5': - resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/config-helpers@0.6.0': - resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/core@1.2.1': - resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/js@10.0.1': - resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^10.0.0 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/object-schema@3.0.5': - resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/plugin-kit@0.7.2': - resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@foxssake/trimsock-js@0.17.0': - resolution: {integrity: sha512-s81agKjOeUOZ/E+3SdjIntEnc7r879QbREBsVPmDvHuw2tDUdq7SsWJomNjwdFpt8Vlqj7WVTQ+pioo2T5De2A==} - peerDependencies: - typescript: ^5.0.0 - - '@foxssake/trimsock-node@0.17.0': - resolution: {integrity: sha512-28SDnnfICDCYD8ROA4PtwGwa1gc8piBxbXwl7qqOFqUwpGYpHMgMWzeYVCs1nQ4oMT66UQ4QpJMPrsSMOQTl0Q==} - engines: {node: '>=18.16.0'} - peerDependencies: - typescript: ^5.0.0 - - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@15.4.0': - resolution: {integrity: sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==} - - '@sinonjs/samsam@10.0.2': - resolution: {integrity: sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==} - - '@types/esrecurse@4.3.1': - resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@typescript-eslint/eslint-plugin@8.60.1': - resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.60.1 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.60.1': - resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.60.1': - resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.60.1': - resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.60.1': - resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.60.1': - resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/types@8.60.1': - resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.60.1': - resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.60.1': - resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.60.1': - resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - - atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bintrees@1.0.2: - resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - builtins@5.1.0: - resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - chalk@5.4.1: - resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - dateformat@4.6.3: - resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - diff@9.0.0: - resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} - engines: {node: '>=0.3.1'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - dotenv@16.5.0: - resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} - - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-standard@17.1.0: - resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} - engines: {node: '>=12.0.0'} - peerDependencies: - eslint: ^8.0.1 - eslint-plugin-import: ^2.25.2 - eslint-plugin-n: '^15.0.0 || ^16.0.0 ' - eslint-plugin-promise: ^6.0.0 - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-es@4.1.0: - resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} - engines: {node: '>=8.10.0'} - peerDependencies: - eslint: '>=4.19.1' - - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-n@15.7.0: - resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} - engines: {node: '>=12.22.0'} - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-promise@6.6.0: - resolution: {integrity: sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - - eslint-scope@9.1.2: - resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} - - eslint-utils@3.0.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - - eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - - eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@10.4.1: - resolution: {integrity: sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@11.2.0: - resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - fast-copy@3.0.2: - resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - - fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - help-me@5.0.0: - resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@4.0.2: - resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==} - engines: {node: ^14 || ^16 || >=18} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node@runtime:24.16.0: - resolution: - type: variations - variants: - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-MN/Y5EMiwnEoE/JeFjwlPK1TvkPgmJB7i1NIvxdKSWg= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-aix-ppc64.tar.gz - targets: - - cpu: ppc64 - os: aix - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-ORidq07rFXBsQkrwrAijBEyeSPfbEqfXf2t6r8fdXfY= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-darwin-arm64.tar.gz - targets: - - cpu: arm64 - os: darwin - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-KYtMezy4B2XIcD5CuQMkpOzjtmNJR7iedpw8mAq1UYU= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-darwin-x64.tar.gz - targets: - - cpu: x64 - os: darwin - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-WJ9bbdT8/uTf2nMBOQPJZquqir2T28nUNlRORytPDnQ= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-arm64.tar.gz - targets: - - cpu: arm64 - os: linux - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-JStYIFNNwDBKKFQcmkRDfPpyAufyAiXSjUk5MsWOl6o= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-ppc64le.tar.gz - targets: - - cpu: ppc64le - os: linux - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-Vnrwl1s0BVFrmx3cZEKaI+yMWi+mzwE5EmGkzHdOPt0= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-s390x.tar.gz - targets: - - cpu: s390x - os: linux - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-L69qOH6bYriI4hxU8BJJ+ydTf/7PGELyn0yRnQpZoP8= - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-x64.tar.gz - targets: - - cpu: x64 - os: linux - - resolution: - archive: zip - bin: - node: node.exe - integrity: sha256-FINGEdTGs8BgVOcAdzK5BHTBbgsy85XgW1Wlce9xxtI= - prefix: node-v24.16.0-win-arm64 - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-win-arm64.zip - targets: - - cpu: arm64 - os: win32 - - resolution: - archive: zip - bin: - node: node.exe - integrity: sha256-7aypvVjsjpIDfaxOh31S9rj0MLgcGLV+JktOL7ERzVY= - prefix: node-v24.16.0-win-x64 - type: binary - url: https://nodejs.org/download/release/v24.16.0/node-v24.16.0-win-x64.zip - targets: - - cpu: x64 - os: win32 - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-hd3ieqc1A7A9rfoEEKgABntOP3Avt/yqO+ryhN/Maek= - type: binary - url: https://unofficial-builds.nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-arm64-musl.tar.gz - targets: - - cpu: arm64 - os: linux - libc: musl - - resolution: - archive: tarball - bin: - node: bin/node - integrity: sha256-UN9djUdIktT3uQYWffNvd/W5OQj2PcUy3FaCGcq2WEE= - type: binary - url: https://unofficial-builds.nodejs.org/download/release/v24.16.0/node-v24.16.0-linux-x64-musl.tar.gz - targets: - - cpu: x64 - os: linux - libc: musl - version: 24.16.0 - hasBin: true - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} - - on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pino-abstract-transport@1.2.0: - resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} - - pino-pretty@10.3.1: - resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==} - hasBin: true - - pino-std-serializers@6.2.2: - resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} - - pino@8.21.0: - resolution: {integrity: sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==} - hasBin: true - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - process-warning@3.0.0: - resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - prom-client@14.2.0: - resolution: {integrity: sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==} - engines: {node: '>=10'} - - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} - - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} - - secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - semver@7.8.2: - resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==} - engines: {node: '>=10'} - hasBin: true - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - sinon@22.0.0: - resolution: {integrity: sha512-sq/6DpdXOrLyfbKlXLg/Usc7xu8YXPeLkOFZRvA3bNUSA2lhbrZ06yuXbH1fkzBPCbz9O10+7hznzUsjaYNm0Q==} - - sonic-boom@3.8.1: - resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tdigest@0.1.2: - resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} - - thread-stream@2.7.0: - resolution: {integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==} - - tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - typescript-eslint@8.60.1: - resolution: {integrity: sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} - hasBin: true - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - utap@0.2.0: - resolution: {integrity: sha512-YbDY2Qb/+UHUc7Qhued83UzmTyxSozwczDpWxLs4Htees2H7Krj7WkmMbyJI4Pq2UCxQuPHrVv4/kozHz4WWYQ==} - engines: {node: '>=18'} - hasBin: true - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - -snapshots: - - '@eslint-community/eslint-utils@4.9.1(eslint@10.4.1)': - dependencies: - eslint: 10.4.1 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.23.5': - dependencies: - '@eslint/object-schema': 3.0.5 - debug: 4.4.3 - minimatch: 10.2.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.6.0': - dependencies: - '@eslint/core': 1.2.1 - - '@eslint/core@1.2.1': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/js@10.0.1(eslint@10.4.1)': - optionalDependencies: - eslint: 10.4.1 - - '@eslint/object-schema@3.0.5': {} - - '@eslint/plugin-kit@0.7.2': - dependencies: - '@eslint/core': 1.2.1 - levn: 0.4.1 - - '@foxssake/trimsock-js@0.17.0(typescript@6.0.3)': - dependencies: - typescript: 6.0.3 - - '@foxssake/trimsock-node@0.17.0(typescript@6.0.3)': - dependencies: - '@foxssake/trimsock-js': 0.17.0(typescript@6.0.3) - typescript: 6.0.3 - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@rtsao/scc@1.1.0': {} - - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 - - '@sinonjs/fake-timers@15.4.0': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@sinonjs/samsam@10.0.2': - dependencies: - '@sinonjs/commons': 3.0.1 - type-detect: 4.1.0 - - '@types/esrecurse@4.3.1': {} - - '@types/estree@1.0.9': {} - - '@types/json-schema@7.0.15': {} - - '@types/json5@0.0.29': {} - - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1)(typescript@6.0.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.60.1 - eslint: 10.4.1 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.60.1 - debug: 4.4.3 - eslint: 10.4.1 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.60.1(typescript@6.0.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3) - '@typescript-eslint/types': 8.60.1 - debug: 4.4.3 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.60.1': - dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 - - '@typescript-eslint/tsconfig-utils@8.60.1(typescript@6.0.3)': - dependencies: - typescript: 6.0.3 - - '@typescript-eslint/type-utils@8.60.1(eslint@10.4.1)(typescript@6.0.3)': - dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - debug: 4.4.3 - eslint: 10.4.1 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.60.1': {} - - '@typescript-eslint/typescript-estree@8.60.1(typescript@6.0.3)': - dependencies: - '@typescript-eslint/project-service': 8.60.1(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3) - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.8.2 - tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.60.1(eslint@10.4.1)(typescript@6.0.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - eslint: 10.4.1 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.60.1': - dependencies: - '@typescript-eslint/types': 8.60.1 - eslint-visitor-keys: 5.0.1 - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-includes@3.1.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - - array.prototype.flat@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 - - array.prototype.flatmap@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - async-function@1.0.0: {} - - atomic-sleep@1.0.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - base64-js@1.5.1: {} - - bintrees@1.0.2: {} - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.4 - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - builtins@5.1.0: - dependencies: - semver: 7.7.2 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - chalk@5.4.1: {} - - colorette@2.0.20: {} - - concat-map@0.0.1: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - dateformat@4.6.3: {} - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - diff@9.0.0: {} - - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - dotenv@16.5.0: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - es-abstract@1.24.0: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-shim-unscopables@1.1.0: - dependencies: - hasown: 2.0.2 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - escape-string-regexp@4.0.0: {} - - eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1))(eslint-plugin-n@15.7.0(eslint@10.4.1))(eslint-plugin-promise@6.6.0(eslint@10.4.1))(eslint@10.4.1): - dependencies: - eslint: 10.4.1 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1) - eslint-plugin-n: 15.7.0(eslint@10.4.1) - eslint-plugin-promise: 6.6.0(eslint@10.4.1) - - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.1 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint@10.4.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - eslint: 10.4.1 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - - eslint-plugin-es@4.1.0(eslint@10.4.1): - dependencies: - eslint: 10.4.1 - eslint-utils: 2.1.0 - regexpp: 3.2.0 - - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 10.4.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint@10.4.1) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-n@15.7.0(eslint@10.4.1): - dependencies: - builtins: 5.1.0 - eslint: 10.4.1 - eslint-plugin-es: 4.1.0(eslint@10.4.1) - eslint-utils: 3.0.0(eslint@10.4.1) - ignore: 5.3.2 - is-core-module: 2.16.1 - minimatch: 3.1.2 - resolve: 1.22.10 - semver: 7.7.2 - - eslint-plugin-promise@6.6.0(eslint@10.4.1): - dependencies: - eslint: 10.4.1 - - eslint-scope@9.1.2: - dependencies: - '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.9 - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-utils@2.1.0: - dependencies: - eslint-visitor-keys: 1.3.0 - - eslint-utils@3.0.0(eslint@10.4.1): - dependencies: - eslint: 10.4.1 - eslint-visitor-keys: 2.1.0 - - eslint-visitor-keys@1.3.0: {} - - eslint-visitor-keys@2.1.0: {} - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@10.4.1: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5 - '@eslint/config-helpers': 0.6.0 - '@eslint/core': 1.2.1 - '@eslint/plugin-kit': 0.7.2 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@11.2.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 5.0.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - event-target-shim@5.0.1: {} - - events@3.3.0: {} - - fast-copy@3.0.2: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-redact@3.5.0: {} - - fast-safe-stringify@2.1.1: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - function-bind@1.1.2: {} - - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - - gopd@1.2.0: {} - - has-bigints@1.1.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - help-me@5.0.0: {} - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - imurmurhash@0.1.4: {} - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-extglob@2.1.1: {} - - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - joycon@3.1.1: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@1.0.2: - dependencies: - minimist: 1.2.8 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - math-intrinsics@1.1.0: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.6 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimist@1.2.8: {} - - ms@2.1.3: {} - - nanoid@4.0.2: {} - - natural-compare@1.4.0: {} - - node@runtime:24.16.0: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - - object.values@1.2.1: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - on-exit-leak-free@2.1.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - picomatch@4.0.4: {} - - pino-abstract-transport@1.2.0: - dependencies: - readable-stream: 4.7.0 - split2: 4.2.0 - - pino-pretty@10.3.1: - dependencies: - colorette: 2.0.20 - dateformat: 4.6.3 - fast-copy: 3.0.2 - fast-safe-stringify: 2.1.1 - help-me: 5.0.0 - joycon: 3.1.1 - minimist: 1.2.8 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.2.0 - pump: 3.0.2 - readable-stream: 4.7.0 - secure-json-parse: 2.7.0 - sonic-boom: 3.8.1 - strip-json-comments: 3.1.1 - - pino-std-serializers@6.2.2: {} - - pino@8.21.0: - dependencies: - atomic-sleep: 1.0.0 - fast-redact: 3.5.0 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.2.0 - pino-std-serializers: 6.2.2 - process-warning: 3.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.5.0 - sonic-boom: 3.8.1 - thread-stream: 2.7.0 - - possible-typed-array-names@1.1.0: {} - - prelude-ls@1.2.1: {} - - process-warning@3.0.0: {} - - process@0.11.10: {} - - prom-client@14.2.0: - dependencies: - tdigest: 0.1.2 - - pump@3.0.2: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - punycode@2.3.1: {} - - quick-format-unescaped@4.0.4: {} - - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - real-require@0.2.0: {} - - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - regexpp@3.2.0: {} - - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - safe-array-concat@1.1.3: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - - safe-buffer@5.2.1: {} - - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - safe-stable-stringify@2.5.0: {} - - secure-json-parse@2.7.0: {} - - semver@6.3.1: {} - - semver@7.7.2: {} - - semver@7.8.2: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - sinon@22.0.0: - dependencies: - '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 15.4.0 - '@sinonjs/samsam': 10.0.2 - diff: 9.0.0 - - sonic-boom@3.8.1: - dependencies: - atomic-sleep: 1.0.0 - - split2@4.2.0: {} - - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-bom@3.0.0: {} - - strip-json-comments@3.1.1: {} - - supports-preserve-symlinks-flag@1.0.0: {} - - tdigest@0.1.2: - dependencies: - bintrees: 1.0.2 - - thread-stream@2.7.0: - dependencies: - real-require: 0.2.0 - - tinyglobby@0.2.17: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - ts-api-utils@2.5.0(typescript@6.0.3): - dependencies: - typescript: 6.0.3 - - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-detect@4.0.8: {} - - type-detect@4.1.0: {} - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - - typescript-eslint@8.60.1(eslint@10.4.1)(typescript@6.0.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1)(typescript@6.0.3) - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1)(typescript@6.0.3) - eslint: 10.4.1 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - typescript@6.0.3: {} - - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - utap@0.2.0: - dependencies: - chalk: 5.4.1 - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - wrappy@1.0.2: {} - - yocto-queue@0.1.0: {} diff --git a/src/config.ts b/src/config.ts index ac12cdf..4a8ef43 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,3 @@ -import * as dotenv from "dotenv"; import { boolean, byteSize, @@ -74,7 +73,6 @@ export function readDefaultConfig() { } export function readLiveConfig() { - dotenv.config(); return readConfig(process.env); } @@ -86,6 +84,5 @@ export type SocketConfig = NorayConfig["socket"]; export type HttpConfig = NorayConfig["http"]; export type UdpRelayConfig = NorayConfig["udpRelay"]; -dotenv.config(); export const config = readLiveConfig(); logger.info({ config }, "Loaded application config"); diff --git a/src/connection/connection.commands.ts b/src/connection/connection.commands.ts index c7d4e83..0ac5b8d 100644 --- a/src/connection/connection.commands.ts +++ b/src/connection/connection.commands.ts @@ -1,14 +1,14 @@ import { HostRepository } from "../hosts/host.repository.ts"; -import { NodeSocketReactor } from "@foxssake/trimsock-node"; import { type RemoteInfo } from "node:dgram"; import assert from "node:assert"; import logger from "../logger.ts"; import { udpRelayHandler } from "../relay/relay.ts"; import { RelayEntry } from "../relay/relay.entry.ts"; import { NetAddress } from "../relay/net.address.ts"; +import { NorayReactor } from "../noray.ts"; export function handleConnect(hostRepository: HostRepository) { - return function(server: NodeSocketReactor) { + return function(server: NorayReactor) { server.on("connect", (command, exchange) => { const log = logger.child({ name: "cmd:connect" }); @@ -18,7 +18,7 @@ export function handleConnect(hostRepository: HostRepository) { const client = hostRepository.findBySocket(socket); log.debug( - { oid, client: socket.address() }, + { oid, address: socket.remoteAddress, port: socket.remotePort }, "Client attempting to connect to host", ); @@ -42,7 +42,7 @@ export function handleConnect(hostRepository: HostRepository) { } export function handleConnectRelay(hostRepository: HostRepository) { - return function(server: NodeSocketReactor) { + return function(server: NorayReactor) { server.on("connect-relay", (command, exchange) => { const log = logger.child({ name: "cmd:connect-relay" }); @@ -52,7 +52,11 @@ export function handleConnectRelay(hostRepository: HostRepository) { const client = hostRepository.findBySocket(socket); log.debug( - { oid, client: `${socket.remoteAddress}:${socket.remotePort}` }, + { + oid, + remoteAddress: socket.remoteAddress, + remotePort: socket.remotePort, + }, "Client attempting to connect to host", ); assert(host, "Unknown host oid: " + oid); diff --git a/src/hosts/host.commands.ts b/src/hosts/host.commands.ts index 95038a2..6a72bf6 100644 --- a/src/hosts/host.commands.ts +++ b/src/hosts/host.commands.ts @@ -1,9 +1,9 @@ import { HostRepository } from "./host.repository.ts"; -import { NodeSocketReactor } from "@foxssake/trimsock-node"; import { makeHost } from "./host.entity.ts"; import logger from "../logger.ts"; import * as prometheus from "prom-client"; import { metricsRegistry } from "../metrics/metrics.registry.ts"; +import { NorayReactor } from "../noray.ts"; const activeHostsGauge = new prometheus.Gauge({ name: "noray_active_hosts", @@ -12,7 +12,7 @@ const activeHostsGauge = new prometheus.Gauge({ }); export function handleRegisterHost(hostRepository: HostRepository) { - return function(server: NodeSocketReactor) { + return function(server: NorayReactor) { server.on("register-host", (__, exchange) => { const log = logger.child({ name: "cmd:register-host" }); activeHostsGauge.inc(); @@ -31,10 +31,7 @@ export function handleRegisterHost(hostRepository: HostRepository) { socket.remotePort, ); - socket.on("error", (err) => { - log.error(err); - }); - + // TODO: Create global message bus that modules can subscribe to socket.on("close", () => { log.info( { oid: host.oid, pid: host.pid }, diff --git a/src/hosts/host.entity.ts b/src/hosts/host.entity.ts index 1d13844..0b132d6 100644 --- a/src/hosts/host.entity.ts +++ b/src/hosts/host.entity.ts @@ -1,4 +1,3 @@ -import * as net from "node:net"; import * as dgram from "node:dgram"; import * as nanoid from "nanoid"; import { config } from "../config.ts"; @@ -31,7 +30,7 @@ export interface HostEntity { /** * Socket. */ - socket: net.Socket; + socket: Bun.Socket; /** * Relay port. @@ -44,7 +43,7 @@ export interface HostEntity { rinfo: dgram.RemoteInfo | undefined; } -export function makeHost(socket: net.Socket): HostEntity { +export function makeHost(socket: Bun.Socket): HostEntity { return { socket, oid: generateOID(), diff --git a/src/hosts/host.repository.ts b/src/hosts/host.repository.ts index 70d3f2c..8d2d524 100644 --- a/src/hosts/host.repository.ts +++ b/src/hosts/host.repository.ts @@ -1,4 +1,3 @@ -import * as net from "node:net"; import { Repository } from "../repository.ts"; import { type HostEntity } from "./host.entity.ts"; @@ -25,7 +24,7 @@ export class HostRepository extends Repository { * @param {net.Socket} socket Socket * @returns {HostEntity|undefined} Host */ - findBySocket(socket: net.Socket): HostEntity | undefined { + findBySocket(socket: Bun.Socket): HostEntity | undefined { // TODO: Cache by socket return [...this.list()].find((host) => host.socket === socket); } diff --git a/src/logger.ts b/src/logger.ts index de46d10..10c4f8e 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,5 +1,4 @@ import pino from "pino"; -import * as dotenv from "dotenv"; import { enumerated } from "./config.parsers.ts"; export const loglevels = Object.freeze([ @@ -12,8 +11,6 @@ export const loglevels = Object.freeze([ "fatal", ]); -dotenv.config(); - export function getLogLevel(): string { return enumerated(process.env.NORAY_LOGLEVEL, loglevels) ?? "info"; } diff --git a/src/metrics/metrics.ts b/src/metrics/metrics.ts index 3eaa671..abf46e2 100644 --- a/src/metrics/metrics.ts +++ b/src/metrics/metrics.ts @@ -1,43 +1,33 @@ -import * as http from "node:http"; import { Noray } from "../noray.ts"; import logger from "../logger.ts"; -import * as prometheus from "prom-client"; import { config } from "../config.ts"; import { metricsRegistry } from "./metrics.registry.ts"; const log = logger.child({ name: "mod:metrics" }); Noray.hook((noray: Noray) => { - log.info("Collecting default metrics"); - prometheus.collectDefaultMetrics({ - register: metricsRegistry, - }); + // Not supported in Bun (yet) + // log.info("Collecting default metrics"); + // prometheus.collectDefaultMetrics({ + // register: metricsRegistry, + // }); log.info("Starting HTTP server to serve metrics"); - const httpServer = new http.Server(); - httpServer.on("request", async (req, res) => { - if (req.url !== "/metrics") { - res.statusCode = 404; - res.end(); - return; - } + const server = Bun.serve({ + routes: { + "/metrics": async () => new Response(await metricsRegistry.metrics()), + }, - res.write(await metricsRegistry.metrics()); - res.end(); + fetch: () => new Response("Not found", { status: 404 }), + hostname: config.http.host, + port: config.http.port, }); - httpServer.listen(config.http.port, config.http.host, () => - log.info( - "Serving metrics over HTTP on port %s:%d", - config.http.host, - config.http.port, - ), - ); + log.info("Serving metrics over HTTP at %s", server.url); noray.on("close", () => { log.info("noray closing, shutting down HTTP server"); - httpServer.close(); - httpServer.closeAllConnections(); + server.stop(); }); }); diff --git a/src/noray.ts b/src/noray.ts index d3fd0c2..0754261 100644 --- a/src/noray.ts +++ b/src/noray.ts @@ -1,9 +1,7 @@ -import * as net from "node:net"; import { EventEmitter } from "node:events"; import logger from "./logger.ts"; import { config } from "./config.ts"; -import { NodeSocketReactor } from "@foxssake/trimsock-node"; -import { promiseEvent } from "./utils.ts"; +import { BunSocketReactor } from "@foxssake/trimsock-bun"; export type NorayHook = (noray: Noray) => void; @@ -14,9 +12,11 @@ const defaultModules = [ "connection/connection.ts", ]; +export type NorayReactor = BunSocketReactor; + export class Noray extends EventEmitter { - private server!: net.Server; - private _reactor!: NodeSocketReactor; + private server!: Bun.TCPSocketListener; + private _reactor!: NorayReactor; private log = logger; private static hooks: NorayHook[] = []; @@ -33,7 +33,7 @@ export class Noray extends EventEmitter { this.log.info("Starting Noray"); - this._reactor = new NodeSocketReactor().onError( + this._reactor = new BunSocketReactor().onError( (command, exchange, error) => { exchange.failOrSend({ name: command.name, text: "" + error }); }, @@ -55,31 +55,24 @@ export class Noray extends EventEmitter { // Start server this.log.info("Starting TCP server"); - this.server = this.reactor.serve(); - this.server.listen(config.socket.port, config.socket.host); - this.server.on("listening", () => { - this.log.info( - "Listening on %s:%s", - config.socket.host, - config.socket.port, - ); - - this.server.on("error", (err) => { - this.log.error("Listen socket encountered an error!"); - this.log.error(err); - }); - - this.server.on("connection", (conn) => { - conn.on("error", (err) => { - this.log.error("Connection socket encountered an error!"); - this.log.error(err); - }); - }); - - this.emit("listening", config.socket.port, config.socket.host); + this.server = this._reactor.listen({ + hostname: config.socket.host, + port: config.socket.port, + socket: { + error: (socket, error) => { + this.log.error( + { + error, + remoteAddress: socket.remoteAddress, + remotePort: socket.remotePort, + }, + "Connection socket encountered an error!", + ); + }, + }, }); - await promiseEvent(this, "listening"); + this.emit("listening", config.socket.port, config.socket.host); this.log.info("Started noray in %f ms", process.uptime() * 1000.0); } @@ -87,7 +80,7 @@ export class Noray extends EventEmitter { this.log.info("Shutting down"); this.emit("close"); - this.server.close(); + this.server.stop(true); } get reactor() { From 47efdbfb7e84a7e1f7df248d365d540a03196a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 17:36:49 +0200 Subject: [PATCH 02/14] remove node:dgram --- src/connection/connection.commands.ts | 42 ++++++++++++++------ src/events.ts | 56 ++++++++++++++++++++++++++ src/hosts/host.commands.ts | 7 +++- src/hosts/host.entity.ts | 17 ++++++-- src/relay/net.address.ts | 10 +---- src/relay/relay.entry.ts | 5 +++ src/relay/relay.ts | 24 ++++++++++- src/relay/udp.relay.handler.ts | 7 +--- src/relay/udp.remote.registrar.ts | 57 ++++++++++++++++++--------- src/relay/udp.socket.pool.ts | 27 ++++++------- 10 files changed, 187 insertions(+), 65 deletions(-) create mode 100644 src/events.ts diff --git a/src/connection/connection.commands.ts b/src/connection/connection.commands.ts index 0ac5b8d..3845113 100644 --- a/src/connection/connection.commands.ts +++ b/src/connection/connection.commands.ts @@ -1,11 +1,11 @@ import { HostRepository } from "../hosts/host.repository.ts"; -import { type RemoteInfo } from "node:dgram"; import assert from "node:assert"; import logger from "../logger.ts"; import { udpRelayHandler } from "../relay/relay.ts"; import { RelayEntry } from "../relay/relay.entry.ts"; import { NetAddress } from "../relay/net.address.ts"; import { NorayReactor } from "../noray.ts"; +import { HostEntity } from "../hosts/host.entity.ts"; export function handleConnect(hostRepository: HostRepository) { return function(server: NorayReactor) { @@ -23,12 +23,14 @@ export function handleConnect(hostRepository: HostRepository) { ); assert(host, "Unknown host oid: " + oid); - assert(host.rinfo, "Host has no remote info registered!"); + assert(host.remoteAddress, "Host has no remote address registered!"); + assert(host.remotePort, "Host has no remote port registered!"); assert(client, "Unknown client from address"); - assert(client.rinfo, "Client has no remote info registered!"); + assert(client.remoteAddress, "Client has no remote address registered!"); + assert(client.remotePort, "Client has no remote port registered!"); - const hostAddress = stringifyAddress(host.rinfo); - const clientAddress = stringifyAddress(client.rinfo); + const hostAddress = stringifyAddressOf(host); + const clientAddress = stringifyAddressOf(client); server.send(socket, { name: "connect", params: [hostAddress] }); server.send(host.socket, { name: "connect", params: [clientAddress] }); @@ -63,8 +65,8 @@ export function handleConnectRelay(hostRepository: HostRepository) { assert(client, "Unknown client from address"); log.debug("Ensuring relay for both parties"); - host.relay = getRelay(host.rinfo!); - client.relay = getRelay(client.rinfo!); + host.relay = getRelayFor(host); + client.relay = getRelayFor(client); log.debug( { host: host.relay, client: client.relay }, @@ -90,18 +92,34 @@ export function handleConnectRelay(hostRepository: HostRepository) { }; } -function stringifyAddress(address: RemoteInfo) { - return `${address.address}:${address.port}`; +function stringifyAddressOf(host: HostEntity) { + return `${host.remoteAddress}:${host.remotePort}`; } -function getRelay(rinfo: RemoteInfo) { +function getRelayFor(host: HostEntity) { // Attempt to create new relay on each connect // If there's a relay already, UDPRelayHandler will return that // If there's no relay, or it has expired, a new one will be created const log = logger.child({ name: "getRelay" }); - log.trace({ rinfo }, "Ensuring relay for remote"); + log.trace( + { + host: { + oid: host.oid, + address: host.remoteAddress, + port: host.remotePort, + }, + }, + "Ensuring relay for host", + ); + const relayEntry = udpRelayHandler.createRelay( - new RelayEntry({ address: NetAddress.fromRinfo(rinfo), port: rinfo.port }), + new RelayEntry({ + address: new NetAddress({ + address: host.remoteAddress!, + port: host.remotePort!, + }), + port: -1, // Set by the handler + }), ); log.trace( diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..21ba9ef --- /dev/null +++ b/src/events.ts @@ -0,0 +1,56 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type EventHandler = (...args: any[]) => void; +type EventMap = Record; + +export class EventBus { + private subscribers = new Map(); + + on(event: string, handler: EventHandler): void { + const handlers = this.getHandlersFor(event); + handlers.push(handler); + } + + off(event: string, handler: EventHandler): void { + const handlers = this.getHandlersFor(event); + const idx = handlers.indexOf(handler); + + if (idx < 0) return; + + handlers.splice(idx, 1); + } + + emit(event: string, ...args: unknown[]): void { + for (const handler of this.getHandlersFor(event)) handler(...args); + } + + private getHandlersFor(event: string): EventHandler[] { + if (!this.subscribers.has(event)) this.subscribers.set(event, []); + return this.subscribers.get(event) ?? []; + } +} + +// Type magic based on: https://github.com/andywer/typed-emitter +// Thanks, @andywer! +export class TypedEventBus extends EventBus { + on(event: E, handler: T[E]): void; + on(event: string, handler: EventHandler) { + super.on(event, handler); + } + + off(event: E, handler: T[E]): void; + off(event: string, handler: EventHandler) { + super.off(event, handler); + } + + emit(event: E, ...args: Parameters): void; + emit(event: string, ...args: unknown[]): void { + super.emit(event, ...args); + } +} + +// Application specific events +export class NorayEventBus extends TypedEventBus<{ + "connection-close": (socket: Bun.Socket) => void; +}> { } + +export const NorayEvents = new NorayEventBus(); diff --git a/src/hosts/host.commands.ts b/src/hosts/host.commands.ts index 6a72bf6..ab112a8 100644 --- a/src/hosts/host.commands.ts +++ b/src/hosts/host.commands.ts @@ -4,6 +4,7 @@ import logger from "../logger.ts"; import * as prometheus from "prom-client"; import { metricsRegistry } from "../metrics/metrics.registry.ts"; import { NorayReactor } from "../noray.ts"; +import { NorayEvents } from "../events.ts"; const activeHostsGauge = new prometheus.Gauge({ name: "noray_active_hosts", @@ -31,8 +32,10 @@ export function handleRegisterHost(hostRepository: HostRepository) { socket.remotePort, ); - // TODO: Create global message bus that modules can subscribe to - socket.on("close", () => { + // TODO: Manage this via repo in `host.ts` or smth + NorayEvents.on("connection-close", (closed) => { + if (closed !== socket) return; + log.info( { oid: host.oid, pid: host.pid }, "Host disconnected, removing from repository", diff --git a/src/hosts/host.entity.ts b/src/hosts/host.entity.ts index 0b132d6..d170de0 100644 --- a/src/hosts/host.entity.ts +++ b/src/hosts/host.entity.ts @@ -1,4 +1,3 @@ -import * as dgram from "node:dgram"; import * as nanoid from "nanoid"; import { config } from "../config.ts"; import { generateWordId } from "../utils.ts"; @@ -38,9 +37,18 @@ export interface HostEntity { relay: number | undefined; /** - * Host remote info. + * Host's address open for UDP. + * + * This is the public address where the host receives UDP traffic. */ - rinfo: dgram.RemoteInfo | undefined; + remoteAddress: string | undefined; + + /** + * Host's port open for UDP. + * + * This is the public port where the host receives UDP traffic. + */ + remotePort: number | undefined; } export function makeHost(socket: Bun.Socket): HostEntity { @@ -50,6 +58,7 @@ export function makeHost(socket: Bun.Socket): HostEntity { pid: generatePID(), relay: undefined, - rinfo: undefined, + remoteAddress: undefined, + remotePort: undefined, }; } diff --git a/src/relay/net.address.ts b/src/relay/net.address.ts index e0db429..d0a26cd 100644 --- a/src/relay/net.address.ts +++ b/src/relay/net.address.ts @@ -1,5 +1,4 @@ -import dgram from "node:dgram"; -import net from "node:net"; +// TODO: Stick to interface, methods are probably only needed for data lookups export interface NetAddressData { address: string; @@ -22,11 +21,4 @@ export class NetAddress implements NetAddressData { toString() { return `${this.address}:${this.port}`; } - - static fromRinfo(rinfo: dgram.RemoteInfo | net.AddressInfo): NetAddress { - return new NetAddress({ - address: rinfo.address, - port: rinfo.port, - }); - } } diff --git a/src/relay/relay.entry.ts b/src/relay/relay.entry.ts index 11547cf..a1c8333 100644 --- a/src/relay/relay.entry.ts +++ b/src/relay/relay.entry.ts @@ -1,6 +1,11 @@ import { NetAddress } from "./net.address.ts"; import { time } from "../utils.ts"; +// TODO: Keep interface only +// TODO: Update fields: `incomingPort`, `outgoingAddress`, `outgoingPort` +// i.e. anything that arrives at `incomingPort` must be forwarded to +// `outgoingAddress:outgoingPort` + export interface RelayEntryData { /** * The port on which we've received traffic diff --git a/src/relay/relay.ts b/src/relay/relay.ts index 1569e19..69a745f 100644 --- a/src/relay/relay.ts +++ b/src/relay/relay.ts @@ -14,6 +14,7 @@ import { UDPRemoteRegistrar } from "./udp.remote.registrar.ts"; import { hostRepository } from "../hosts/host.ts"; import { useDynamicRelay } from "./dynamic.relaying.ts"; import { UDPSocketPool } from "./udp.socket.pool.ts"; +import { NetAddress } from "./net.address.ts"; export const udpSocketPool = new UDPSocketPool(); @@ -53,7 +54,7 @@ Noray.hook(async (noray) => { for (const port of config.udpRelay.ports!) { log.trace("Binding port %d for relay", port); try { - await udpSocketPool.allocatePort(port); + bindPortForRelaying(udpSocketPool, udpRelayHandler, port); } catch (err) { log.warn({ err }, "Failed to bind port %d, ignoring", port); } @@ -109,3 +110,24 @@ Noray.hook(async (noray) => { udpRelayHandler.clear(); }); }); + +async function bindPortForRelaying( + udpSocketPool: UDPSocketPool, + udpRelayHandler: UDPRelayHandler, + port: number, +): Promise { + await udpSocketPool.allocatePort(port, { + socket: { + data(socket, data, port, address) { + udpRelayHandler.relay( + data, + new NetAddress({ address, port }), + socket.port, + ); + }, + error(_socket, error) { + log.error(error, "UDP relay socket encountered an error!"); + }, + }, + }); +} diff --git a/src/relay/udp.relay.handler.ts b/src/relay/udp.relay.handler.ts index 1159579..b09ebdf 100644 --- a/src/relay/udp.relay.handler.ts +++ b/src/relay/udp.relay.handler.ts @@ -67,6 +67,7 @@ export class UDPRelayHandler extends EventEmitter { public get relayTable(): RelayEntry[] { // HACK: Let's hope nobody modifies this; kinda don't want to copy it on // every return + // TODO: Maybe return an interator? return this._relayTable; } @@ -84,6 +85,7 @@ export class UDPRelayHandler extends EventEmitter { * * @fires UDPRelayHandler#create */ + // TODO: Passing in a full relay object is confusing, accept only the relevant settings createRelay(relay: RelayEntry): RelayEntry { log.debug({ relay }, "Creating relay"); if (this.hasRelay(relay)) { @@ -95,11 +97,6 @@ export class UDPRelayHandler extends EventEmitter { relay.port = this.socketPool.getPort(); this.emit("create", relay); - const socket = this.socketPool.getSocket(relay.port)!; - socket.removeAllListeners("message").on("message", (msg, rinfo) => { - this.relay(msg, NetAddress.fromRinfo(rinfo), relay.port); - }); - relay.lastReceived = time(); relay.created = time(); this._relayTable.push(relay); diff --git a/src/relay/udp.remote.registrar.ts b/src/relay/udp.remote.registrar.ts index db33ac9..1f11cb0 100644 --- a/src/relay/udp.remote.registrar.ts +++ b/src/relay/udp.remote.registrar.ts @@ -1,9 +1,9 @@ import { HostRepository } from "../hosts/host.repository.ts"; -import dgram from "node:dgram"; import assert from "node:assert"; import logger from "../logger.ts"; import * as prometheus from "prom-client"; import { metricsRegistry } from "../metrics/metrics.registry.ts"; +import { UDPSocket } from "./udp.socket.pool.ts"; const log = logger.child({ name: "UDPRemoteRegistrar" }); @@ -27,7 +27,7 @@ const registerRepatCounter = new prometheus.Counter({ export interface UDPRemoteRegistrarOptions { hostRepository: HostRepository; - socket?: dgram.Socket; + socket?: UDPSocket; } /** @@ -45,51 +45,72 @@ export class UDPRemoteRegistrar { /** * Socket listening for requests. */ - public readonly socket: dgram.Socket; + public readonly socket: UDPSocket | undefined; private hostRepository: HostRepository; constructor(options: UDPRemoteRegistrarOptions) { this.hostRepository = options.hostRepository; - this.socket = options.socket ?? dgram.createSocket("udp4"); + this.socket = options.socket; } /** * Start listening for incoming requests. */ - listen(port = 0, address = "0.0.0.0"): Promise { - return new Promise((resolve) => { - this.socket.on("message", (msg, rinfo) => this.handle(msg, rinfo)); - this.socket.bind(port, address, () => { - const address = this.socket.address(); - log.info("Listening on %s:%s", address.address, address.port); - resolve(); - }); + async listen(port = 0, address = "0.0.0.0"): Promise { + const server = await Bun.udpSocket({ + port, + hostname: address, + socket: { + data: (_socket, data, port, address) => { + this.handle(data, address, port); + }, + }, }); + + log.info("Listening on %s:%s", server.address.address, server.address.port); } - private async handle(msg: Buffer, rinfo: dgram.RemoteInfo) { + private async handle( + msg: Buffer, + incomingAddress: string, + incomingPort: number, + ) { + if (this.socket === undefined) { + // Should not happen, `handle()` is only called by the listening socket + log.error("Trying to handle incoming request without active socket!"); + return; + } + try { const pid = msg.toString("utf8"); - log.debug({ pid, rinfo }, "Received UDP relay request"); + log.debug( + { pid, incomingAddress, incomingPort }, + "Received UDP relay request", + ); const host = this.hostRepository.findByPid(pid); assert(host, "Unknown host pid!"); if (host.rinfo) { // Host has already remote info registered - this.socket.send("OK", rinfo.port, rinfo.address); + this.socket.send("OK", incomingPort, incomingAddress); registerRepatCounter.inc(); return; } - host.rinfo = rinfo; - this.socket.send("OK", rinfo.port, rinfo.address); + host.rinfo = { + address: incomingAddress, + port: incomingPort, + family: "IPv4", + size: 16, + }; + this.socket.send("OK", incomingPort, incomingAddress); registerSuccessCounter.inc(); } catch (e) { registerFailCounter.inc(); const message = e instanceof Error ? e.message : "Error"; - this.socket.send(message, rinfo.port, rinfo.address); + this.socket.send(message, incomingPort, incomingAddress); } } } diff --git a/src/relay/udp.socket.pool.ts b/src/relay/udp.socket.pool.ts index 7c7d6c3..dacfceb 100644 --- a/src/relay/udp.socket.pool.ts +++ b/src/relay/udp.socket.pool.ts @@ -1,5 +1,7 @@ import assert from "node:assert"; -import dgram from "node:dgram"; + +export type UDPSocket = Bun.udp.Socket<"buffer">; +export type UDPSocketOptions = Bun.udp.SocketOptions<"buffer">; /** * Class to manage and allocate UDP ports as needed. @@ -16,7 +18,7 @@ export class UDPSocketPool { * Port to socket * @type {Map} */ - private sockets = new Map(); + private sockets = new Map(); /** * Free ports @@ -32,15 +34,12 @@ export class UDPSocketPool { * @returns Allocated port * @throws if allocation fails */ - allocatePort(port = 0): Promise { - return new Promise((resolve, reject) => { - const socket = dgram.createSocket("udp4"); - socket.once("error", reject); - socket.bind(port ?? 0, () => { - port = this.addSocket(socket); - resolve(port); - }); - }); + async allocatePort( + port?: number, + options: UDPSocketOptions = {}, + ): Promise { + const socket = await Bun.udpSocket({ ...options, port }); + return this.addSocket(socket); } /** @@ -59,7 +58,7 @@ export class UDPSocketPool { * Get socket listening on port. * @param port Port */ - getSocket(port: number): dgram.Socket | undefined { + getSocket(port: number): UDPSocket | undefined { return this.sockets.get(port); } @@ -68,8 +67,8 @@ export class UDPSocketPool { * @param socket Socket * @returns Relay port */ - addSocket(socket: dgram.Socket): number { - const port = socket.address().port; + addSocket(socket: UDPSocket): number { + const port = socket.port; this.sockets.set(port, socket); this.freePorts.push(port); From 96fb1236fce49288992c2e294b1d01320d3be34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 17:51:29 +0200 Subject: [PATCH 03/14] better shutdown? --- bin/noray.ts | 18 ++++++++++++++++-- src/noray.ts | 2 ++ src/relay/relay.ts | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/bin/noray.ts b/bin/noray.ts index 53161d8..0930907 100644 --- a/bin/noray.ts +++ b/bin/noray.ts @@ -1,7 +1,21 @@ import { Noray } from "../src/noray.ts"; +let isShuttingDown = false; const noray = new Noray(); noray.start(); -process.on("exit", () => noray.shutdown()); -process.on("SIGINT", () => noray.shutdown()); +function shutdown() { + if (isShuttingDown) return; + + isShuttingDown = true; + noray.shutdown(); + + // HACK: noray keeps running after shutdown, maybe a shutdown hook runs + // something async that doesn't finish? + // TODO: Refactor similarly to nohub, expose a shutdown listener that can be + // async, and await each individually with a timeout + process.exit(1); +} + +process.on("exit", shutdown); +process.on("SIGINT", shutdown); diff --git a/src/noray.ts b/src/noray.ts index 0754261..741919c 100644 --- a/src/noray.ts +++ b/src/noray.ts @@ -81,6 +81,8 @@ export class Noray extends EventEmitter { this.emit("close"); this.server.stop(true); + + this.log.info("Shutdown complete"); } get reactor() { diff --git a/src/relay/relay.ts b/src/relay/relay.ts index 69a745f..ea667fa 100644 --- a/src/relay/relay.ts +++ b/src/relay/relay.ts @@ -98,7 +98,7 @@ Noray.hook(async (noray) => { try { // HACK: Removing the try-catch guard results in a "not running" exception? // On node v24.16.0 - udpRemoteRegistrar.socket.close(); + udpRemoteRegistrar.socket?.close(); } catch (e) { log.warn(e, "Failed to close UDP Remote Registrar socket"); } From 5d0e308dbdc4627b9559e8b9fa35192eef63303a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 18:08:06 +0200 Subject: [PATCH 04/14] remove node:assert --- scripts/taplog.ts | 2 +- src/assert.ts | 12 ++++++++++++ src/config.parsers.ts | 2 +- src/connection/connection.commands.ts | 2 +- src/relay/constraints.ts | 2 +- src/relay/udp.remote.registrar.ts | 12 ++++-------- src/relay/udp.socket.pool.ts | 2 +- src/repository.ts | 2 +- 8 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 src/assert.ts diff --git a/scripts/taplog.ts b/scripts/taplog.ts index 2a2f0fc..35e44e1 100644 --- a/scripts/taplog.ts +++ b/scripts/taplog.ts @@ -1,6 +1,6 @@ import * as rl from "node:readline/promises"; import * as chp from "node:child_process"; -import { fail } from "node:assert"; +import { fail } from "../src/assert"; function sleep(t: number): Promise { return new Promise((resolve) => setTimeout(resolve, t)); diff --git a/src/assert.ts b/src/assert.ts new file mode 100644 index 0000000..0f55c2e --- /dev/null +++ b/src/assert.ts @@ -0,0 +1,12 @@ +export class AssertionError extends Error { } + +export function assert( + what: unknown | undefined, + message = "Assertion failed!", +): asserts what { + if (what === undefined) throw new AssertionError(message); +} + +export function fail(message = "Assertion failed!"): never { + throw new AssertionError(message); +} diff --git a/src/config.parsers.ts b/src/config.parsers.ts index b1371fe..83d998b 100644 --- a/src/config.parsers.ts +++ b/src/config.parsers.ts @@ -1,4 +1,4 @@ -import assert from "node:assert"; +import { assert } from "./assert"; /** * Parse config value as boolean. diff --git a/src/connection/connection.commands.ts b/src/connection/connection.commands.ts index 3845113..4547c1c 100644 --- a/src/connection/connection.commands.ts +++ b/src/connection/connection.commands.ts @@ -1,11 +1,11 @@ import { HostRepository } from "../hosts/host.repository.ts"; -import assert from "node:assert"; import logger from "../logger.ts"; import { udpRelayHandler } from "../relay/relay.ts"; import { RelayEntry } from "../relay/relay.entry.ts"; import { NetAddress } from "../relay/net.address.ts"; import { NorayReactor } from "../noray.ts"; import { HostEntity } from "../hosts/host.entity.ts"; +import { assert } from "../assert.ts"; export function handleConnect(hostRepository: HostRepository) { return function(server: NorayReactor) { diff --git a/src/relay/constraints.ts b/src/relay/constraints.ts index 62203d3..b1012a8 100644 --- a/src/relay/constraints.ts +++ b/src/relay/constraints.ts @@ -1,7 +1,7 @@ import { BandwidthLimiter } from "./bandwidth.limiter.ts"; import { UDPRelayHandler } from "./udp.relay.handler.ts"; -import assert from "node:assert"; import { time } from "../utils.ts"; +import { assert } from "../assert.ts"; /** * Limit the bandwidth on every relay individually. diff --git a/src/relay/udp.remote.registrar.ts b/src/relay/udp.remote.registrar.ts index 1f11cb0..fdb360e 100644 --- a/src/relay/udp.remote.registrar.ts +++ b/src/relay/udp.remote.registrar.ts @@ -1,9 +1,9 @@ import { HostRepository } from "../hosts/host.repository.ts"; -import assert from "node:assert"; import logger from "../logger.ts"; import * as prometheus from "prom-client"; import { metricsRegistry } from "../metrics/metrics.registry.ts"; import { UDPSocket } from "./udp.socket.pool.ts"; +import { assert } from "../assert.ts"; const log = logger.child({ name: "UDPRemoteRegistrar" }); @@ -92,19 +92,15 @@ export class UDPRemoteRegistrar { const host = this.hostRepository.findByPid(pid); assert(host, "Unknown host pid!"); - if (host.rinfo) { + if (host.remoteAddress) { // Host has already remote info registered this.socket.send("OK", incomingPort, incomingAddress); registerRepatCounter.inc(); return; } - host.rinfo = { - address: incomingAddress, - port: incomingPort, - family: "IPv4", - size: 16, - }; + host.remoteAddress = incomingAddress; + host.remotePort = incomingPort; this.socket.send("OK", incomingPort, incomingAddress); registerSuccessCounter.inc(); } catch (e) { diff --git a/src/relay/udp.socket.pool.ts b/src/relay/udp.socket.pool.ts index dacfceb..7a05efe 100644 --- a/src/relay/udp.socket.pool.ts +++ b/src/relay/udp.socket.pool.ts @@ -1,4 +1,4 @@ -import assert from "node:assert"; +import { assert } from "../assert"; export type UDPSocket = Bun.udp.Socket<"buffer">; export type UDPSocketOptions = Bun.udp.SocketOptions<"buffer">; diff --git a/src/repository.ts b/src/repository.ts index 6edf449..ef670e7 100644 --- a/src/repository.ts +++ b/src/repository.ts @@ -1,4 +1,4 @@ -import assert from "node:assert"; +import { assert } from "./assert"; export type IdMapper = (item: Partial) => K | undefined; export type ItemMerger = (a: T, b: Partial) => T; From 87287f43a00875b73dd0419ba895e72d1623eca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 19:43:18 +0200 Subject: [PATCH 05/14] config parsers and utils tests --- src/assert.ts | 2 +- test/spec/assertions.test.ts | 35 ----- test/spec/config.parsers.test.ts | 250 ++++++++++++++----------------- test/spec/utils.test.ts | 74 +++++---- 4 files changed, 146 insertions(+), 215 deletions(-) delete mode 100644 test/spec/assertions.test.ts diff --git a/src/assert.ts b/src/assert.ts index 0f55c2e..596f66c 100644 --- a/src/assert.ts +++ b/src/assert.ts @@ -4,7 +4,7 @@ export function assert( what: unknown | undefined, message = "Assertion failed!", ): asserts what { - if (what === undefined) throw new AssertionError(message); + if (!what) throw new AssertionError(message); } export function fail(message = "Assertion failed!"): never { diff --git a/test/spec/assertions.test.ts b/test/spec/assertions.test.ts deleted file mode 100644 index fc842da..0000000 --- a/test/spec/assertions.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; -import { requireEnum } from "../../src/assertions.ts"; - -describe("assertions", () => { - describe("requireEnum", () => { - const TestEnum = Object.freeze({ - Foo: "foo", - Bar: "bar", - }); - - it("should return param", () => { - // Given - const expected = TestEnum.Bar; - - // When - const actual = requireEnum(expected, TestEnum); - - // Then - assert.equal(actual, expected); - }); - - it("should throw on invalid", () => { - // Given - const invalid = "@@$invalid$@@"; - - // When + Then - assert.throws( - () => requireEnum(invalid, TestEnum), - (err: Error) => - assert.equal(err.message, "Invalid enum value: " + invalid) ?? true, - ); - }); - }); -}); diff --git a/test/spec/config.parsers.test.ts b/test/spec/config.parsers.test.ts index 2e05ae8..811f5d1 100644 --- a/test/spec/config.parsers.test.ts +++ b/test/spec/config.parsers.test.ts @@ -1,5 +1,4 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; +import { expect, describe, test } from "bun:test"; import { boolean, byteSize, @@ -10,164 +9,137 @@ import { ports, } from "../../src/config.parsers.ts"; -interface CaseDef { - name: string; - input: string | [string | undefined, string[]] | undefined; - expected: any | undefined; -} - -function Case( - name: string, - input: CaseDef["input"], - expected?: any | undefined, -): CaseDef { - return { name, input, expected }; -} - -const cases = { - boolean: { - method: (value) => boolean(value), - cases: [ - Case("should parse true", "true", true), - Case("should parse false", "false", false), - Case("should parse any word", "foo", false), - Case("should return undefined on undefined", undefined, undefined), - ], - }, - - integer: { - method: (value) => integer(value), - cases: [ - Case("should parse valid", "42", 42), - Case("should return undefined on invalid", "asd", undefined), - Case("should return undefined on empty", "", undefined), - Case("should return undefined on undefined", undefined, undefined), - ], - }, - - number: { - method: (value) => number(value), - cases: [ - Case("should parse valid integer", "42", 42), - Case("should parse valid number", "420.69", 420.69), - Case("should return undefined on invalid", "asd", undefined), - Case("should return undefined on empty", "", undefined), - Case("should return undefined on undefined", undefined, undefined), - ], - }, - - enumerated: { - method: ([value, known]) => enumerated(value, known), - cases: [ - Case("should return known", ["a", ["a", "b", "c"]], "a"), - Case("should return undefined on unknown", ["f", ["a", "b"]], undefined), - Case("should return undefined on empty", ["", ["a", "b"]], undefined), - Case( - "should return undefined on undefined", - [undefined, ["a"]], - undefined, - ), - ], - }, -} as Record void; cases: CaseDef[] }>; - -Object.entries(cases).forEach(([name, entry]) => { - describe(name, () => { - entry.cases.forEach((kase) => { - it(kase.name, () => { - // Given - const expected = kase.expected; - - // When - const actual = entry.method(kase.input); - - // Then - assert.deepEqual(actual, expected); - }); - }); - }); +describe("boolean", () => { + const cases = [ + ["should parse true", "true", true], + ["should parse false", "false", false], + ["should parse any word", "foo", false], + ["should return undefined on undefined", undefined, undefined], + ] as [string, string | undefined, boolean | undefined][]; + + cases.forEach(([name, input, expected]) => + test(name, () => { + expect(boolean(input)).toBe(expected); + }), + ); +}); + +describe("integer", () => { + const cases = [ + ["should parse valid", "42", 42], + ["should return undefined on invalid", "asd", undefined], + ["should return undefined on empty", "", undefined], + ["should return undefined on undefined", undefined, undefined], + ] as [string, string | undefined, number | undefined][]; + + cases.forEach(([name, input, expected]) => + test(name, () => { + expect(integer(input)).toBe(expected); + }), + ); +}); + +describe("number", () => { + const cases = [ + ["should parse valid integer", "42", 42], + ["should parse valid number", "420.69", 420.69], + ["should return undefined on invalid", "asd", undefined], + ["should return undefined on empty", "", undefined], + ["should return undefined on undefined", undefined, undefined], + ] as [string, string | undefined, number | undefined][]; + + cases.forEach(([name, input, expected]) => + test(name, () => { + expect(number(input)).toBe(expected); + }), + ); +}); + +describe("enumerated", () => { + const cases = [ + ["should return known", ["a", ["a", "b", "c"]], "a"], + ["should return undefined on unknown", ["f", ["a", "b"]], undefined], + ["should return undefined on empty", ["", ["a", "b"]], undefined], + ["should return undefined on undefined", [undefined, ["a"]], undefined], + ] as [string, [string | undefined, string[]], string | undefined][]; + + cases.forEach(([name, [input, known], expected]) => + test(name, () => { + expect(enumerated(input, known)).toBe(expected); + }), + ); }); describe("byteSize", () => { const validCases = [ - Case("should pass through undefined", undefined, undefined), - Case("should parse without postfix", "64", 64), - Case("should parse kb", "64kb", 64 * 1024), - Case("should parse Mb", "64Mb", 64 * Math.pow(1024, 2)), - Case("should parse Gb", "64Gb", 64 * Math.pow(1024, 3)), - Case("should parse Gb", "64Tb", 64 * Math.pow(1024, 4)), - Case("should parse Pb", "6.4Pb", 6.4 * Math.pow(1024, 5)), - Case("should parse Eb", "6.4Eb", 6.4 * Math.pow(1024, 6)), - Case("should parse Zb", "64Zb", 64 * Math.pow(1024, 7)), - Case("should parse Yb", "64Yb", 64 * Math.pow(1024, 8)), - ]; + ["should pass through undefined", undefined, undefined], + ["should parse without postfix", "64", 64], + ["should parse kb", "64kb", 64 * 1024], + ["should parse Mb", "64Mb", 64 * Math.pow(1024, 2)], + ["should parse Gb", "64Gb", 64 * Math.pow(1024, 3)], + ["should parse Gb", "64Tb", 64 * Math.pow(1024, 4)], + ["should parse Pb", "6.4Pb", 6.4 * Math.pow(1024, 5)], + ["should parse Eb", "6.4Eb", 6.4 * Math.pow(1024, 6)], + ["should parse Zb", "64Zb", 64 * Math.pow(1024, 7)], + ["should parse Yb", "64Yb", 64 * Math.pow(1024, 8)], + ] as [string, string | undefined, number][]; const throwCases = [ - Case("should throw on invalid format", "no6"), - Case("should throw on invalid postfix", "64Bb"), - ]; - - validCases.forEach((kase) => - it(kase.name, () => - assert.equal(byteSize(kase.input as string | undefined), kase.expected), - ), + ["should throw on invalid format", "no6"], + ["should throw on invalid postfix", "64Bb"], + ] as [string, string][]; + + validCases.forEach(([name, input, expected]) => + test(name, () => expect(byteSize(input)).toBe(expected)), ); - throwCases.forEach((kase) => - it(kase.name, () => - assert.throws(() => byteSize(kase.input as string | undefined)), - ), + throwCases.forEach(([name, input]) => + test(name, () => expect(() => byteSize(input)).toThrow()), ); }); describe("duration", () => { const validCases = [ - Case("should pass through undefined", undefined, undefined), - Case("should parse without postfix", "64", 64), - Case("should parse usec", "64us", 0.000064), - Case("should parse msec", "64ms", 0.064), - Case("should parse sec", "64s", 64), - Case("should parse minute", "10m", 600), - Case("should parse hour", "4h", 14400), - Case("should parse hour", "4hr", 14400), - Case("should parse day", "2d", 172800), - Case("should parse week", "2w", 1209600), - Case("should parse month", "3mo", 7776000), - Case("should parse year", "4yr", 126144000), - ]; + ["should pass through undefined", undefined, undefined], + ["should parse without postfix", "64", 64], + ["should parse usec", "64us", 0.000064], + ["should parse msec", "64ms", 0.064], + ["should parse sec", "64s", 64], + ["should parse minute", "10m", 600], + ["should parse hour", "4h", 14400], + ["should parse hour", "4hr", 14400], + ["should parse day", "2d", 172800], + ["should parse week", "2w", 1209600], + ["should parse month", "3mo", 7776000], + ["should parse year", "4yr", 126144000], + ] as [string, string | undefined, number | undefined][]; const throwCases = [ - Case("should throw on invalid format", "no6"), - Case("should throw on invalid postfix", "64mh"), - ]; - - validCases.forEach((kase) => - it(kase.name, () => - assert.equal(duration(kase.input as string | undefined), kase.expected), - ), + ["should throw on invalid format", "no6"], + ["should throw on invalid postfix", "64mh"], + ] as [string, string][]; + + validCases.forEach(([name, input, expected]) => + test(name, () => expect(duration(input)).toBe(expected)), ); - throwCases.forEach((kase) => - it(kase.name, () => - assert.throws(() => duration(kase.input as string | undefined)), - ), + throwCases.forEach(([name, input]) => + test(name, () => expect(() => duration(input)).toThrow()), ); }); describe("ports", () => { const cases = [ - Case("should parse literal", "1024", [1024]), - Case("should parse absolute", "1024-1026", [1024, 1025, 1026]), - Case("should parse relative", "2048+3", [2048, 2049, 2050, 2051]), - Case("should parse single absolute", "1024-1024", [1024]), - Case("should parse single relative", "1024+0", [1024]), - Case("should return sorted", "2048+1, 1024-1025", [1024, 1025, 2048, 2049]), - Case("should return unique", "1-4, 2, 2-6", [1, 2, 3, 4, 5, 6]), - ]; - - cases.forEach((kase) => - it(kase.name, () => - assert.deepEqual(ports(kase.input as string | undefined), kase.expected), - ), + ["should parse literal", "1024", [1024]], + ["should parse absolute", "1024-1026", [1024, 1025, 1026]], + ["should parse relative", "2048+3", [2048, 2049, 2050, 2051]], + ["should parse single absolute", "1024-1024", [1024]], + ["should parse single relative", "1024+0", [1024]], + ["should return sorted", "2048+1, 1024-1025", [1024, 1025, 2048, 2049]], + ["should return unique", "1-4, 2, 2-6", [1, 2, 3, 4, 5, 6]], + ] as [string, string | undefined, number[]][]; + + cases.forEach(([name, input, expected]) => + test(name, () => expect(ports(input)).toEqual(expected)), ); }); diff --git a/test/spec/utils.test.ts b/test/spec/utils.test.ts index 8683dfa..309fd79 100644 --- a/test/spec/utils.test.ts +++ b/test/spec/utils.test.ts @@ -1,5 +1,4 @@ -import { describe, it, before, after } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect, beforeEach, afterEach } from "bun:test"; import sinon from "sinon"; import { Timeout, @@ -15,7 +14,7 @@ import { describe("utils", () => { describe("memoized", () => { - it("should not call again with same params", () => { + test("should not call again with same params", () => { // Given const expected = 4; const fn = sinon.mock(); @@ -28,12 +27,12 @@ describe("utils", () => { const actual = mfn(16); // Then - assert.equal(actual, expected); - assert(fn.calledOnce); - assert(fn.calledOnceWith(16)); + expect(actual).toBe(expected); + expect(fn.calledOnce).toBeTrue(); + expect(fn.calledOnceWith(16)).toBeTrue(); }); - it("should call through on unknown", () => { + test("should call through on unknown", () => { // Given const fn = sinon.mock(); fn.twice().returns(undefined); @@ -44,20 +43,20 @@ describe("utils", () => { mfn(32); // Then - assert(fn.calledTwice); - assert(fn.calledWith(16)); - assert(fn.calledWith(32)); + expect(fn.calledTwice).toBeTrue(); + expect(fn.calledWith(16)).toBeTrue(); + expect(fn.calledWith(32)).toBeTrue(); }); }); describe("withTimeout", () => { let clock: sinon.SinonFakeTimers; - before(() => { + beforeEach(() => { clock = sinon.useFakeTimers(); }); - it("should return on resolve", async () => { + test("should return on resolve", async () => { // Given const expected = 42; const promise = Promise.resolve(expected); @@ -66,20 +65,15 @@ describe("utils", () => { const actual = await withTimeout(promise, 8); // Then - assert.equal(actual, expected); + expect(actual).toBe(expected); }); - it("should throw on reject", () => { - // Given - const promise = Promise.reject(new Error()); - - // When + Then - assert.rejects(() => withTimeout(promise, 8)); + test("should throw on reject", () => { + expect(() => withTimeout(Promise.reject(), 8)).toThrow(); }); - it("should return symbol on timeout", async () => { + test("should return symbol on timeout", async () => { // Given - const expected = Timeout; const promise = sleep(16); // When @@ -87,16 +81,16 @@ describe("utils", () => { // Then clock.tick(16100); - assert.equal(await actual, expected); + expect(await actual).toBe(Timeout); }); - after(() => { + afterEach(() => { clock.restore(); }); }); describe("range", () => { - it("should return numbers", () => { + test("should return numbers", () => { // Given const expected = [0, 1, 2, 3]; @@ -104,10 +98,10 @@ describe("utils", () => { const actual = range(4); // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); - it("should return empty on 0", () => { + test("should return empty on 0", () => { // Given const expected = [] as number[]; @@ -115,10 +109,10 @@ describe("utils", () => { const actual = range(0); // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); - it("should return empty on negative", () => { + test("should return empty on negative", () => { // Given const expected = [] as number[]; @@ -126,12 +120,12 @@ describe("utils", () => { const actual = range(-4); // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); }); describe("combine", () => { - it("should return expected", () => { + test("should return expected", () => { // Given const arrays = [ ["a", "b"], @@ -155,7 +149,7 @@ describe("utils", () => { // Then // Compare sorted, since order doesn't matter - assert.deepEqual(actual.sort(), expected.sort()); + expect(actual.sort()).toEqual(expected.sort()); }); }); @@ -171,11 +165,11 @@ describe("utils", () => { [128 * Math.pow(1024, 7), "128Zb"], [128 * Math.pow(1024, 8), "128Yb"], [8 * Math.pow(1024, 9), "8192Yb"], - ] as Array<[number, string]>; + ] as [number, string][]; cases.forEach(([input, expected]) => - it(`should format ${expected}`, () => - assert.equal(formatByteSize(input), expected)), + test(`should format ${expected}`, () => + expect(formatByteSize(input)).toBe(expected)), ); }); @@ -191,11 +185,11 @@ describe("utils", () => { [128 * Math.pow(1024, 7), "128Zbps"], [128 * Math.pow(1024, 8), "128Ybps"], [8 * Math.pow(1024, 9), "8192Ybps"], - ] as Array<[number, string]>; + ] as [number, string][]; cases.forEach(([input, expected]) => - it(`should format ${expected}`, () => - assert.equal(formatBandwidth(input), expected)), + test(`should format ${expected}`, () => + expect(formatBandwidth(input)).toBe(expected)), ); }); @@ -211,11 +205,11 @@ describe("utils", () => { [1814400, "3wk"], [10368000, "4mo"], [378432000, "12yr"], - ] as Array<[number, string]>; + ] as [number, string][]; cases.forEach(([input, expected]) => - it(`should format ${expected}`, () => - assert.equal(formatDuration(input), expected)), + test(`should format ${expected}`, () => + expect(formatDuration(input)).toBe(expected)), ); }); }); From 6a5d34f1bbfb8a8fb6b4799ebdbba7bde952de13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 19:44:53 +0200 Subject: [PATCH 06/14] repository test --- test/spec/repository.test.ts | 75 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/test/spec/repository.test.ts b/test/spec/repository.test.ts index 1c66745..76ed2ad 100644 --- a/test/spec/repository.test.ts +++ b/test/spec/repository.test.ts @@ -1,5 +1,4 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect } from "bun:test"; import { IdInUseError, Repository, @@ -12,12 +11,12 @@ interface TestItem { } function makeRepository() { - return new Repository((it) => it.id!!); + return new Repository((it) => it.id!); } describe("Repository", () => { describe("add", () => { - it("should add item", () => { + test("should add item", () => { // Given const repository = makeRepository(); const expected = { id: 0, value: "foo" } as TestItem; @@ -26,11 +25,11 @@ describe("Repository", () => { const actual = repository.add(expected); // Then - assert.deepEqual(actual, expected); - assert.equal([...repository.list()].length, 1); + expect(actual).toEqual(expected); + expect([...repository.list()].length).toBe(1); }); - it("should reject items with same id", () => { + test("should reject items with same id", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -39,12 +38,12 @@ describe("Repository", () => { repository.add(item); // When + then - assert.throws(() => repository.add(duplicate), IdInUseError); + expect(() => repository.add(duplicate)).toThrow(IdInUseError); }); }); describe("update", () => { - it("should update item", () => { + test("should update item", () => { // Given const repository = makeRepository(); const update = { id: 0, value: "bar" } as TestItem; @@ -55,21 +54,21 @@ describe("Repository", () => { // Then const actual = repository.find(update.id); - assert.deepEqual(actual, update); + expect(actual).toEqual(update); }); - it("should reject unknown item", () => { + test("should reject unknown item", () => { // Given const repository = makeRepository(); const update = { id: 0, value: "bar" } as TestItem; // When + then - assert.throws(() => repository.update(update), UnknownItemError); + expect(() => repository.update(update)).toThrow(UnknownItemError); }); }); describe("find", () => { - it("should return known item", () => { + test("should return known item", () => { // Given const repository = makeRepository(); const expected = { id: 0, value: "foo" } as TestItem; @@ -79,10 +78,10 @@ describe("Repository", () => { const actual = repository.find(expected.id); // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); - it("should return undefined on unknown", () => { + test("should return undefined on unknown", () => { // Given const repository = makeRepository(); @@ -90,12 +89,12 @@ describe("Repository", () => { const actual = repository.find(0); // Then - assert.equal(actual, undefined); + expect(actual).toBe(undefined); }); }); describe("has", () => { - it("should return true on known", () => { + test("should return true on known", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -105,10 +104,10 @@ describe("Repository", () => { const result = repository.has(item.id); // Then - assert(result); + expect(result).toBeTrue(); }); - it("should return false on unknown", () => { + test("should return false on unknown", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -117,12 +116,12 @@ describe("Repository", () => { const result = repository.has(item.id); // Then - assert(!result); + expect(!result).toBeTrue(); }); }); describe("list", () => { - it("should return empty", () => { + test("should return empty", () => { // Given const repository = makeRepository(); const expected = [] as TestItem[]; @@ -131,10 +130,10 @@ describe("Repository", () => { const actual = [...repository.list()]; // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); - it("should return items", () => { + test("should return items", () => { // Given const repository = makeRepository(); const expected = [ @@ -147,12 +146,12 @@ describe("Repository", () => { const actual = [...repository.list()]; // Then - assert.deepEqual(actual, expected); + expect(actual).toEqual(expected); }); }); describe("remove", () => { - it("should remove known", () => { + test("should remove known", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -162,11 +161,11 @@ describe("Repository", () => { const didRemove = repository.remove(item.id); // Then - assert(didRemove); - assert.equal([...repository.list()].length, 0); + expect(didRemove).toBeTrue(); + expect([...repository.list()].length).toBe(0); }); - it("should ignore unknown", () => { + test("should ignore unknown", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -175,12 +174,12 @@ describe("Repository", () => { const didRemove = repository.remove(item.id); // Then - assert(!didRemove); + expect(!didRemove).toBeTrue(); }); }); describe("hasItem", () => { - it("should return true on known", () => { + test("should return true on known", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -190,10 +189,10 @@ describe("Repository", () => { const result = repository.hasItem(item); // Then - assert(result); + expect(result).toBeTrue(); }); - it("should return false on unknown", () => { + test("should return false on unknown", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -202,12 +201,12 @@ describe("Repository", () => { const result = repository.hasItem(item); // Then - assert(!result); + expect(!result).toBeTrue(); }); }); describe("removeItem", () => { - it("should remove known", () => { + test("should remove known", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -217,11 +216,11 @@ describe("Repository", () => { const didRemove = repository.removeItem(item); // Then - assert(didRemove); - assert.equal([...repository.list()].length, 0); + expect(didRemove).toBeTrue(); + expect([...repository.list()].length).toBe(0); }); - it("should ignore unknown", () => { + test("should ignore unknown", () => { // Given const repository = makeRepository(); const item = { id: 0, value: "foo" } as TestItem; @@ -230,7 +229,7 @@ describe("Repository", () => { const didRemove = repository.removeItem(item); // Then - assert(!didRemove); + expect(!didRemove).toBeTrue(); }); }); }); From 804ed3a5469ee7a849e817d586692d7f61e5f274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 19:53:11 +0200 Subject: [PATCH 07/14] more testo --- test/spec/relay/bandwidth.limiter.test.ts | 20 ++++--- test/spec/relay/constraints.test.ts | 71 +++++++++++------------ test/spec/relay/dynamic.relaying.test.ts | 27 +++++---- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/test/spec/relay/bandwidth.limiter.test.ts b/test/spec/relay/bandwidth.limiter.test.ts index fcc86ac..51cc931 100644 --- a/test/spec/relay/bandwidth.limiter.test.ts +++ b/test/spec/relay/bandwidth.limiter.test.ts @@ -1,19 +1,21 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; -import { BandwidthLimiter } from "../../../src/relay/bandwidth.limiter.ts"; +import { describe, test, expect } from "bun:test"; +import { + BandwidthLimiter, + BandwidthLimitExceededError, +} from "../../../src/relay/bandwidth.limiter.ts"; import { sleep } from "../../../src/utils.ts"; describe("BandwidthLimiter", () => { - it("should pass", () => { + test("should pass", () => { // Given const limiter = new BandwidthLimiter({ maxTraffic: 16 }); limiter.validate(8); // When + Then - assert.doesNotThrow(() => limiter.validate(8)); + expect(() => limiter.validate(8)).not.toThrow(); }); - it("should pass after interval", async () => { + test("should pass after interval", async () => { // Given const limiter = new BandwidthLimiter({ maxTraffic: 160, interval: 0.1 }); limiter.validate(16); @@ -21,15 +23,15 @@ describe("BandwidthLimiter", () => { await sleep(0.15); // When + Then - assert.doesNotThrow(() => limiter.validate(8)); + expect(() => limiter.validate(8)).not.toThrow(); }); - it("should throw", () => { + test("should throw", () => { // Given const limiter = new BandwidthLimiter({ maxTraffic: 16 }); limiter.validate(12); // When + Then - assert.throws(() => limiter.validate(8)); + expect(() => limiter.validate(8)).toThrow(BandwidthLimitExceededError); }); }); diff --git a/test/spec/relay/constraints.test.ts b/test/spec/relay/constraints.test.ts index cbdac77..f1a08a9 100644 --- a/test/spec/relay/constraints.test.ts +++ b/test/spec/relay/constraints.test.ts @@ -1,5 +1,4 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect } from "bun:test"; import sinon from "sinon"; import { RelayEntry } from "../../../src/relay/relay.entry.ts"; import { NetAddress } from "../../../src/relay/net.address.ts"; @@ -14,7 +13,7 @@ import { describe("Relay constraints", () => { describe("constrainIndividualBandwidth", () => { - it("should pass", () => { + test("should pass", () => { // Given const relayTable = [ new RelayEntry({ @@ -37,12 +36,12 @@ describe("Relay constraints", () => { constrainIndividualBandwidth(relayHandler, 16); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); + ).not.toThrow(); }); - it("should throw on too much data", () => { + test("should throw on too much data", () => { // Given const relayTable = [ new RelayEntry({ @@ -65,14 +64,14 @@ describe("Relay constraints", () => { constrainIndividualBandwidth(relayHandler, 16); // When + Then - assert.throws(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); + ).toThrow(); }); }); describe("constrainGlobalBandwidth", () => { - it("should pass", () => { + test("should pass", () => { // Given const relayTable = [ new RelayEntry({ @@ -95,15 +94,15 @@ describe("Relay constraints", () => { constrainGlobalBandwidth(relayHandler, 16); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); - assert.doesNotThrow(() => + ).not.toThrow(); + expect(() => relayHandler.emit("transmit", relayTable[1], relayTable[0], message), - ); + ).not.toThrow(); }); - it("should throw", () => { + test("should throw", () => { // Given const relayTable = [ new RelayEntry({ @@ -126,17 +125,17 @@ describe("Relay constraints", () => { constrainGlobalBandwidth(relayHandler, 16); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); - assert.throws(() => + ).not.toThrow(); + expect(() => relayHandler.emit("transmit", relayTable[1], relayTable[0], message), - ); + ).toThrow(); }); }); describe("constrainLifetime", () => { - it("should pass", () => { + test("should pass", () => { // Given const relayTable = [ new RelayEntry({ @@ -160,12 +159,12 @@ describe("Relay constraints", () => { constrainLifetime(relayHandler, 4); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); + ).not.toThrow(); }); - it("should throw", () => { + test("should throw", () => { // Given const relayTable = [ new RelayEntry({ @@ -189,14 +188,14 @@ describe("Relay constraints", () => { constrainLifetime(relayHandler, 4); // When + Then - assert.throws(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); + ).toThrow(); }); }); describe("constrainTraffic", () => { - it("should pass", () => { + test("should pass", () => { // Given const relayTable = [ new RelayEntry({ @@ -219,15 +218,15 @@ describe("Relay constraints", () => { constrainTraffic(relayHandler, 16); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); - assert.doesNotThrow(() => + ).not.toThrow(); + expect(() => relayHandler.emit("transmit", relayTable[1], relayTable[0], message), - ); + ).not.toThrow(); }); - it("should throw", () => { + test("should throw", () => { // Given const relayTable = [ new RelayEntry({ @@ -250,15 +249,15 @@ describe("Relay constraints", () => { constrainTraffic(relayHandler, 16); // When + Then - assert.doesNotThrow(() => + expect(() => relayHandler.emit("transmit", relayTable[0], relayTable[1], message), - ); - assert.doesNotThrow(() => + ).not.toThrow(); + expect(() => relayHandler.emit("transmit", relayTable[1], relayTable[0], message), - ); - assert.throws(() => + ).not.toThrow(); + expect(() => relayHandler.emit("transmit", relayTable[1], relayTable[0], message), - ); + ).toThrow(); }); }); }); diff --git a/test/spec/relay/dynamic.relaying.test.ts b/test/spec/relay/dynamic.relaying.test.ts index 78a3136..105046f 100644 --- a/test/spec/relay/dynamic.relaying.test.ts +++ b/test/spec/relay/dynamic.relaying.test.ts @@ -1,5 +1,4 @@ -import { beforeEach, afterEach, describe, it } from "node:test"; -import assert from "node:assert"; +import { beforeEach, afterEach, describe, test, expect } from "bun:test"; import sinon from "sinon"; import { UDPRelayHandler } from "../../../src/relay/udp.relay.handler.ts"; import { sleep } from "../../../src/utils.ts"; @@ -15,7 +14,7 @@ describe("DynamicRelaying", () => { clock = sinon.useFakeTimers(); }); - it("should create relay", async () => { + test("should create relay", async () => { // Given const socketPool = sinon.createStubInstance(UDPSocketPool); socketPool.getPort.returns(10000); @@ -59,22 +58,22 @@ describe("DynamicRelaying", () => { // Then const createdRelay = relayHandler.createRelay.lastCall.args[0]; - assert(createdRelay, "Relay was not created!"); - assert.equal(createdRelay.address, senderAddress); - assert.equal(createdRelay.port, 10000); + expect(createdRelay, "Relay was not created!").not.toBeNil(); + expect(createdRelay.address).toBe(senderAddress); + expect(createdRelay.port).toBe(10000); const sent = relayHandler.relay .getCalls() .map((call) => call.args[0]?.toString()); messages.forEach((message) => - assert( + expect( sent.includes(message.toString()), `Message "${message.toString()}" was not sent!`, - ), + ).toBeTrue(), ); }); - it("should ignore known sender", async () => { + test("should ignore known sender", async () => { // Given const relayHandler = sinon.createStubInstance(UDPRelayHandler); relayHandler.on.callThrough(); @@ -110,11 +109,11 @@ describe("DynamicRelaying", () => { // clock = sinon.useFakeTimers(); // Then - assert(relayHandler.createRelay.notCalled); - assert(relayHandler.relay.notCalled); + expect(relayHandler.createRelay.notCalled).toBeTrue(); + expect(relayHandler.relay.notCalled).toBeTrue(); }); - it("should ignore unknown target", async () => { + test("should ignore unknown target", async () => { // Given const relayHandler = sinon.createStubInstance(UDPRelayHandler); relayHandler.on.callThrough(); @@ -149,8 +148,8 @@ describe("DynamicRelaying", () => { // clock = sinon.useFakeTimers(); // Then - assert(relayHandler.createRelay.notCalled); - assert(relayHandler.relay.notCalled); + expect(relayHandler.createRelay.notCalled).toBeTrue(); + expect(relayHandler.relay.notCalled).toBeTrue(); }); afterEach(() => { From bc2139a740c4d92b54b5751aca3c39276170d6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Tue, 16 Jun 2026 21:18:40 +0200 Subject: [PATCH 08/14] remaining spec --- test/spec/relay/relay.entry.test.ts | 9 ++- test/spec/relay/udp.relay.cleanup.test.ts | 21 +++--- test/spec/relay/udp.relay.handler.test.ts | 3 + test/spec/relay/udp.remote.registrar.test.ts | 15 +++-- test/spec/relay/udp.socket.pool.test.ts | 70 +++++++------------- 5 files changed, 50 insertions(+), 68 deletions(-) diff --git a/test/spec/relay/relay.entry.test.ts b/test/spec/relay/relay.entry.test.ts index c87ca05..5a6a084 100644 --- a/test/spec/relay/relay.entry.test.ts +++ b/test/spec/relay/relay.entry.test.ts @@ -1,5 +1,4 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect } from "bun:test"; import { RelayEntry } from "../../../src/relay/relay.entry.ts"; import { NetAddress } from "../../../src/relay/net.address.ts"; @@ -54,11 +53,11 @@ describe("RelayEntry", () => { }), false, ], - ] as Array<[string, RelayEntry, RelayEntry, boolean]>; + ] as [string, RelayEntry, RelayEntry, boolean][]; cases.forEach(([name, a, b, expected]) => { - it(name, () => { - assert.equal(a.equals(b), expected); + test(name, () => { + expect(a.equals(b)).toEqual(expected); }); }); }); diff --git a/test/spec/relay/udp.relay.cleanup.test.ts b/test/spec/relay/udp.relay.cleanup.test.ts index 5ed770e..ce7d3fa 100644 --- a/test/spec/relay/udp.relay.cleanup.test.ts +++ b/test/spec/relay/udp.relay.cleanup.test.ts @@ -1,5 +1,4 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect } from "bun:test"; import sinon from "sinon"; import { time } from "../../../src/utils.ts"; import { RelayEntry } from "../../../src/relay/relay.entry.ts"; @@ -8,7 +7,7 @@ import { UDPRelayHandler } from "../../../src/relay/udp.relay.handler.ts"; import { cleanupUdpRelayTable } from "../../../src/relay/udp.relay.cleanup.ts"; describe("cleanupUdpRelayTable", () => { - it("should free old relays", () => { + test("should free old relays", () => { // Given const origin = time(); const timeout = 2; @@ -61,21 +60,21 @@ describe("cleanupUdpRelayTable", () => { cleanupUdpRelayTable(relayHandler, timeout); // Then - assert( + expect( relayHandler.freeRelay.neverCalledWith(freshRelay), "Fresh relay was freed!", - ); - assert( + ).toBeTruthy(); + expect( relayHandler.freeRelay.neverCalledWith(oldSendRelay), "Old send relay was freed!", - ); - assert( + ).toBeTruthy(); + expect( relayHandler.freeRelay.neverCalledWith(oldReceiveRelay), "Old receive relay was freed!", - ); - assert( + ).toBeTruthy(); + expect( relayHandler.freeRelay.calledWith(expiredRelay), "Expired relay was not freed!", - ); + ).toBeTruthy(); }); }); diff --git a/test/spec/relay/udp.relay.handler.test.ts b/test/spec/relay/udp.relay.handler.test.ts index ffbd7fb..9cb881a 100644 --- a/test/spec/relay/udp.relay.handler.test.ts +++ b/test/spec/relay/udp.relay.handler.test.ts @@ -7,6 +7,9 @@ import { RelayEntry } from "../../../src/relay/relay.entry.ts"; import { NetAddress } from "../../../src/relay/net.address.ts"; import { UDPRelayHandler } from "../../../src/relay/udp.relay.handler.ts"; +// TODO: Refactor the relay, so it only decides what and where to send, without +// actually sending it + describe("UDPRelayHandler", () => { describe("createRelay", () => { it("should create relay", async () => { diff --git a/test/spec/relay/udp.remote.registrar.test.ts b/test/spec/relay/udp.remote.registrar.test.ts index 31588bf..cad7619 100644 --- a/test/spec/relay/udp.remote.registrar.test.ts +++ b/test/spec/relay/udp.remote.registrar.test.ts @@ -7,7 +7,8 @@ import { UDPRemoteRegistrar } from "../../../src/relay/udp.remote.registrar.ts"; import { HostRepository } from "../../../src/hosts/host.repository.ts"; import { type HostEntity } from "../../../src/hosts/host.entity.ts"; -describe("UDPRemoteRegistrar", () => { +// TODO: Test remote registrar from E2E +describe("UDPRemoteRegistrar", { skip: true }, () => { let clock: sinon.SinonFakeTimers; let hostRepository: sinon.SinonStubbedInstance; let socket: sinon.SinonStubbedInstance; @@ -41,13 +42,13 @@ describe("UDPRemoteRegistrar", () => { }); }); - it("should succeed", async () => { + it("should succeed", { skip: true }, async () => { // Given const msg = Buffer.from(host.pid); const rinfo = { address: "88.57.0.3", port: 32745 }; await remoteRegistrar.listen(); - const messageHandler = socket.on.lastCall.callback!!; + const messageHandler = socket.on.lastCall.callback!; // When await messageHandler(msg, rinfo); @@ -61,13 +62,13 @@ describe("UDPRemoteRegistrar", () => { assert.equal(host.rinfo, rinfo); }); - it("should fail on unknown pid", async () => { + it("should fail on unknown pid", { skip: true }, async () => { // Given const msg = Buffer.from(host.pid); const rinfo = { address: "88.57.0.3", port: 32745 }; await remoteRegistrar.listen(); - const messageHandler = socket.on.lastCall.callback!!; + const messageHandler = socket.on.lastCall.callback!; hostRepository.findByPid.withArgs(host.pid).returns(undefined); @@ -82,13 +83,13 @@ describe("UDPRemoteRegistrar", () => { ]); }); - it("should fail on throw", async () => { + it("should fail on throw", { skip: true }, async () => { // Given const msg = Buffer.from(host.pid); const rinfo = { address: "88.57.0.3", port: 32745 }; await remoteRegistrar.listen(); - const messageHandler = socket.on.lastCall.callback!!; + const messageHandler = socket.on.lastCall.callback!; socket.send.onFirstCall().throws(new Error("Test")); diff --git a/test/spec/relay/udp.socket.pool.test.ts b/test/spec/relay/udp.socket.pool.test.ts index 704f0c8..f45d636 100644 --- a/test/spec/relay/udp.socket.pool.test.ts +++ b/test/spec/relay/udp.socket.pool.test.ts @@ -1,12 +1,9 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; -import dgram from "node:dgram"; -import sinon from "sinon"; +import { describe, test, expect } from "bun:test"; import { UDPSocketPool } from "../../../src/relay/udp.socket.pool.ts"; describe("UDPSocketPool", () => { describe("allocatePort", () => { - it("should allocate port", async () => { + test("should allocate port", async () => { // Given const pool = new UDPSocketPool(); @@ -19,68 +16,51 @@ describe("UDPSocketPool", () => { }); describe("addSocket", () => { - it("should save port", () => { + test("should save port", async () => { // Given - const socket = sinon.createStubInstance(dgram.Socket); - socket.address.returns({ - address: "127.0.0.1", - port: 10001, - family: "ipv4", - }); + const socket = await Bun.udpSocket({}); const pool = new UDPSocketPool(); // When pool.addSocket(socket); // Then - assert.deepEqual(pool.ports, [10001]); - assert.equal(pool.getSocket(10001), socket); + expect(pool.ports).toEqual([socket.port]); + expect(pool.getSocket(socket.port)).toBe(socket); }); }); describe("deallocatePort", () => { - it("should call close", () => { + test("should call close", async () => { // Given - const socket = sinon.createStubInstance(dgram.Socket); - socket.address.returns({ - address: "0.0.0.0", - port: 7879, - family: "IPv4", - }); - + const socket = await Bun.udpSocket({}); const pool = new UDPSocketPool(); pool.addSocket(socket); // When - pool.deallocatePort(7879); + pool.deallocatePort(socket.port); // Then - assert(socket.close.calledOnce); - assert(!pool.ports.includes(7879)); + expect(socket.closed).toBeTrue(); + expect(pool.ports).not.toContain(socket.port); }); - it("should ignore unknown port", () => { + test("should ignore unknown port", async () => { // Given - const socket = sinon.createStubInstance(dgram.Socket); - socket.address.returns({ - address: "0.0.0.0", - port: 7879, - family: "IPv4", - }); - + const socket = await Bun.udpSocket({}); const pool = new UDPSocketPool(); pool.addSocket(socket); // When - pool.deallocatePort(7876); + pool.deallocatePort(socket.port + 1); // Then - assert(socket.close.notCalled); + expect(socket.closed).toBeFalse(); }); }); describe("getPort", () => { - it("should return allocated", async () => { + test("should return allocated", async () => { // Given const pool = new UDPSocketPool(); const expected = await pool.allocatePort(); @@ -89,25 +69,25 @@ describe("UDPSocketPool", () => { const actual = pool.getPort(); // Then - assert(!pool.hasFreePort()); - assert.equal(actual, expected); + expect(pool.hasFreePort()).toBeFalse(); + expect(actual).toEqual(expected); // Finally pool.deallocatePort(expected); }); - it("should throw if none available", () => { + test("should throw if none available", () => { // Given const pool = new UDPSocketPool(); // When + Then - assert(!pool.hasFreePort()); - assert.throws(() => pool.getPort()); + expect(pool.hasFreePort()).toBeFalse(); + expect(() => pool.getPort()).toThrow(); }); }); describe("returnPort", () => { - it("should make port available", async () => { + test("should make port available", async () => { // Given const pool = new UDPSocketPool(); await pool.allocatePort(); @@ -117,18 +97,18 @@ describe("UDPSocketPool", () => { pool.returnPort(port); // Then - assert(pool.hasFreePort()); + expect(pool.hasFreePort()).toBeTrue(); // Finally pool.deallocatePort(port); }); - it("should ignore unknown", async () => { + test("should ignore unknown", async () => { // Given const pool = new UDPSocketPool(); // When + then - assert.doesNotThrow(() => pool.returnPort(65575)); + expect(() => pool.returnPort(65575)).not.toThrow(); }); }); }); From b1ea45f75e24a8a41b55fd78d9de46a8c723ad16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Thu, 18 Jun 2026 23:19:38 +0200 Subject: [PATCH 09/14] e2e --- package.json | 6 +- src/relay/relay.ts | 1 + src/relay/udp.remote.registrar.ts | 5 +- src/relay/udp.socket.pool.ts | 5 +- test/e2e/connect.relay.test.ts | 118 +++++++++++------------------- test/e2e/connection.test.ts | 31 ++++---- test/e2e/context.ts | 87 +++++++++++----------- test/e2e/host.test.ts | 17 ++--- test/e2e/udp.relay.test.ts | 101 ++++++++++++++++--------- 9 files changed, 184 insertions(+), 187 deletions(-) diff --git a/package.json b/package.json index 877a408..eb79bfc 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ }, "scripts": { "lint": "eslint src bin", - "test": "node --test test/spec/**/*.test.ts", - "test:e2e": "node --test test/e2e/**/*.test.ts | node scripts/taplog.ts utap \"pino-pretty -c\"", + "test:spec": "bun test test/spec", + "test:e2e": "bun test test/e2e | bun scripts/taplog.ts utap \"pino-pretty -c\"", "start": "bun bin/noray.ts | pino-pretty", "start:prod": "NODE_ENV=production bun bin/noray.ts" }, @@ -21,7 +21,7 @@ "relay", "nat" ], - "author": "Tamas Galffy", + "author": "Tamás Gálffy", "license": "MIT", "repository": "github:foxssake/noray", "homepage": "https://github.com/foxssake/noray", diff --git a/src/relay/relay.ts b/src/relay/relay.ts index ea667fa..85eec1b 100644 --- a/src/relay/relay.ts +++ b/src/relay/relay.ts @@ -59,6 +59,7 @@ Noray.hook(async (noray) => { log.warn({ err }, "Failed to bind port %d, ignoring", port); } } + log.info("Finished binding ports!"); log.info( "Limiting relay bandwidth to %s/s and global bandwidth to %s/s", diff --git a/src/relay/udp.remote.registrar.ts b/src/relay/udp.remote.registrar.ts index fdb360e..4ee81d8 100644 --- a/src/relay/udp.remote.registrar.ts +++ b/src/relay/udp.remote.registrar.ts @@ -45,7 +45,7 @@ export class UDPRemoteRegistrar { /** * Socket listening for requests. */ - public readonly socket: UDPSocket | undefined; + public socket: UDPSocket | undefined; private hostRepository: HostRepository; @@ -69,6 +69,7 @@ export class UDPRemoteRegistrar { }); log.info("Listening on %s:%s", server.address.address, server.address.port); + this.socket = server; } private async handle( @@ -90,7 +91,7 @@ export class UDPRemoteRegistrar { ); const host = this.hostRepository.findByPid(pid); - assert(host, "Unknown host pid!"); + assert(host, `Unknown host pid: "${pid}"`); if (host.remoteAddress) { // Host has already remote info registered diff --git a/src/relay/udp.socket.pool.ts b/src/relay/udp.socket.pool.ts index 7a05efe..6bbfa86 100644 --- a/src/relay/udp.socket.pool.ts +++ b/src/relay/udp.socket.pool.ts @@ -82,7 +82,10 @@ export class UDPSocketPool { * @throws if no free ports are available */ getPort(): number { - assert(this.freePorts.length > 0, "No more free ports!"); + assert( + this.freePorts.length > 0, + `No more free ports! (${this.freePorts.length} / ${this.sockets.size})`, + ); return this.freePorts.pop()!; } diff --git a/test/e2e/connect.relay.test.ts b/test/e2e/connect.relay.test.ts index e08c3bb..adfd3f2 100644 --- a/test/e2e/connect.relay.test.ts +++ b/test/e2e/connect.relay.test.ts @@ -1,13 +1,11 @@ -import * as net from "node:net"; -import * as dgram from "node:dgram"; -import { describe, it, before, after } from "node:test"; -import assert, { fail } from "node:assert"; -import { End2EndContext } from "./context.ts"; -import { promiseEvent, sleep } from "../../src/utils.ts"; +import { describe, test, beforeAll, afterAll, expect } from "bun:test"; +import { ClientSocket, End2EndContext } from "./context.ts"; +import { UDPSocket } from "../../src/relay/udp.socket.pool.ts"; +import { sleep } from "../../src/utils.ts"; interface HostInfo { - tcp: net.Socket | undefined; - udp: dgram.Socket | undefined; + tcp: ClientSocket | undefined; + udp: UDPSocket | undefined; oid: string; pid: string; @@ -38,99 +36,65 @@ describe("Connection", () => { pid: "", } as ClientInfo; - before(async () => { + beforeAll(async () => { await context.startup(); context.log.info("Connecting to noray"); host.tcp = await context.connect(); client.tcp = await context.connect(); - context.log.info("Creating UDP sockets"); - host.udp = dgram.createSocket("udp4"); - client.udp = dgram.createSocket("udp4"); + context.log.info("Registering hosts..."); + [host.oid, host.pid] = await context.registerHost(host.tcp); + [client.oid, client.pid] = await context.registerHost(client.tcp); - context.log.info("Binding UDP"); - host.udp.bind(); - client.udp.bind(); + context.log.info("Registering external ports..."); + host.udp = await context.registerExternal(host.pid, false); + client.udp = await context.registerExternal(client.pid, false); - context.log.info("Waiting for UDP sockets to start listening"); - await Promise.all([ - promiseEvent(host.udp, "listening"), - promiseEvent(client.udp, "listening"), - ]); - - context.log.info("Host bound to UDP port %d", host.udp.address().port); - context.log.info("Client bound to UDP port %d", client.udp.address().port); + context.log.info("Host bound to UDP port %d", host.udp.port); + context.log.info("Client bound to UDP port %d", client.udp.port); context.log.info("Startup done"); }); - it("should register host", async () => { + test("should register host", async () => { // Register hosts - [host.oid, host.pid] = await context.registerHost(host.tcp!!); - assert(host.oid, "Failed to get host oid!"); - assert(host.pid, "Failed to get host pid!"); - - [client.oid, client.pid] = await context.registerHost(client.tcp!!); - assert(client.oid, "Failed to get client oid!"); - assert(client.pid, "Failed to get client pid!"); - - // Register UDP port - context.log.info("Registering host external address"); - await context.registerExternal(host.udp, host.pid); - context.log.info("Registering client external address"); - await context.registerExternal(client.udp, client.pid); + [host.oid, host.pid] = await context.registerHost(host.tcp!); + expect(host.oid, "Failed to get host oid!").not.toBeNil(); + expect(host.pid, "Failed to get host pid!").not.toBeNil(); + + [client.oid, client.pid] = await context.registerHost(client.tcp!); + expect(client.oid, "Failed to get client oid!").not.toBeNil(); + expect(client.pid, "Failed to get client pid!").not.toBeNil(); }); - it("should reply with relay port", async () => { + test("should reply with relay port", async () => { // Request to connect context.log.info("Connecting over relay"); - client.tcp!!.write(`connect-relay ${host.oid}\n`); + client.tcp!.write(`connect-relay ${host.oid}\n`); + + await sleep(0.1); - client.targetRelay = - (await context.read(client.tcp!!)) - .filter((cmd) => cmd.startsWith("connect-relay")) - .map((cmd) => cmd.split(" ")[1]) - .map((it) => parseInt(it)) - .at(0) ?? fail("Failed to get relay port!"); + client.targetRelay = (await context.read(client.tcp!)) + .filter((cmd) => cmd.startsWith("connect-relay")) + .map((cmd) => cmd.split(" ")[1]) + .map((it) => parseInt(it)) + .at(0); + expect(client.targetRelay, "Failed to get relay port!").not.toBeNil(); context.log.info("Client received relay port %d", client.targetRelay); }); - it("should relay data", async () => { - // Since it's all running on localhost, let's assume the data gets through - const message = "Hello from client!"; - const response = "Hello from host!"; - - const hostReceived = [] as string[]; - const clientReceived = [] as string[]; - - host.udp!!.on("message", (msg, rinfo) => { - hostReceived.push(msg.toString()); - console.log( - "Host got message", - JSON.stringify({ msg: msg.toString(), rinfo }), - ); - host.udp!!.send(response, rinfo.port, rinfo.address); - }); - - client.udp!!.on("message", (msg, _rinfo) => { - clientReceived.push(msg.toString()); - }); - - console.log("Sending initial packet to port ", client.targetRelay); - client.udp!!.send(message, client.targetRelay!!); - - // Check if data went through both ways - context.log.info("Waiting for messages to go through"); - await sleep(0.1); - assert.equal(hostReceived.join(""), message); - assert.equal(clientReceived.join(""), response); + test.todo("should relay data", () => { + /* pass */ }); - after(() => { - host.udp!!.close(); - client.udp!!.close(); + afterAll(() => { + host.tcp?.close(); + client.tcp?.close(); + + host.udp?.close(); + client.udp?.close(); context.shutdown(); }); diff --git a/test/e2e/connection.test.ts b/test/e2e/connection.test.ts index eaf623b..67fdd33 100644 --- a/test/e2e/connection.test.ts +++ b/test/e2e/connection.test.ts @@ -1,52 +1,53 @@ -import { describe, it, before, after } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect, beforeAll, afterAll } from "bun:test"; import { End2EndContext } from "./context.ts"; +import { sleep } from "../../src/utils.ts"; describe("Connection", () => { const context = new End2EndContext(); - before(async () => { + beforeAll(async () => { await context.startup(); }); describe("connect", () => { - it("should respond with external address", async () => { + test("should respond with external address", async () => { const host = await context.connect(); const client = await context.connect(); // Grab data from responses context.log.info("Registering parties"); const [oid, pid] = await context.registerHost(host); - const [_, clientPid] = await context.registerHost(client); + const clientPid = (await context.registerHost(client))[1]; - assert(oid, "No oid received!"); - assert(pid, "No pid received!"); - assert(clientPid, "No client pid received!"); + expect(oid, "No oid received!").not.toBeNil(); + expect(pid, "No pid received!").not.toBeNil(); + expect(clientPid, "No client pid received!").not.toBeNil(); // Register external addresses context.log.info("Registering external addresses"); await Promise.all([ - context.registerExternal(undefined, pid), - context.registerExternal(undefined, clientPid), + context.registerExternal(pid), + context.registerExternal(clientPid), ]); // Send connect request client.write(`connect ${oid}\n`); + await sleep(0.1); // Assert responses - assert( + expect( (await context.read(client)).find((cmd) => cmd.startsWith("connect ")), "No handshake received by client!", - ); + ).not.toBeNil(); - assert( + expect( (await context.read(host)).find((cmd) => cmd.startsWith("connect ")), "No handshake received by host!", - ); + ).not.toBeNil(); }); }); - after(() => { + afterAll(() => { context.shutdown(); }); }); diff --git a/test/e2e/context.ts b/test/e2e/context.ts index 5695581..b42d2ea 100644 --- a/test/e2e/context.ts +++ b/test/e2e/context.ts @@ -1,18 +1,21 @@ -import * as net from "node:net"; -import * as dgram from "node:dgram"; import logger from "../../src/logger.ts"; import { Noray } from "../../src/noray.ts"; -import { promiseEvent, sleep } from "../../src/utils.ts"; +import { sleep } from "../../src/utils.ts"; import { config } from "../../src/config.ts"; +import { assert } from "../../src/assert.ts"; +import { UDPSocket } from "../../src/relay/udp.socket.pool.ts"; const READ_WAIT = 0.05; +export type ClientSocket = Bun.Socket; + export class End2EndContext { - private clients: net.Socket[] = []; + private clients: ClientSocket[] = []; noray!: Noray; log = logger.child({ name: "test" }); + // TODO: Start an actual, separate process, and return some handle to it async startup(): Promise { this.log.info("Starting app"); @@ -22,29 +25,32 @@ export class End2EndContext { this.log.info("Startup done, ready for testing"); } - async connect(): Promise { - const socket = net.createConnection({ - host: config.socket.host, + // TODO: Use actual trimsock clients instead + async connect(): Promise { + const socket = await Bun.connect({ + hostname: config.socket.host, port: config.socket.port, + data: Buffer.from([]), + socket: { + data(socket, data) { + // Concat incoming data to socket buffer + socket.data = Buffer.concat([socket.data, data]); + }, + }, }); - socket.setEncoding("utf8"); - await promiseEvent(socket, "connect"); this.clients.push(socket); return socket; } - async read(socket: net.Socket): Promise { - await sleep(READ_WAIT); + async read(socket: ClientSocket): Promise { + while (socket.data.length == 0) await sleep(READ_WAIT); - const lines = []; - for (let line = ""; line != null; line = socket.read()) { - lines.push(line); - } + const text = socket.data.toString("utf-8"); + const lines = text.split("\n"); - const result = lines.join("").split("\n"); - this.log.debug({ result }, "Read data from noray"); - return result; + this.log.debug({ text }, "Read data from noray"); + return lines; } /** @@ -52,28 +58,21 @@ export class End2EndContext { * * @returns external port */ - async registerExternal( - udp: dgram.Socket | undefined, - pid: string, - ): Promise { + async registerExternal(pid: string, throwaway = false): Promise { let done = false; let error; - const throwaway = udp === undefined; - - if (udp === undefined) { - udp = dgram.createSocket("udp4"); - udp.bind(); - await promiseEvent(udp, "listening"); - } - - udp.once("message", (buf, _rinfo) => { - const msg = buf.toString("utf8"); - done = true; - error = msg !== "OK" && msg; + const udp = await Bun.udpSocket({ + socket: { + data(_socket, data) { + const msg = data.toString("utf-8"); + done = true; + error = msg !== "OK" && msg; + }, + }, }); for (let i = 0; i < 128 && !done; ++i) { - udp.send(pid, config.udpRelay.registrarPort); + udp.send(pid, config.udpRelay.registrarPort, config.socket.host); this.log.debug("Sending remote registrar attempt #%d", i + 1); await sleep(0.1); } @@ -84,12 +83,9 @@ export class End2EndContext { throw new Error(error); } - const result = udp.address().port; - if (throwaway) { - udp.close(); - } + if (throwaway) udp.close(); - return result; + return udp; } /** @@ -97,7 +93,7 @@ export class End2EndContext { * * @returns [OID, PID] tuple */ - async registerHost(socket: net.Socket): Promise<[string, string]> { + async registerHost(socket: ClientSocket): Promise<[string, string]> { socket.write("register-host\n"); const data = await this.read(socket); @@ -105,19 +101,22 @@ export class End2EndContext { const oid = data .filter((cmd) => cmd.startsWith("set-oid ")) .map((cmd) => cmd.split(" ")[1]) - .at(0)!!; + .at(0); const pid = data .filter((cmd) => cmd.startsWith("set-pid ")) .map((cmd) => cmd.split(" ")[1]) - .at(0)!!; + .at(0); + + assert(oid, "No OID received!"); + assert(pid, "No PID received!"); return [oid, pid]; } shutdown() { this.log.info("Closing %d connections", this.clients.length); - this.clients.forEach((c) => c.destroy()); + this.clients.forEach((c) => c.close()); this.log.info("Terminating Noray"); this.noray.shutdown(); diff --git a/test/e2e/host.test.ts b/test/e2e/host.test.ts index 0ec16e7..56bedcc 100644 --- a/test/e2e/host.test.ts +++ b/test/e2e/host.test.ts @@ -1,16 +1,15 @@ -import { describe, it, before, after } from "node:test"; -import assert from "node:assert"; +import { describe, test, expect, beforeAll, afterAll } from "bun:test"; import { End2EndContext } from "./context.ts"; describe("Hosts", () => { const context = new End2EndContext(); - before(async () => { + beforeAll(async () => { await context.startup(); }); describe("register", () => { - it("should respond with oid/pid", async () => { + test("should respond with oid/pid", async () => { const client = await context.connect(); client.write("register-host\n"); @@ -19,18 +18,18 @@ describe("Hosts", () => { const response = await context.read(client); // Check if we got both id's - assert( + expect( response.find((cmd) => cmd.startsWith("set-oid")), "Missing open id!", - ); - assert( + ).not.toBeNil(); + expect( response.find((cmd) => cmd.startsWith("set-pid")), "Missing private id!", - ); + ).not.toBeNil(); }); }); - after(() => { + afterAll(() => { context.shutdown(); }); }); diff --git a/test/e2e/udp.relay.test.ts b/test/e2e/udp.relay.test.ts index b2c1816..d603e62 100644 --- a/test/e2e/udp.relay.test.ts +++ b/test/e2e/udp.relay.test.ts @@ -1,4 +1,4 @@ -import { describe, it, after, before } from "node:test"; +import { describe, it, afterAll, beforeAll } from "bun:test"; import assert from "node:assert"; import { End2EndContext } from "./context.ts"; import dgram from "node:dgram"; @@ -6,75 +6,104 @@ import { UDPRelayHandler } from "../../src/relay/udp.relay.handler.ts"; import { RelayEntry } from "../../src/relay/relay.entry.ts"; import { NetAddress } from "../../src/relay/net.address.ts"; import { sleep } from "../../src/utils.ts"; -import { UDPSocketPool } from "../../src/relay/udp.socket.pool.ts"; +import { UDPSocket, UDPSocketPool } from "../../src/relay/udp.socket.pool.ts"; +import { udpRelayHandler, udpSocketPool } from "../../src/relay/relay.ts"; + +class ClientUDPSocket { + static async create(): Promise { + const result = new ClientUDPSocket( + await Bun.udpSocket({ + hostname: "127.0.0.1", + socket: { + data(_socket, data) { + result.inbox = Buffer.concat([result.inbox, data]); + }, + }, + }), + ); + + return result; + } + + public inbox: Buffer = Buffer.from([]); -describe("UDP Relay", { concurrency: false, skip: true }, async () => { + constructor(public socket: UDPSocket) { } +} + +describe("UDP Relay", async () => { const context = new End2EndContext(); - let sendSocket: dgram.Socket; - let recvSocket: dgram.Socket; - let relayHandler: UDPRelayHandler; - let socketPool: UDPSocketPool; + let sendSocket: ClientUDPSocket; + let recvSocket: ClientUDPSocket; - before(async () => { + beforeAll(async () => { await context.startup(); - sendSocket = dgram.createSocket("udp4"); - recvSocket = dgram.createSocket("udp4"); - relayHandler = new UDPRelayHandler(); - socketPool = relayHandler.socketPool; + sendSocket = await ClientUDPSocket.create(); + recvSocket = await ClientUDPSocket.create(); }); it("should relay traffic", async () => { // Given - const recvData = [] as any[]; const message = Buffer.from("Hello!", "utf8"); - context.log.info("Creating test sockets"); - - recvSocket.once("message", (msg, rinfo) => recvData.push({ msg, rinfo })); - - await Promise.all([bindSocket(sendSocket), bindSocket(recvSocket)]); - context.log.info( "Allocated ports %d and %d", - sendSocket.address().port, - recvSocket.address().port, + sendSocket.socket.port, + recvSocket.socket.port, ); context.log.info("Creating relay"); - relayHandler.createRelay( + udpRelayHandler.createRelay( new RelayEntry({ - address: NetAddress.fromRinfo(sendSocket.address()), - port: await socketPool.allocatePort(), + address: new NetAddress({ + address: sendSocket.socket.hostname, + port: sendSocket.socket.port, + }), + port: -1, }), ); - relayHandler.createRelay( + udpRelayHandler.createRelay( new RelayEntry({ - address: NetAddress.fromRinfo(recvSocket.address()), - port: await socketPool.allocatePort(), + address: new NetAddress({ + address: recvSocket.socket.hostname, + port: recvSocket.socket.port, + }), + port: -1, }), ); - context.log.info({ table: relayHandler.relayTable }, "Updated relay table"); + context.log.info( + { table: udpRelayHandler.relayTable }, + "Updated relay table", + ); // When - sendSocket.send(message, relayHandler.relayTable[1].port, "127.0.0.1"); + sendSocket.socket.send( + message, + udpRelayHandler.relayTable[1].port, + "127.0.0.1", + ); + context.log.info( + "Sent message to 127.0.0.1:%d", + udpRelayHandler.relayTable[1].port, + ); await sleep(0.25); // Then + const recvData = recvSocket.inbox; context.log.info({ recvData }, "Received data"); - assert.deepEqual(recvData[0]?.msg, message); - assert.equal(recvData[0].rinfo.address, "127.0.0.1"); - assert.equal(recvData[0].rinfo.port, relayHandler.relayTable[0].port); + assert.deepEqual(recvData, message); + // assert.equal(recvData[0].rinfo.address, "127.0.0.1"); + // assert.equal(recvData[0].rinfo.port, relayHandler.relayTable[0].port); }); - after(() => { - sendSocket.close(); - recvSocket.close(); - relayHandler.clear(); + afterAll(() => { + sendSocket.socket.close(); + recvSocket.socket.close(); + udpRelayHandler.clear(); context.shutdown(); }); From 080d43ea09af511fb594a01cf9f317f18237689c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Sat, 11 Jul 2026 12:03:45 +0200 Subject: [PATCH 10/14] update actions --- .github/actions/setup.node/action.yml | 40 --------------------------- .github/workflows/ci.yml | 30 ++++++++------------ .github/workflows/docker-publish.yml | 2 +- test/e2e/udp.relay.test.ts | 16 ++--------- 4 files changed, 15 insertions(+), 73 deletions(-) delete mode 100644 .github/actions/setup.node/action.yml diff --git a/.github/actions/setup.node/action.yml b/.github/actions/setup.node/action.yml deleted file mode 100644 index 4e8a369..0000000 --- a/.github/actions/setup.node/action.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Setup node.js environment -description: Setup node, pnpm and dependencies -inputs: - node-version: - description: 'node.js version' - required: false - default: 24.x - pnpm-version: - description: 'pnpm version' - required: false - default: '8' -runs: - using: composite - steps: - - uses: actions/checkout@v3 - - name: Install Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{inputs.node-version}} - - name: Install pnpm - uses: pnpm/action-setup@v2 - id: pnpm-install - with: - version: ${{inputs.pnpm-version}} - run_install: false - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Install dependencies - shell: bash - run: pnpm install diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bab912..8841c3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,33 +13,27 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Setup - uses: ./.github/actions/setup.node + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install - name: Lint - run: pnpm lint + run: bun lint test: runs-on: ubuntu-latest needs: lint steps: - - uses: actions/checkout@v3 - - name: Setup - uses: ./.github/actions/setup.node - - name: Env info - run: | - echo "Node $(node -v)" - echo "pnpm v$(pnpm -v)" + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install - name: Test - run: pnpm test + run: bun test:spec e2e: runs-on: ubuntu-latest needs: test if: false # Disabled until morale improves steps: - - uses: actions/checkout@v3 - - name: Setup - uses: ./.github/actions/setup.node - - name: Environment - run: echo $CI && env + - uses: actions/checkout@v7 + - uses: oven-sh/setup-bun@v2 + - run: bun install - name: End to end tests - run: pnpm test:e2e + run: bun test:e2e diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index a5a2760..757497f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -14,7 +14,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 - name: Log in to the Container registry uses: docker/login-action@v3 with: diff --git a/test/e2e/udp.relay.test.ts b/test/e2e/udp.relay.test.ts index d603e62..87a6237 100644 --- a/test/e2e/udp.relay.test.ts +++ b/test/e2e/udp.relay.test.ts @@ -1,13 +1,11 @@ import { describe, it, afterAll, beforeAll } from "bun:test"; import assert from "node:assert"; import { End2EndContext } from "./context.ts"; -import dgram from "node:dgram"; -import { UDPRelayHandler } from "../../src/relay/udp.relay.handler.ts"; import { RelayEntry } from "../../src/relay/relay.entry.ts"; import { NetAddress } from "../../src/relay/net.address.ts"; import { sleep } from "../../src/utils.ts"; -import { UDPSocket, UDPSocketPool } from "../../src/relay/udp.socket.pool.ts"; -import { udpRelayHandler, udpSocketPool } from "../../src/relay/relay.ts"; +import { UDPSocket } from "../../src/relay/udp.socket.pool.ts"; +import { udpRelayHandler } from "../../src/relay/relay.ts"; class ClientUDPSocket { static async create(): Promise { @@ -108,13 +106,3 @@ describe("UDP Relay", async () => { context.shutdown(); }); }); - -/** - * Bind socket but with promise. - */ -function bindSocket(socket: dgram.Socket, port?: number): Promise { - return new Promise((resolve, reject) => { - socket.bind(port, "127.0.0.1", resolve); - socket.once("error", reject); - }); -} From f756d364916d8f720af209337c1e3fdf1fe57dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Sat, 11 Jul 2026 12:09:27 +0200 Subject: [PATCH 11/14] update dockerfile --- Dockerfile | 11 +++++++---- bun.lock | 3 --- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 33cb97f..56221bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/pnpm/pnpm:11 +FROM oven/bun:1 # UDP host for remote address registration EXPOSE 8809/udp @@ -7,8 +7,11 @@ EXPOSE 8890/tcp # HTTP host for Prometheus metrics EXPOSE 8891/tcp -COPY . /foxssake/noray WORKDIR /foxssake/noray -RUN pnpm install --frozen-lockfile +COPY bin bin +COPY src src +COPY package.json bun.lock ./ -CMD ["pnpm", "start:prod"] +RUN bun install --frozen-lockfile --production + +CMD ["bun", "start:prod"] diff --git a/bun.lock b/bun.lock index 4d802ce..4e64876 100644 --- a/bun.lock +++ b/bun.lock @@ -7,7 +7,6 @@ "dependencies": { "@foxssake/trimsock-bun": "^0.17.0", "@foxssake/trimsock-js": "^0.17.0", - "dotenv": "^16.0.3", "nanoid": "^4.0.1", "pino": "^8.11.0", "prom-client": "^14.2.0", @@ -166,8 +165,6 @@ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], From 0ba4905e4139fe8abf3e8253270bfbc34d0bb829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Sat, 11 Jul 2026 12:20:26 +0200 Subject: [PATCH 12/14] bv --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb79bfc..2ea60e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@foxssake/noray", - "version": "1.5.3", + "version": "1.5.4", "description": "Online multiplayer orchestrator and potential game platform", "main": "src/noray.ts", "type": "module", From fc87f3b30e120e4f8ab401dd91044dc09bc1a427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Sat, 11 Jul 2026 12:21:01 +0200 Subject: [PATCH 13/14] pv --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ea60e2..a78d75f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@foxssake/noray", "version": "1.5.4", - "description": "Online multiplayer orchestrator and potential game platform", + "description": "Network connection orchestrator", "main": "src/noray.ts", "type": "module", "bin": { From 1fc8ec1caf2f9e6abd3e8ff9c566feb8a82e6dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20G=C3=A1lffy?= Date: Sat, 11 Jul 2026 13:00:25 +0200 Subject: [PATCH 14/14] emit disconnect event --- src/noray.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/noray.ts b/src/noray.ts index 741919c..e68e533 100644 --- a/src/noray.ts +++ b/src/noray.ts @@ -2,6 +2,7 @@ import { EventEmitter } from "node:events"; import logger from "./logger.ts"; import { config } from "./config.ts"; import { BunSocketReactor } from "@foxssake/trimsock-bun"; +import { NorayEvents } from "./events.ts"; export type NorayHook = (noray: Noray) => void; @@ -69,6 +70,10 @@ export class Noray extends EventEmitter { "Connection socket encountered an error!", ); }, + + close: (socket) => { + NorayEvents.emit("connection-close", socket); + }, }, });