diff --git a/.ackrc b/.ackrc index 16d13cc..244cbf6 100644 --- a/.ackrc +++ b/.ackrc @@ -1,6 +1,6 @@ --ignore-dir=docs --ignore-dir=dist --ignore-dir=build ---ignore-dir=__tests__ +# --ignore-dir=__tests__ --ignore-dir=.svelte-kit --ignore-file=match:yarn.lock diff --git a/package-lock.json b/package-lock.json index cd5c7e5..c64ca7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1058,19 +1058,6 @@ "node": ">=8" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -1712,13 +1699,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, "node_modules/@tiptap/core": { "version": "2.11.5", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.11.5.tgz", @@ -2753,19 +2733,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2808,16 +2775,6 @@ "node": ">= 14.0.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2873,20 +2830,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2948,19 +2891,6 @@ "dev": true, "license": "MIT" }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/birpc": { "version": "0.2.19", "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", @@ -2995,13 +2925,6 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, "node_modules/builtins": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", @@ -3144,44 +3067,6 @@ "node": ">= 16" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3205,18 +3090,6 @@ "node": ">= 10" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/code-red": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", @@ -3277,13 +3150,6 @@ "dev": true, "license": "MIT" }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -3437,26 +3303,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3572,16 +3418,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4146,16 +3982,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -4259,26 +4085,6 @@ "node": ">=10" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -4489,16 +4295,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", @@ -4664,19 +4460,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -4778,19 +4561,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -5017,23 +4787,6 @@ "license": "MIT", "peer": true }, - "node_modules/local-pkg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", - "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.7.3", - "pkg-types": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -5070,23 +4823,6 @@ "dev": true, "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", @@ -5466,115 +5202,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" - } - }, - "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5648,16 +5275,6 @@ "node": ">=10" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/nostr-editor": { "version": "0.0.4-pre.14", "resolved": "https://registry.npmjs.org/nostr-editor/-/nostr-editor-0.0.4-pre.14.tgz", @@ -6025,18 +5642,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -6116,34 +5721,6 @@ "node": ">=6.0.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/property-information": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", @@ -6400,23 +5977,6 @@ "node": ">=8" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -6557,19 +6117,6 @@ "node": ">=8" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -6624,16 +6171,6 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -6806,27 +6343,6 @@ "npm": ">=2.0.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6855,16 +6371,6 @@ "node": ">=10" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7140,26 +6646,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", - "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, "node_modules/superjson": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", @@ -7529,16 +7015,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -7653,13 +7129,6 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, - "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true, - "license": "MIT" - }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -8087,31 +7556,6 @@ "node": ">=0.10.0" } }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", @@ -8173,16 +7617,6 @@ } } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -8203,25 +7637,6 @@ "node": ">= 14" } }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", @@ -8232,58 +7647,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -8473,9 +7836,6 @@ "@welshman/util": "^0.1.0", "isomorphic-ws": "^5.0.0", "ws": "^8.16.0" - }, - "devDependencies": { - "mocha": "^10.7.3" } }, "packages/net2": { @@ -8487,458 +7847,6 @@ "@welshman/util": "^0.1.0", "isomorphic-ws": "^5.0.0", "typed-emitter": "^2.1.0" - }, - "devDependencies": { - "mocha": "^10.7.3", - "vitest": "^1.0.0" - } - }, - "packages/net2/node_modules/@vitest/expect": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", - "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/@vitest/runner": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", - "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "1.6.1", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/@vitest/snapshot": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", - "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/@vitest/spy": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", - "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/@vitest/utils": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", - "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "packages/net2/node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/net2/node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "packages/net2/node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "packages/net2/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "packages/net2/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "packages/net2/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "packages/net2/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "packages/net2/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "packages/net2/node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "packages/net2/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/net2/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/net2/node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "packages/net2/node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "packages/net2/node_modules/vite-node": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", - "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/net2/node_modules/vitest": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", - "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.1", - "@vitest/runner": "1.6.1", - "@vitest/snapshot": "1.6.1", - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.1", - "@vitest/ui": "1.6.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "packages/net2/node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "packages/signer": { diff --git a/packages/net2/__tests__/Socket.test.ts b/packages/net2/__tests__/Socket.test.ts index 057cf28..a61ca33 100644 --- a/packages/net2/__tests__/Socket.test.ts +++ b/packages/net2/__tests__/Socket.test.ts @@ -1,36 +1,35 @@ import { sleep } from "@welshman/lib" -import WebSocket from "isomorphic-ws" +import WebSocket from 'isomorphic-ws' import { afterEach, beforeEach, describe, expect, it, vi } from "vitest" import { Socket, SocketStatus, SocketEventType } from "../src/socket" import { ClientMessage, RelayMessage } from "../src/message" -vi.mock("isomorphic-ws") +vi.mock('isomorphic-ws', () => { + const WebSocket = vi.fn(function () { + setTimeout(() => this.onopen()) + }) + + WebSocket.prototype.send = vi.fn() + + WebSocket.prototype.close = vi.fn(function () { + this.onclose() + }) + + return { default: WebSocket } +}) describe("Socket", () => { let socket: Socket - let mockWs: any beforeEach(() => { vi.useFakeTimers() - vi.clearAllMocks() - - mockWs = { - close: vi.fn(), - send: vi.fn(), - onopen: null, - onclose: null, - onerror: null, - onmessage: null, - } - - vi.mocked(WebSocket).mockImplementation(() => mockWs) - socket = new Socket("wss://test.relay") }) afterEach(() => { - socket.cleanup() + vi.clearAllMocks() vi.useRealTimers() + socket.cleanup() }) it("should initialize with correct url", () => { @@ -44,16 +43,10 @@ describe("Socket", () => { socket.open() - expect(WebSocket).toHaveBeenCalledWith("wss://test.relay") + expect(socket._ws).toBeDefined() expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Opening, "wss://test.relay") - }) - it("should emit open status when connection opens", () => { - const statusSpy = vi.fn() - socket.on(SocketEventType.Status, statusSpy) - - socket.open() - mockWs.onopen() + vi.runAllTimers() expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Open, "wss://test.relay") }) @@ -83,10 +76,12 @@ describe("Socket", () => { socket.on(SocketEventType.Status, statusSpy) socket.open() - socket.close() - mockWs.onclose() - expect(mockWs.close).toHaveBeenCalled() + const ws = socket._ws + + socket.close() + + expect(ws.close).toHaveBeenCalled() expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Closed, "wss://test.relay") }) }) @@ -96,26 +91,25 @@ describe("Socket", () => { const enqueueSpy = vi.fn() socket.on(SocketEventType.Enqueue, enqueueSpy) - const message: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const message: ClientMessage = ["EVENT", { id: "123", kind: 1 }] socket.send(message) expect(enqueueSpy).toHaveBeenCalledWith(message, "wss://test.relay") }) - it("should send queued messages when socket is open", async () => { + it("should send messages when socket is open", async () => { const sendSpy = vi.fn() socket.on(SocketEventType.Send, sendSpy) socket.open() - mockWs.onopen() + socket._ws.onopen() - const message: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const message: ClientMessage = ["EVENT", { id: "123", kind: 1 }] socket.send(message) - // Allow task queue to process await vi.runAllTimers() - expect(mockWs.send).toHaveBeenCalledWith(JSON.stringify(message)) + expect(socket._ws.send).toHaveBeenCalledWith(JSON.stringify(message)) expect(sendSpy).toHaveBeenCalledWith(message, "wss://test.relay") }) }) @@ -126,8 +120,8 @@ describe("Socket", () => { socket.on(SocketEventType.Receive, receiveSpy) socket.open() - const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] - mockWs.onmessage({ data: JSON.stringify(message) }) + const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1 }] + socket._ws.onmessage({ data: JSON.stringify(message) }) // Allow task queue to process await vi.runAllTimers() @@ -140,7 +134,7 @@ describe("Socket", () => { socket.on(SocketEventType.Error, errorSpy) socket.open() - mockWs.onmessage({ data: "invalid json" }) + socket._ws.onmessage({ data: "invalid json" }) expect(errorSpy).toHaveBeenCalledWith("Invalid message received", "wss://test.relay") }) @@ -150,7 +144,7 @@ describe("Socket", () => { socket.on(SocketEventType.Error, errorSpy) socket.open() - mockWs.onmessage({ data: JSON.stringify({ not: "an array" }) }) + socket._ws.onmessage({ data: JSON.stringify({ not: "an array" }) }) expect(errorSpy).toHaveBeenCalledWith("Invalid message received", "wss://test.relay") }) @@ -159,9 +153,12 @@ describe("Socket", () => { describe("cleanup", () => { it("should close socket and clear queues", () => { socket.open() + + const ws = socket._ws + socket.cleanup() - expect(mockWs.close).toHaveBeenCalled() + expect(ws.close).toHaveBeenCalled() expect(socket.listenerCount(SocketEventType.Send)).toBe(0) }) }) @@ -172,7 +169,7 @@ describe("Socket", () => { socket.on(SocketEventType.Status, statusSpy) socket.open() - mockWs.onerror() + socket._ws.onerror() expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Error, "wss://test.relay") }) diff --git a/packages/net2/__tests__/adapter.test.ts b/packages/net2/__tests__/adapter.test.ts index 284439b..712926d 100644 --- a/packages/net2/__tests__/adapter.test.ts +++ b/packages/net2/__tests__/adapter.test.ts @@ -6,39 +6,35 @@ import { Pool } from "../src/pool" import { ClientMessage, RelayMessage } from "../src/message" import EventEmitter from "events" -vi.mock("@welshman/lib", () => ({ - on: (target: any, eventName: string, callback: Function) => { - target.on(eventName, callback) - return () => target.off(eventName, callback) - }, - call: (fn: Function) => fn() -})) +vi.mock('isomorphic-ws', () => { + const WebSocket = vi.fn(function () { + setTimeout(() => this.onopen()) + }) -vi.mock("../src/socket") -vi.mock("@welshman/util", () => ({ - Relay: vi.fn(() => new EventEmitter()), - LOCAL_RELAY_URL: "local://welshman.relay/", - isRelayUrl: vi.fn((url) => url.startsWith("wss://")) -})) + WebSocket.prototype.send = vi.fn() + + WebSocket.prototype.close = vi.fn(function () { + this.onclose() + }) + + return { default: WebSocket } +}) describe("SocketAdapter", () => { let socket: Socket let adapter: SocketAdapter beforeEach(() => { - const mockSocket = new EventEmitter() - Object.assign(mockSocket, { - url: "wss://test.relay", - send: vi.fn(), - removeAllListeners: vi.fn() - }) - socket = mockSocket as unknown as Socket + vi.useFakeTimers() + socket = new Socket('wss://test.relay') adapter = new SocketAdapter(socket) }) afterEach(() => { - adapter.cleanup() vi.clearAllMocks() + vi.useRealTimers() + socket.cleanup() + adapter.cleanup() }) it("should initialize with correct socket", () => { @@ -51,17 +47,18 @@ describe("SocketAdapter", () => { const receiveSpy = vi.fn() adapter.on(AdapterEventType.Receive, receiveSpy) - const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1 }] socket.emit(SocketEventType.Receive, message, "wss://test.relay") expect(receiveSpy).toHaveBeenCalledWith(message, "wss://test.relay") }) it("should send messages to socket", () => { - const message: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const sendSpy = vi.spyOn(socket, 'send') + const message: ClientMessage = ["EVENT", { id: "123", kind: 1 }] adapter.send(message) - expect(socket.send).toHaveBeenCalledWith(message) + expect(sendSpy).toHaveBeenCalledWith(message) }) it("should cleanup properly", () => { @@ -100,14 +97,14 @@ describe("LocalAdapter", () => { const receiveSpy = vi.fn() adapter.on(AdapterEventType.Receive, receiveSpy) - const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1 }] relay.emit("*", ...message) expect(receiveSpy).toHaveBeenCalledWith(message, LOCAL_RELAY_URL) }) it("should send messages to relay", () => { - const message: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + const message: ClientMessage = ["EVENT", { id: "123", kind: 1 }] adapter.send(message) expect(relay.send).toHaveBeenCalledWith("EVENT", message[1]) @@ -147,7 +144,6 @@ describe("getAdapter", () => { }) it("should throw error for invalid relay URL", () => { - vi.mocked(isRelayUrl).mockReturnValue(false) expect(() => getAdapter("invalid-url", {})).toThrow("Invalid relay url invalid-url") }) @@ -158,7 +154,6 @@ describe("getAdapter", () => { it("should throw error for remote relay URL without pool context", () => { const url = "wss://test.relay" - vi.mocked(isRelayUrl).mockReturnValue(true) expect(() => getAdapter(url, {})).toThrow(`Unable to get socket for ${url}`) }) diff --git a/packages/net2/__tests__/auth.test.ts b/packages/net2/__tests__/auth.test.ts index 2600ffa..b96490c 100644 --- a/packages/net2/__tests__/auth.test.ts +++ b/packages/net2/__tests__/auth.test.ts @@ -1,242 +1,203 @@ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest" import { Socket, SocketStatus, SocketEventType } from "../src/socket" import { makeEvent, CLIENT_AUTH } from "@welshman/util" +import { Nip01Signer } from "@welshman/signer" import { AuthState, AuthStatus, AuthStateEventType, AuthManager, makeAuthEvent } from "../src/auth" import EventEmitter from "events" import { RelayMessage } from "../src/message" -// Mock dependencies -vi.mock("@welshman/lib", () => ({ - on: (target: any, eventName: string, callback: Function) => { - target.on(eventName, callback) - return () => target.off(eventName, callback) - }, - call: (fn: Function) => fn(), - sleep: vi.fn() -})) - -vi.mock("@welshman/util", () => ({ - makeEvent: vi.fn((kind, opts) => ({ - kind, - id: "test-event-id", - ...opts - })), - CLIENT_AUTH: 24242 -})) - -describe("AuthState", () => { - let socket: Socket & EventEmitter - let authState: AuthState - - beforeEach(() => { - const mockSocket = new EventEmitter() - Object.assign(mockSocket, { - url: "wss://test.relay", - send: vi.fn(), - removeAllListeners: vi.fn() - }) - socket = mockSocket as unknown as Socket - authState = new AuthState(socket) +vi.mock('isomorphic-ws', () => { + const WebSocket = vi.fn(function () { + setTimeout(() => this.onopen()) }) - afterEach(() => { - authState.cleanup() - vi.clearAllMocks() + WebSocket.prototype.send = vi.fn() + + WebSocket.prototype.close = vi.fn(function () { + this.onclose() }) - it("should initialize with None status", () => { - expect(authState.status).toBe(AuthStatus.None) - }) - - it("should handle AUTH message from relay", () => { - const message: RelayMessage = ["AUTH", "challenge123"] - socket.emit(SocketEventType.Receive, message) - - expect(authState.challenge).toBe("challenge123") - expect(authState.status).toBe(AuthStatus.Requested) - }) - - it("should handle successful OK message", () => { - authState.request = "request123" - const message: RelayMessage = ["OK", "request123", true, "success"] - socket.emit(SocketEventType.Receive, message) - - expect(authState.status).toBe(AuthStatus.Ok) - expect(authState.details).toBe("success") - }) - - it("should handle failed OK message", () => { - authState.request = "request123" - const message: RelayMessage = ["OK", "request123", false, "forbidden"] - socket.emit(SocketEventType.Receive, message) - - expect(authState.status).toBe(AuthStatus.Forbidden) - expect(authState.details).toBe("forbidden") - }) - - it("should ignore OK messages for different requests", () => { - authState.request = "request123" - const message: RelayMessage = ["OK", "different-request", true, "success"] - socket.emit(SocketEventType.Receive, message) - - expect(authState.status).toBe(AuthStatus.None) - }) - - it("should handle client AUTH message", () => { - const message: RelayMessage = ["AUTH", { id: "123", kind: CLIENT_AUTH }] - socket.emit(SocketEventType.Enqueue, message) - - expect(authState.status).toBe(AuthStatus.PendingResponse) - }) - - it("should reset state on socket close", () => { - authState.challenge = "challenge123" - authState.request = "request123" - authState.details = "details" - authState.status = AuthStatus.PendingResponse - - socket.emit(SocketEventType.Status, SocketStatus.Closed) - - expect(authState.challenge).toBeUndefined() - expect(authState.request).toBeUndefined() - expect(authState.details).toBeUndefined() - expect(authState.status).toBe(AuthStatus.None) - }) - - it("should emit status changes", () => { - const statusSpy = vi.fn() - authState.on(AuthStateEventType.Status, statusSpy) - - authState.setStatus(AuthStatus.Requested) - - expect(statusSpy).toHaveBeenCalledWith(AuthStatus.Requested) - }) - - it("should cleanup properly", () => { - const removeListenersSpy = vi.spyOn(authState, "removeAllListeners") - authState.cleanup() - expect(removeListenersSpy).toHaveBeenCalled() - }) + return { default: WebSocket } }) -describe("AuthManager", () => { - let socket: Socket & EventEmitter - let manager: AuthManager - let signFn: jest.Mock +describe('auth', () => { + let socket: Socket + let authManager: AuthManager + let sign = vi.fn(Nip01Signer.ephemeral().sign) beforeEach(() => { - const mockSocket = new EventEmitter() - Object.assign(mockSocket, { - url: "wss://test.relay", - send: vi.fn(), - removeAllListeners: vi.fn(), - attemptToOpen: vi.fn() - }) - socket = mockSocket as unknown as Socket & EventEmitter - signFn = vi.fn() - manager = new AuthManager(socket, { sign: signFn }) + socket = new Socket('wss://test.relay') + authManager = new AuthManager(socket, { sign }) }) afterEach(() => { - manager.cleanup() vi.clearAllMocks() + socket.cleanup() + authManager.cleanup() }) - it("should create AuthState instance", () => { - expect(manager.state).toBeInstanceOf(AuthState) - }) - - it("should respond automatically when eager is true", () => { - const respondSpy = vi.spyOn(AuthManager.prototype, "respond") - const eagerManager = new AuthManager(socket, { sign: signFn, eager: true }) - - socket.emit(SocketEventType.Receive, ["AUTH", "challenge123"]) - - expect(respondSpy).toHaveBeenCalled() - }) - - it("should not respond automatically when eager is false", () => { - const respondSpy = vi.spyOn(AuthManager.prototype, "respond") - socket.emit(SocketEventType.Receive, ["AUTH", "challenge123"]) - - expect(respondSpy).not.toHaveBeenCalled() - }) - - describe("respond", () => { - it("should throw error if no challenge", async () => { - await expect(manager.respond()).rejects.toThrow("Attempted to authenticate with no challenge") + describe("AuthState", () => { + it("should initialize with None status", () => { + expect(authManager.state.status).toBe(AuthStatus.None) }) - it("should throw error if status is not Requested", async () => { - manager.state.challenge = "challenge123" - manager.state.status = AuthStatus.PendingSignature + it("should handle AUTH message from relay", () => { + const message: RelayMessage = ["AUTH", "challenge123"] + socket.emit(SocketEventType.Receive, message) - await expect(manager.respond()).rejects.toThrow("Attempted to authenticate when auth is already auth:status:pending_signature") + expect(authManager.state.challenge).toBe("challenge123") + expect(authManager.state.status).toBe(AuthStatus.Requested) }) - it("should handle successful sign", async () => { - manager.state.challenge = "challenge123" - manager.state.status = AuthStatus.Requested - const signedEvent = { id: "signed-event-id", kind: CLIENT_AUTH } - signFn.mockResolvedValue(signedEvent) + it("should handle successful OK message", () => { + authManager.state.request = "request123" + const message: RelayMessage = ["OK", "request123", true, "success"] + socket.emit(SocketEventType.Receive, message) - await manager.respond() - - expect(manager.state.request).toBe("signed-event-id") - expect(socket.send).toHaveBeenCalledWith(["AUTH", signedEvent]) + expect(authManager.state.status).toBe(AuthStatus.Ok) + expect(authManager.state.details).toBe("success") }) - it("should handle denied signature", async () => { - manager.state.challenge = "challenge123" - manager.state.status = AuthStatus.Requested - signFn.mockResolvedValue(null) + it("should handle failed OK message", () => { + authManager.state.request = "request123" + const message: RelayMessage = ["OK", "request123", false, "forbidden"] + socket.emit(SocketEventType.Receive, message) - await manager.respond() + expect(authManager.state.status).toBe(AuthStatus.Forbidden) + expect(authManager.state.details).toBe("forbidden") + }) - expect(manager.state.status).toBe(AuthStatus.DeniedSignature) - expect(socket.send).not.toHaveBeenCalled() + it("should ignore OK messages for different requests", () => { + authManager.state.request = "request123" + const message: RelayMessage = ["OK", "different-request", true, "success"] + socket.emit(SocketEventType.Receive, message) + + expect(authManager.state.status).toBe(AuthStatus.None) + }) + + it("should handle client AUTH message", () => { + const message: RelayMessage = ["AUTH", { id: "123", kind: CLIENT_AUTH }] + socket.emit(SocketEventType.Enqueue, message) + + expect(authManager.state.status).toBe(AuthStatus.PendingResponse) + }) + + it("should reset state on socket close", () => { + authManager.state.challenge = "challenge123" + authManager.state.request = "request123" + authManager.state.details = "details" + authManager.state.status = AuthStatus.PendingResponse + + socket.emit(SocketEventType.Status, SocketStatus.Closed) + + expect(authManager.state.challenge).toBeUndefined() + expect(authManager.state.request).toBeUndefined() + expect(authManager.state.details).toBeUndefined() + expect(authManager.state.status).toBe(AuthStatus.None) + }) + + it("should emit status changes", () => { + const statusSpy = vi.fn() + authManager.state.on(AuthStateEventType.Status, statusSpy) + + authManager.state.setStatus(AuthStatus.Requested) + + expect(statusSpy).toHaveBeenCalledWith(AuthStatus.Requested) + }) + + it("should cleanup properly", () => { + const removeListenersSpy = vi.spyOn(authManager.state, "removeAllListeners") + authManager.state.cleanup() + expect(removeListenersSpy).toHaveBeenCalled() }) }) - describe("attempt", () => { - it("should attempt to open socket", async () => { - await manager.attempt() - expect(socket.attemptToOpen).toHaveBeenCalled() + describe("AuthManager", () => { + it("should create AuthState instance", () => { + expect(authManager.state).toBeInstanceOf(AuthState) }) - it("should wait for challenge", async () => { - const waitForChallengeSpy = vi.spyOn(manager, "waitForChallenge") - await manager.attempt() - expect(waitForChallengeSpy).toHaveBeenCalled() - }) + it("should respond automatically when eager is true", () => { + const respondSpy = vi.spyOn(AuthManager.prototype, "respond") + const eagerManager = new AuthManager(socket, { sign, eager: true }) + + socket.emit(SocketEventType.Receive, ["AUTH", "challenge123"]) - it("should respond if challenge received", async () => { - const respondSpy = vi.spyOn(manager, "respond") - manager.state.challenge = "challenge123" - manager.state.status = AuthStatus.Requested - await manager.attempt() expect(respondSpy).toHaveBeenCalled() }) - it("should wait for resolution", async () => { - const waitForResolutionSpy = vi.spyOn(manager, "waitForResolution") - await manager.attempt() - expect(waitForResolutionSpy).toHaveBeenCalled() + it("should not respond automatically when eager is false", () => { + const respondSpy = vi.spyOn(AuthManager.prototype, "respond") + socket.emit(SocketEventType.Receive, ["AUTH", "challenge123"]) + + expect(respondSpy).not.toHaveBeenCalled() }) - }) - describe("makeAuthEvent", () => { - it("should create auth event with correct tags", () => { - const url = "wss://test.relay" - const challenge = "challenge123" + describe("respond", () => { + it("should throw error if no challenge", async () => { + await expect(authManager.respond()).rejects.toThrow("Attempted to authenticate with no challenge") + }) - makeAuthEvent(url, challenge) + it("should throw error if status is not Requested", async () => { + authManager.state.challenge = "challenge123" + authManager.state.status = AuthStatus.PendingSignature - expect(makeEvent).toHaveBeenCalledWith(CLIENT_AUTH, { - tags: [ - ["relay", url], - ["challenge", challenge] - ] + await expect(authManager.respond()).rejects.toThrow("Attempted to authenticate when auth is already auth:status:pending_signature") + }) + + it("should handle successful sign", async () => { + const sendSpy = vi.spyOn(socket, 'send') + + authManager.state.challenge = "challenge123" + authManager.state.status = AuthStatus.Requested + const signedEvent = { id: "signed-event-id", kind: CLIENT_AUTH } + sign.mockResolvedValue(signedEvent) + + await authManager.respond() + + expect(authManager.state.request).toBe("signed-event-id") + expect(sendSpy).toHaveBeenCalledWith(["AUTH", signedEvent]) + }) + + it("should handle denied signature", async () => { + const sendSpy = vi.spyOn(socket, 'send') + + authManager.state.challenge = "challenge123" + authManager.state.status = AuthStatus.Requested + sign.mockResolvedValue(null) + + await authManager.respond() + + expect(authManager.state.status).toBe(AuthStatus.DeniedSignature) + expect(sendSpy).not.toHaveBeenCalled() + }) + }) + + describe("attempt", () => { + it("should attempt to open socket", async () => { + const attemptToOpenSpy = vi.spyOn(socket, 'attemptToOpen') + await authManager.attempt() + expect(attemptToOpenSpy).toHaveBeenCalled() + }) + + it("should wait for challenge", async () => { + const waitForChallengeSpy = vi.spyOn(authManager, "waitForChallenge") + await authManager.attempt() + expect(waitForChallengeSpy).toHaveBeenCalled() + }) + + it("should respond if challenge received", async () => { + const respondSpy = vi.spyOn(authManager, "respond") + authManager.state.challenge = "challenge123" + authManager.state.status = AuthStatus.Requested + await authManager.attempt() + expect(respondSpy).toHaveBeenCalled() + }) + + it("should wait for resolution", async () => { + const waitForResolutionSpy = vi.spyOn(authManager, "waitForResolution") + await authManager.attempt() + expect(waitForResolutionSpy).toHaveBeenCalled() }) }) }) diff --git a/packages/net2/__tests__/policy.test.ts b/packages/net2/__tests__/policy.test.ts index b34de48..26dec62 100644 --- a/packages/net2/__tests__/policy.test.ts +++ b/packages/net2/__tests__/policy.test.ts @@ -1,4 +1,3 @@ -import WebSocket from "isomorphic-ws" import { AUTH_JOIN } from "@welshman/util" import { describe, expect, it, vi, beforeEach, afterEach } from "vitest" import { Socket, SocketStatus, SocketEventType } from "../src/socket" @@ -13,50 +12,33 @@ import { } from "../src/policy" import { ClientMessage, RelayMessage } from "../src/message" +// Hoist mock definition to top level +const mockWs = vi.hoisted(() => ({ + close: vi.fn(), + send: vi.fn(), + onopen: vi.fn(), + onclose: null, + onerror: null, + onmessage: null, +})) + +// Mock the WebSocket module +vi.mock('isomorphic-ws', () => ({ + default: mockWs +})) + describe('policy', () => { let socket: Socket - let mockWs: any beforeEach(() => { vi.useFakeTimers() - vi.clearAllMocks() - - mockWs = { - close: vi.fn(), - send: vi.fn(), - onopen: vi.fn(), - onclose: null, - onerror: null, - onmessage: null, - } - - vi.mock('@/store', () => ({default: mockWs})) - socket = new Socket("wss://test.relay") }) afterEach(() => { socket.cleanup() vi.useRealTimers() - }) - - describe("socketPolicySendWhenOpen", () => { - it("should send when open", async () => { - const cleanup = socketPolicySendWhenOpen(socket) - const stopSpy = vi.spyOn(socket._sendQueue, 'stop') - const startSpy = vi.spyOn(socket._sendQueue, 'start') - - socket.emit(SocketEventType.Status, SocketStatus.Opening, socket.url) - - expect(stopSpy).toHaveBeenCalled() - expect(startSpy).not.toHaveBeenCalled() - - socket.emit(SocketEventType.Status, SocketStatus.Open, socket.url) - - expect(startSpy).toHaveBeenCalled() - - cleanup() - }) + vi.clearAllMocks() }) describe("socketPolicyDeferOnAuth", () => { @@ -127,4 +109,155 @@ describe('policy', () => { cleanup() }) }) + + describe("socketPolicyRetryAuthRequired", () => { + it("should retry events once when auth-required", () => { + const cleanup = socketPolicyRetryAuthRequired(socket) + const sendSpy = vi.spyOn(socket, 'send') + + // Send an event + const event: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + socket.emit(SocketEventType.Send, event) + + // Receive auth-required rejection + socket.emit(SocketEventType.Receive, ["OK", "123", false, "auth-required: need to auth first"]) + + // Should retry the event + expect(sendSpy).toHaveBeenCalledWith(event) + + // Receive another auth-required rejection + socket.emit(SocketEventType.Receive, ["OK", "123", false, "auth-required: need to auth first"]) + + // Should not retry again + expect(sendSpy).toHaveBeenCalledTimes(1) + + cleanup() + }) + + it("should retry REQ once when auth-required", () => { + const cleanup = socketPolicyRetryAuthRequired(socket) + const sendSpy = vi.spyOn(socket, 'send') + + // Send a REQ + const req: ClientMessage = ["REQ", "123", { kinds: [1] }] + socket.emit(SocketEventType.Send, req) + + // Receive auth-required rejection via CLOSED + socket.emit(SocketEventType.Receive, ["CLOSED", "123", "auth-required: need to auth first"]) + + // Should retry the request + expect(sendSpy).toHaveBeenCalledWith(req) + + // Receive another auth-required rejection + socket.emit(SocketEventType.Receive, ["CLOSED", "123", "auth-required: need to auth first"]) + + // Should not retry again + expect(sendSpy).toHaveBeenCalledTimes(1) + + cleanup() + }) + + it("should not retry AUTH_JOIN events", () => { + const cleanup = socketPolicyRetryAuthRequired(socket) + const sendSpy = vi.spyOn(socket, 'send') + + // Send an AUTH_JOIN event + const event: ClientMessage = ["EVENT", { id: "123", kind: AUTH_JOIN, content: "", tags: [], pubkey: "", sig: "" }] + socket.emit(SocketEventType.Send, event) + + // Receive auth-required rejection + socket.emit(SocketEventType.Receive, ["OK", "123", false, "auth-required: need to auth first"]) + + // Should not retry AUTH_JOIN events + expect(sendSpy).not.toHaveBeenCalled() + + cleanup() + }) + + it("should clear pending messages on successful response", () => { + const cleanup = socketPolicyRetryAuthRequired(socket) + const sendSpy = vi.spyOn(socket, 'send') + + // Send an event + const event: ClientMessage = ["EVENT", { id: "123", kind: 1, content: "", tags: [], pubkey: "", sig: "" }] + socket.emit(SocketEventType.Send, event) + + // Receive successful response + socket.emit(SocketEventType.Receive, ["OK", "123", true, ""]) + + // Receive auth-required rejection (should not trigger retry since message was cleared) + socket.emit(SocketEventType.Receive, ["OK", "123", false, "auth-required: need to auth first"]) + + // Should not retry + expect(sendSpy).not.toHaveBeenCalled() + + cleanup() + }) + }) + + describe("socketPolicyConnectOnSend", () => { + it("should open socket on send when closed", () => { + const cleanup = socketPolicyConnectOnSend(socket) + const openSpy = vi.spyOn(socket, 'open') + + // Socket starts closed + socket.emit(SocketEventType.Status, SocketStatus.Closed) + + // Send a message + const event: ClientMessage = ["EVENT", { id: "123", kind: 1 }] + socket.emit(SocketEventType.Enqueue, event) + + // Should open the socket + expect(openSpy).toHaveBeenCalled() + + cleanup() + }) + + it("should not open socket if already open", () => { + const cleanup = socketPolicyConnectOnSend(socket) + const openSpy = vi.spyOn(socket, 'open') + + // Socket is open + socket.emit(SocketEventType.Status, SocketStatus.Open) + + // Send a message + const event: ClientMessage = ["EVENT", { id: "123", kind: 1 }] + socket.emit(SocketEventType.Enqueue, event) + + // Should not try to open the socket + expect(openSpy).not.toHaveBeenCalled() + + cleanup() + }) + + it("should not open socket if there was a recent error", () => { + const cleanup = socketPolicyConnectOnSend(socket) + const openSpy = vi.spyOn(socket, 'open') + + // Socket has an error + socket.emit(SocketEventType.Status, SocketStatus.Error) + socket.emit(SocketEventType.Status, SocketStatus.Closed) + + // Send a message + const event: ClientMessage = ["EVENT", { id: "123", kind: 1 }] + socket.emit(SocketEventType.Enqueue, event) + + // Should not try to open the socket due to recent error + expect(openSpy).not.toHaveBeenCalled() + + // Advance time past the error timeout + vi.advanceTimersByTime(31000) + + // Send another message + socket.emit(SocketEventType.Enqueue, event) + + // Now it should try to open + expect(openSpy).toHaveBeenCalled() + + cleanup() + }) + }) + + describe("socketPolicyCloseOnTimeout", () => { + }) }) diff --git a/packages/net2/__tests__/pool.test.ts b/packages/net2/__tests__/pool.test.ts index f76c870..3683363 100644 --- a/packages/net2/__tests__/pool.test.ts +++ b/packages/net2/__tests__/pool.test.ts @@ -3,188 +3,80 @@ import { Socket } from "../src/socket" import { Pool, makeSocket } from "../src/pool" import { normalizeRelayUrl } from "@welshman/util" -// Mock dependencies -vi.mock("@welshman/lib", () => ({ - remove: vi.fn((item, array) => array.filter(x => x !== item)), - on: vi.fn((target, event, callback) => { - if (target.on) { - target.on(event, callback) - } - return () => { - if (target.off) { - target.off(event, callback) - } - } - }), - call: vi.fn(fn => fn()) -})) - -vi.mock("@welshman/util", () => ({ - normalizeRelayUrl: vi.fn(url => url) -})) - -vi.mock("../src/socket", async (importOriginal) => { - const original = await importOriginal() - - return { - ...original, - Socket: vi.fn().mockImplementation((url) => ({ - url, - cleanup: vi.fn(), - _sendQueue: { - start: vi.fn(), - stop: vi.fn() - }, - on: vi.fn(), - off: vi.fn() - })), - } -}) - -describe("makeSocket", () => { - let mockSocket: any - - beforeEach(() => { - mockSocket = { - url: "wss://test.relay", - cleanup: vi.fn(), - _sendQueue: { - start: vi.fn(), - stop: vi.fn() - }, - on: vi.fn(), - off: vi.fn() - } - vi.mocked(Socket).mockReturnValue(mockSocket) +vi.mock('isomorphic-ws', () => { + const WebSocket = vi.fn(function () { + setTimeout(() => this.onopen()) }) - afterEach(() => { - vi.clearAllMocks() + WebSocket.prototype.send = vi.fn() + + WebSocket.prototype.close = vi.fn(function () { + this.onclose() }) - it("should create socket with url", () => { - const socket = makeSocket("wss://test.relay", []) - expect(Socket).toHaveBeenCalledWith("wss://test.relay") - }) - - it("should apply custom policies", () => { - const customPolicy = vi.fn(() => () => {}) - const socket = makeSocket("wss://test.relay", [customPolicy]) - expect(customPolicy).toHaveBeenCalledWith(mockSocket) - }) + return { default: WebSocket } }) describe("Pool", () => { let pool: Pool - let customMakeSocket: jest.Mock beforeEach(() => { - customMakeSocket = vi.fn() - pool = new Pool({ makeSocket: customMakeSocket }) + pool = new Pool() }) afterEach(() => { vi.clearAllMocks() }) - describe("initialization", () => { - it("should initialize with empty data map", () => { - expect(pool._data.size).toBe(0) - }) - - it("should initialize with empty subscriptions", () => { - expect(pool._subs).toEqual([]) - }) - }) - describe("has", () => { it("should return false for non-existent socket", () => { expect(pool.has("wss://test.relay")).toBe(false) }) - it("should return true for existing socket", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) - pool.get("wss://test.relay") + it("should return true for existing socket, normalizing the url", () => { + pool.get("wss://test.relay/") expect(pool.has("wss://test.relay")).toBe(true) }) }) - describe("makeSocket", () => { - it("should use custom makeSocket if provided", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) - - const result = pool.makeSocket("wss://test.relay") - - expect(customMakeSocket).toHaveBeenCalledWith("wss://test.relay") - expect(result).toBe(mockSocket) - }) - - it("should use default makeSocket if none provided", () => { - pool = new Pool({}) - const socket = pool.makeSocket("wss://test.relay") - expect(Socket).toHaveBeenCalledWith("wss://test.relay") - }) - }) - describe("get", () => { - it("should normalize relay URL", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) - pool.get("wss://test.relay") - expect(normalizeRelayUrl).toHaveBeenCalledWith("wss://test.relay") - }) - - it("should create new socket if none exists", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) - + it("should create new socket if none exists, normalizing the relay url", () => { const socket = pool.get("wss://test.relay") - expect(customMakeSocket).toHaveBeenCalledWith("wss://test.relay") - expect(socket).toBe(mockSocket) + expect(socket.url).toEqual("wss://test.relay/") }) it("should return existing socket if it exists", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) - const firstSocket = pool.get("wss://test.relay") const secondSocket = pool.get("wss://test.relay") - expect(customMakeSocket).toHaveBeenCalledTimes(1) expect(firstSocket).toBe(secondSocket) }) + }) + describe("subscribe", () => { it("should notify subscribers of new sockets", () => { const sub1 = vi.fn() const sub2 = vi.fn() - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) pool.subscribe(sub1) pool.subscribe(sub2) pool.get("wss://test.relay") - expect(sub1).toHaveBeenCalledWith(mockSocket) - expect(sub2).toHaveBeenCalledWith(mockSocket) + expect(sub1).toHaveBeenCalledTimes(1) + expect(sub2).toHaveBeenCalledTimes(1) }) it("should not notify subscribers for existing sockets", () => { - const mockSocket = { url: "wss://test.relay" } - customMakeSocket.mockReturnValue(mockSocket) pool.get("wss://test.relay") - + const sub = vi.fn() pool.subscribe(sub) pool.get("wss://test.relay") expect(sub).not.toHaveBeenCalled() }) - }) - describe("subscribe", () => { it("should add subscription", () => { const sub = vi.fn() pool.subscribe(sub) @@ -194,9 +86,9 @@ describe("Pool", () => { it("should return unsubscribe function", () => { const sub = vi.fn() const unsubscribe = pool.subscribe(sub) - + unsubscribe() - + expect(pool._subs).not.toContain(sub) }) }) @@ -204,13 +96,12 @@ describe("Pool", () => { describe("remove", () => { it("should remove and cleanup existing socket", () => { const mockSocket = { url: "wss://test.relay", cleanup: vi.fn() } - customMakeSocket.mockReturnValue(mockSocket) - - pool.get("wss://test.relay") - pool.remove("wss://test.relay") + + pool._data.set(mockSocket.url, mockSocket) + pool.remove(mockSocket.url) expect(mockSocket.cleanup).toHaveBeenCalled() - expect(pool._data.has("wss://test.relay")).toBe(false) + expect(pool._data.has(mockSocket.url)).toBe(false) }) it("should do nothing for non-existent socket", () => { @@ -223,10 +114,11 @@ describe("Pool", () => { it("should remove all sockets", () => { const urls = ["wss://test1.relay", "wss://test2.relay"] const mockSockets = urls.map(url => ({ url, cleanup: vi.fn() })) - let socketIndex = 0 - customMakeSocket.mockImplementation(() => mockSockets[socketIndex++]) - urls.forEach(url => pool.get(url)) + for (const mockSocket of mockSockets) { + pool._data.set(mockSocket.url, mockSocket) + } + pool.clear() expect(pool._data.size).toBe(0) @@ -234,9 +126,5 @@ describe("Pool", () => { expect(socket.cleanup).toHaveBeenCalled() }) }) - - it("should do nothing on empty pool", () => { - expect(() => pool.clear()).not.toThrow() - }) }) }) diff --git a/packages/net2/src/policy.ts b/packages/net2/src/policy.ts index 4785151..a2e9ffd 100644 --- a/packages/net2/src/policy.ts +++ b/packages/net2/src/policy.ts @@ -14,21 +14,11 @@ import { import {Socket, SocketStatus, SocketEventType} from "./socket.js" import {AuthState, AuthStatus, AuthStateEventType} from "./auth.js" -// Pause sending messages when the socket isn't open -export const socketPolicySendWhenOpen = (socket: Socket) => { - const unsubscribers = [ - on(socket, SocketEventType.Status, (newStatus: SocketStatus) => { - if (newStatus === SocketStatus.Open) { - socket._sendQueue.start() - } else { - socket._sendQueue.stop() - } - }), - ] - - return () => unsubscribers.forEach(call) -} - +/** + * Defers sending messages when a challenge has been presented and not answered yet + * @param socket - a Socket object + * @return a cleanup function + */ export const socketPolicyDeferOnAuth = (socket: Socket) => { const buffer: ClientMessage[] = [] const authState = new AuthState(socket) @@ -78,6 +68,11 @@ export const socketPolicyDeferOnAuth = (socket: Socket) => { } } +/** + * Re-enqueues event/req messages once if rejected due to auth-required + * @param socket - a Socket object + * @return a cleanup function + */ export const socketPolicyRetryAuthRequired = (socket: Socket) => { const retried = new Set() const pending = new Map() @@ -132,6 +127,11 @@ export const socketPolicyRetryAuthRequired = (socket: Socket) => { return () => unsubscribers.forEach(call) } +/** + * Auto-connects a closed socket when a message is sent unless there was a recent error + * @param socket - a Socket object + * @return a cleanup function + */ export const socketPolicyConnectOnSend = (socket: Socket) => { let lastError = 0 let currentStatus = SocketStatus.Closed @@ -146,9 +146,9 @@ export const socketPolicyConnectOnSend = (socket: Socket) => { // Keep track of the current status currentStatus = newStatus }), - on(socket, SocketEventType.Send, (message: ClientMessage) => { + on(socket, SocketEventType.Enqueue, (message: ClientMessage) => { // When a new message is sent, make sure the socket is open (unless there was a recent error) - if (currentStatus === SocketStatus.Closed && now() - lastError < ago(30)) { + if (currentStatus === SocketStatus.Closed && lastError < ago(30)) { socket.open() } }), @@ -157,8 +157,13 @@ export const socketPolicyConnectOnSend = (socket: Socket) => { return () => unsubscribers.forEach(call) } +/** + * Auto-closes a socket after 30 seconds of inactivity + * @param socket - a Socket object + * @return a cleanup function + */ export const socketPolicyCloseOnTimeout = (socket: Socket) => { - let lastActivity = 0 + let lastActivity = now() const unsubscribers = [ on(socket, SocketEventType.Send, (message: ClientMessage) => { @@ -170,7 +175,7 @@ export const socketPolicyCloseOnTimeout = (socket: Socket) => { ] const interval = setInterval(() => { - if (lastActivity < ago(30)) { + if (socket.status === SocketStatus.Open && lastActivity < ago(30)) { socket.close() } }, 3000) @@ -181,6 +186,11 @@ export const socketPolicyCloseOnTimeout = (socket: Socket) => { } } +/** + * Automatically re-opens a socket if there are active requests or publishes + * @param socket - a Socket object + * @return a cleanup function + */ export const socketPolicyReopenActive = (socket: Socket) => { const pending = new Map() @@ -226,7 +236,6 @@ export const socketPolicyReopenActive = (socket: Socket) => { } export const defaultSocketPolicies = [ - socketPolicySendWhenOpen, socketPolicyDeferOnAuth, socketPolicyRetryAuthRequired, socketPolicyConnectOnSend, diff --git a/packages/net2/src/pool.ts b/packages/net2/src/pool.ts index 25504c3..190b2de 100644 --- a/packages/net2/src/pool.ts +++ b/packages/net2/src/pool.ts @@ -23,10 +23,10 @@ export class Pool { _data = new Map() _subs: PoolSubscription[] = [] - constructor(readonly options: PoolOptions) {} + constructor(readonly options: PoolOptions = {}) {} has(url: string) { - return this._data.has(url) + return this._data.has(normalizeRelayUrl(url)) } makeSocket(url: string) { diff --git a/packages/net2/src/socket.ts b/packages/net2/src/socket.ts index ad463af..30545a8 100644 --- a/packages/net2/src/socket.ts +++ b/packages/net2/src/socket.ts @@ -62,15 +62,20 @@ export class Socket extends (EventEmitter as new () => TypedEmitter this.emit(SocketEventType.Status, SocketStatus.Open, this.url) + this._ws.onopen = () => { + this.emit(SocketEventType.Status, SocketStatus.Open, this.url) + this._sendQueue.start() + } this._ws.onerror = () => { this.emit(SocketEventType.Status, SocketStatus.Error, this.url) + this._sendQueue.stop() this._ws = undefined } this._ws.onclose = () => { this.emit(SocketEventType.Status, SocketStatus.Closed, this.url) + this._sendQueue.stop() this._ws = undefined }